From dbc607eeeb7c0069a375815212444db3f16b0d40 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= <fpeters@entrouvert.com>
Date: Tue, 23 Nov 2021 13:30:32 +0100
Subject: [PATCH 2/2] api: add a transient formdata to evaluated submitted
 fields (#58877)

---
 tests/api/test_formdef.py | 22 +++++++++++++++++++-
 wcs/api.py                | 42 ++++++++++++++++++++++-----------------
 2 files changed, 45 insertions(+), 19 deletions(-)

diff --git a/tests/api/test_formdef.py b/tests/api/test_formdef.py
index b6e60678f..140225fb8 100644
--- a/tests/api/test_formdef.py
+++ b/tests/api/test_formdef.py
@@ -922,6 +922,15 @@ def test_formdef_submit_structured(pub, local_user):
                 'value': '[dict(id=i, text=\'label %s\' % i, foo=i) for i in range(10)]',
             },
         ),
+        fields.ItemField(
+            id='2',
+            label='foobar2',
+            varname='foobar2',
+            data_source={
+                'type': 'json',
+                'value': 'http://datasource.com/{{form_var_foobar_foo}}',
+            },
+        ),
     ]
     formdef.store()
     data_class = formdef.data_class()
@@ -946,10 +955,14 @@ def test_formdef_submit_structured(pub, local_user):
             {
                 'data': {
                     '0': '0',
-                    "1": '3',
+                    '1': '3',
+                    '2': '2',
                 }
             },
         )
+        assert len(urlopen.mock_calls) == 2
+        assert urlopen.call_args_list[0][0] == ('http://datasource.com',)
+        assert urlopen.call_args_list[1][0] == ('http://datasource.com/bar',)
 
     formdata = data_class.get(resp.json['data']['id'])
     assert formdata.status == 'wf-new'
@@ -967,5 +980,12 @@ def test_formdef_submit_structured(pub, local_user):
         'text': 'label 3',
         'foo': 3,
     }
+    assert formdata.data['2'] == '2'
+    assert formdata.data['2_display'] == 'deux'
+    assert formdata.data['2_structured'] == {
+        'id': 2,
+        'text': 'deux',
+        'foo': 'bar2',
+    }
 
     data_class.wipe()
diff --git a/wcs/api.py b/wcs/api.py
index 5ca9c76ff..9eae1a3b7 100644
--- a/wcs/api.py
+++ b/wcs/api.py
@@ -74,24 +74,30 @@ def posted_json_data_to_formdata_data(formdef, data):
         if field.store_structured_value and structured in data:
             data['%s_structured' % field.id] = data.pop(structured)
 
-    # complete/adapt field values
-    for field in formdef.get_all_fields():
-        structured = '%s_structured' % field.id
-        display = '%s_display' % field.id
-        if data.get(field.id) is None:
-            continue
-        if hasattr(field, 'from_json_value'):
-            data[field.id] = field.from_json_value(data[field.id])
-        # only fill display/structured if both are absent
-        if display not in data and structured not in data:
-            if field.store_display_value:
-                display_value = field.store_display_value(data, field.id)
-                if display_value is not None:
-                    data[display] = display_value
-            if field.store_structured_value:
-                structured_value = field.store_structured_value(data, field.id)
-                if structured_value is not None:
-                    data[structured] = structured_value
+    # create a temporary formdata so datasources using previous fields in
+    # parameters can find their values.
+    transient_formdata = formdef.data_class()()
+    transient_formdata.data = data
+
+    with get_publisher().substitutions.temporary_feed(transient_formdata, force_mode='lazy'):
+        # complete/adapt field values
+        for field in formdef.get_all_fields():
+            structured = '%s_structured' % field.id
+            display = '%s_display' % field.id
+            if data.get(field.id) is None:
+                continue
+            if hasattr(field, 'from_json_value'):
+                data[field.id] = field.from_json_value(data[field.id])
+            # only fill display/structured if both are absent
+            if display not in data and structured not in data:
+                if field.store_display_value:
+                    display_value = field.store_display_value(data, field.id)
+                    if display_value is not None:
+                        data[display] = display_value
+                if field.store_structured_value:
+                    structured_value = field.store_structured_value(data, field.id)
+                    if structured_value is not None:
+                        data[structured] = structured_value
     return data
 
 
-- 
2.34.0

