From 148a9f7cb05fb609eab5ff17dce1bcde10b74c55 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= <fpeters@entrouvert.com>
Date: Tue, 29 Oct 2019 13:23:34 +0100
Subject: [PATCH] workflows: also mark status on trigger/timeout jumps (#37169)

---
 tests/test_form_pages.py                     |  4 ++-
 tests/test_workflows.py                      | 34 ++++++++++++++++++++
 wcs/ctl/management/commands/trigger_jumps.py | 16 +++++----
 wcs/wf/jump.py                               |  2 ++
 4 files changed, 48 insertions(+), 8 deletions(-)

diff --git a/tests/test_form_pages.py b/tests/test_form_pages.py
index 2826250f9..6c0c7e7fc 100644
--- a/tests/test_form_pages.py
+++ b/tests/test_form_pages.py
@@ -4548,6 +4548,7 @@ def test_form_workflow_trigger(pub):
     jump2 = JumpWorkflowStatusItem()
     jump2.trigger = 'YYY'
     jump2.status = 'st3'
+    jump2.set_marker_on_status = True
     st1.items.append(jump2)
     jump2.parent = st1
 
@@ -4591,6 +4592,7 @@ def test_form_workflow_trigger(pub):
     resp = app.post(formdata.get_url() + 'jump/trigger/YYY', status=302)
     formdata = formdef.data_class().get(formdata.id)
     assert formdata.status == 'wf-st3'
+    assert formdata.workflow_data.get('_markers_stack') == [{'status_id': 'st1'}]
 
     formdata.status = 'wf-st1'
     formdata.store()
@@ -4598,7 +4600,7 @@ def test_form_workflow_trigger(pub):
             params=json.dumps({'data': {'foo': 'bar'}}),
             content_type='application/json')
     formdata = formdef.data_class().get(formdata.id)
-    assert formdata.workflow_data == {'data': {'foo': 'bar'}}
+    assert formdata.workflow_data.get('data') == {'foo': 'bar'}
 
 def test_form_worklow_multiple_identical_status(pub):
     user = create_user(pub)
diff --git a/tests/test_workflows.py b/tests/test_workflows.py
index de496f66c..3cb6873b6 100644
--- a/tests/test_workflows.py
+++ b/tests/test_workflows.py
@@ -2152,6 +2152,40 @@ def test_timeout_then_remove(two_pubs):
 
     assert not str(formdata_id) in [str(x) for x in formdef.data_class().keys()]
 
+def test_timeout_with_mark(two_pubs):
+    workflow = Workflow(name='timeout')
+    st1 = workflow.add_status('Status1', 'st1')
+    st2 = workflow.add_status('Status2', 'st2')
+
+    jump = JumpWorkflowStatusItem()
+    jump.id = '_jump'
+    jump.by = ['_submitter', '_receiver']
+    jump.timeout = 0.1
+    jump.status = 'st2'
+    jump.set_marker_on_status = True
+    st1.items.append(jump)
+    jump.parent = st1
+
+    workflow.store()
+
+    formdef = FormDef()
+    formdef.name = 'baz'
+    formdef.fields = []
+    formdef.workflow_id = workflow.id
+    assert formdef.get_workflow().id == workflow.id
+    formdef.store()
+
+    formdata = formdef.data_class()()
+    formdata.just_created()
+    formdata.store()
+    formdata_id = formdata.id
+
+    time.sleep(0.3)
+    _apply_timeouts(two_pubs)
+
+    formdata = formdef.data_class().get(formdata_id)
+    assert formdata.workflow_data.get('_markers_stack') == [{'status_id': 'st1'}]
+
 def test_sms(pub, sms_mocking):
     pub.cfg['sms'] = {'mode': 'xxx'}
     formdef = FormDef()
diff --git a/wcs/ctl/management/commands/trigger_jumps.py b/wcs/ctl/management/commands/trigger_jumps.py
index f77bb6775..735bd1c0c 100644
--- a/wcs/ctl/management/commands/trigger_jumps.py
+++ b/wcs/ctl/management/commands/trigger_jumps.py
@@ -89,7 +89,7 @@ def get_status_ids_accepting_trigger(workflow, trigger):
         for item in status.items:
             if isinstance(item, JumpWorkflowStatusItem) and \
                 item.trigger == trigger:
-                yield 'wf-%s' % status.id, item.status
+                yield 'wf-%s' % status.id, item.status, item
                 break
 
 def get_formdata_accepting_trigger(formdef, trigger, status_ids=None):
@@ -99,10 +99,10 @@ def get_formdata_accepting_trigger(formdef, trigger, status_ids=None):
     formdata_ids = []
 
     data_class = formdef.data_class()
-    for status_id, jump_to in status_ids:
+    for status_id, jump_to, action_item in status_ids:
         formdata_ids = data_class.get_ids_with_indexed_value('status', status_id)
         for formdata_id in formdata_ids:
-            yield data_class.get(id=formdata_id), jump_to
+            yield data_class.get(id=formdata_id), jump_to, action_item
 
 def match_row(substitution_variables, row):
     select = row['select']
@@ -111,21 +111,23 @@ def match_row(substitution_variables, row):
             return False
     return True
 
-def jump_and_perform(formdata, jump_to, workflow_data=None):
+def jump_and_perform(formdata, jump_to, workflow_data=None, action=None):
     get_publisher().substitutions.reset()
     get_publisher().substitutions.feed(get_publisher())
     get_publisher().substitutions.feed(formdata.formdef)
     get_publisher().substitutions.feed(formdata)
     print 'formdata %s jumps to status %s' % (formdata, jump_to)
+    if action:
+        action.handle_markers_stack(formdata)
     wcs_jump_and_perform(formdata, jump_to, workflow_data=workflow_data)
 
 def select_and_jump_formdata(formdef, trigger, rows, status_ids=None):
-    for formdata, jump_to in get_formdata_accepting_trigger(formdef, trigger, status_ids):
+    for formdata, jump_to, action_item in get_formdata_accepting_trigger(formdef, trigger, status_ids):
         if rows == '__all__':
-            jump_and_perform(formdata, jump_to)
+            jump_and_perform(formdata, jump_to, action=action_item)
         else:
             substitution_variables = formdata.get_substitution_variables()
             for row in rows:
                 if match_row(substitution_variables, row):
-                    jump_and_perform(formdata, jump_to, row.get('data'))
+                    jump_and_perform(formdata, jump_to, row.get('data'), action=action_item)
                     break # next formdata
diff --git a/wcs/wf/jump.py b/wcs/wf/jump.py
index e7b07ed66..eaf6fa396 100644
--- a/wcs/wf/jump.py
+++ b/wcs/wf/jump.py
@@ -83,6 +83,7 @@ class TriggerDirectory(Directory):
                     workflow_data = None
                     if hasattr(get_request(), 'json'):
                         workflow_data = get_request().json
+                    item.handle_markers_stack(self.formdata)
                     url = jump_and_perform(self.formdata, item.status,
                             workflow_data=workflow_data)
                 else:
@@ -293,6 +294,7 @@ def _apply_timeouts(publisher):
                     get_publisher().substitutions.feed(formdef)
                     get_publisher().substitutions.feed(formdata)
                     if x.must_jump(formdata):
+                        x.handle_markers_stack(formdata)
                         jump_and_perform(formdata, x.status)
                         break
 
-- 
2.24.0.rc1

