From 71acff1441af6acca213bafb7954e7ed68dc7e6c Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE <nroche@entrouvert.com>
Date: Wed, 24 Apr 2019 12:18:54 +0200
Subject: [PATCH] unfeed: clean cached values of substitution variables using a
 condition before entering into workflow (#32558)

---
 tests/test_form_pages.py | 68 ++++++++++++++++++++++++++++++++++++++++
 wcs/forms/root.py        |  2 ++
 2 files changed, 70 insertions(+)

diff --git a/tests/test_form_pages.py b/tests/test_form_pages.py
index be18ae49..a760e4b4 100644
--- a/tests/test_form_pages.py
+++ b/tests/test_form_pages.py
@@ -6158,3 +6158,71 @@ def test_field_live_condition_unknown_page_id(pub):
     params = resp.form.submit_fields()
     params = [(key, value if key != 'page_id' else 'eiuiu') for key, value in params]
     app.post('/foo/live', params=params)
+
+def test_unfeed_structured_list_when_condition_changes(pub):
+    """
+    simulate selection of a structured list via condition on from,
+    followed by a firstof evaluation on workflow in order to get
+    a structured value from the selected list.
+    """
+    Workflow.wipe()
+    workflow = Workflow(name='test')
+    workflow.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(workflow)
+    workflow.backoffice_fields_formdef.fields = [
+        fields.StringField(
+            id='bo1', label='first text', type='string', varname='firstof_text'),
+        fields.StringField(
+            id='bo2', label='first more', type='string', varname='firstof_more')
+    ]
+
+    st1 = workflow.add_status('Status1', 'st1')
+    setbo = SetBackofficeFieldsWorkflowStatusItem()
+    setbo.parent = st1
+    setbo.fields = [
+        {'field_id': 'bo1',
+         'value': '{% firstof form_var_listA form_var_listB %}'},
+        {'field_id': 'bo2',
+         'value': '{% firstof form_var_listA_more form_var_listB_more %}'}
+         ]
+    st1.items.append(setbo)
+    workflow.store()
+
+    items_A = [{'id': '1', 'text': 'A1', 'more':'moreA1'}]
+    items_B = [{'id': '1', 'text': 'B1', 'more':'moreB1'},
+               {'id': '2', 'text': 'B2', 'more':'moreB2'}]
+    formdef = create_formdef()
+    formdef.fields = [
+        fields.ItemField(id='1', varname='choice', items=['A', 'B'],
+                         type='item', label='list to choice'),
+        fields.ItemField(id='2', varname='listA', type='item', label='list A',
+                         data_source={'type': 'formula', 'value': str(items_A)},
+                         condition={'type': 'python',
+                                    'value': 'form_var_choice_raw == "A"'}),
+        fields.ItemField(id='3', varname='listB', type='item', label='list B',
+                         data_source={'type': 'formula', 'value': str(items_B)},
+                         condition={'type': 'python',
+                                    'value': 'form_var_choice_raw == "B"'})
+        ]
+    formdef.confirmation = False
+    formdef.workflow_id = workflow.id
+    formdef.store()
+    formdef.data_class().wipe()
+
+    create_user_and_admin(pub)
+    resp = get_app(pub).get('/test/')
+
+    resp.form['f1'].value = 'B'
+    resp.form['f2'].value = '1'
+    resp.form['f3'].value = '2'
+
+    resp = resp.form.submit('submit').follow()
+    assert 'The form has been recorded' in resp.body
+
+    assert formdef.data_class().count() == 1
+    formdata = formdef.data_class().select()[0]
+    assert formdata.data['1'] == 'B'
+    assert formdata.data.get('2') is None
+    assert formdata.data['3'] == '2'
+
+    assert formdata.data['bo1'] == 'B2'
+    assert formdata.data['bo2'] == 'moreB2'
diff --git a/wcs/forms/root.py b/wcs/forms/root.py
index 313a94d7..7f92ab53 100644
--- a/wcs/forms/root.py
+++ b/wcs/forms/root.py
@@ -1148,6 +1148,8 @@ class FormPage(Directory, FormTemplateMixin):
         get_logger().info('form %s - done (id: %s)' % (self.formdef.name, filled.id))
         url = None
         if existing_formdata is None:
+            get_publisher().substitutions.unfeed(lambda x: x.__class__.__name__ == 'ConditionVars')
+            get_publisher().substitutions.unfeed(lambda x: isinstance(x, FormData))
             url = filled.perform_workflow()
 
         if not filled.user_id:
-- 
2.20.1

