From d3c0b75ff92fc7f47ce91bbf3d3f9b5b3a3a5063 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= <fpeters@entrouvert.com>
Date: Sun, 19 Jun 2022 17:54:49 +0200
Subject: [PATCH] workflows: store attachment references as templates (#66398)

---
 tests/admin_pages/test_workflow.py | 46 +++++++++++++++++++++---------
 wcs/workflows.py                   | 21 +++++++++++---
 2 files changed, 49 insertions(+), 18 deletions(-)

diff --git a/tests/admin_pages/test_workflow.py b/tests/admin_pages/test_workflow.py
index ddf678218..d792fa1a5 100644
--- a/tests/admin_pages/test_workflow.py
+++ b/tests/admin_pages/test_workflow.py
@@ -1061,12 +1061,12 @@ def test_workflows_edit_email_action(pub):
 
     # attachments without backoffice fields: python expressions
     resp = app.get(item_url)
-    assert "Attachments (templates or Python expressions)" in resp.text
+    assert "Attachments (templates)" in resp.text
     resp.form['attachments$element0'] = 'form_var_upload_raw'
     resp = resp.form.submit('submit')
     assert resp.location
     resp = app.get(item_url)
-    assert "Attachments (templates or Python expressions)" in resp.text
+    assert "Attachments (templates)" in resp.text
     assert resp.form['attachments$element0'].value == 'form_var_upload_raw'
     sendmail = Workflow.get(workflow.id).get_status(st1.id).items[0]
     assert sendmail.attachments == ['form_var_upload_raw']
@@ -1082,23 +1082,23 @@ def test_workflows_edit_email_action(pub):
     workflow.store()
     resp = app.get(item_url)
     assert "Attachments" in resp.text
-    assert "Attachments (templates or Python expressions)" not in resp.text
-    assert resp.form['attachments$element0$choice'].value == 'form_var_upload_raw'
+    assert "Attachments (templates)" not in resp.text
+    assert resp.form['attachments$element0$choice'].value == '{{form_var_upload_raw}}'
     assert len(resp.form['attachments$element0$choice'].options) == 5
     resp = resp.form.submit('attachments$add_element')  # add one
-    resp.form['attachments$element1$choice'] = 'form_var_upload2_raw'
+    resp.form['attachments$element1$choice'] = '{{form_var_upload2_raw}}'
     resp = resp.form.submit('submit')
     assert resp.location
     sendmail = Workflow.get(workflow.id).get_status(st1.id).items[0]
-    assert sendmail.attachments == ['form_var_upload_raw', 'form_var_upload2_raw']
+    assert sendmail.attachments == ['{{form_var_upload_raw}}', '{{form_var_upload2_raw}}']
 
     resp = app.get(item_url)
     resp = resp.form.submit('attachments$add_element')  # add one
-    resp.form['attachments$element2$choice'] = 'form_fbo3_3x'
+    resp.form['attachments$element2$choice'] = '{{form_fbo3_3x}}'
     resp = resp.form.submit('submit')
     assert resp.location
     sendmail = Workflow.get(workflow.id).get_status(st1.id).items[0]
-    assert sendmail.attachments == ['form_var_upload_raw', 'form_var_upload2_raw', 'form_fbo3_3x']
+    assert sendmail.attachments == ['{{form_var_upload_raw}}', '{{form_var_upload2_raw}}', '{{form_fbo3_3x}}']
 
     resp = app.get(item_url)
     resp = resp.form.submit('attachments$add_element')  # add one
@@ -1108,9 +1108,26 @@ def test_workflows_edit_email_action(pub):
     assert resp.location
     sendmail = Workflow.get(workflow.id).get_status(st1.id).items[0]
     assert sendmail.attachments == [
+        '{{form_var_upload_raw}}',
+        '{{form_var_upload2_raw}}',
+        '{{form_fbo3_3x}}',
+        '{"content":"foo", "filename":"bar.txt"}',
+    ]
+
+    # check old attachments python expressions are converted to templates
+    workflow.refresh_from_storage()
+    workflow.get_status(st1.id).items[0].attachments = [
         'form_var_upload_raw',
         'form_var_upload2_raw',
-        'form_fbo3_3x',
+        '{"content":"foo", "filename":"bar.txt"}',
+    ]
+    workflow.store()
+    resp = app.get(item_url)
+    resp = resp.form.submit('submit')
+    sendmail = Workflow.get(workflow.id).get_status(st1.id).items[0]
+    assert sendmail.attachments == [
+        '{{form_var_upload_raw}}',
+        '{{form_var_upload2_raw}}',
         '{"content":"foo", "filename":"bar.txt"}',
     ]
 
@@ -1125,22 +1142,23 @@ def test_workflows_edit_email_action(pub):
     assert resp.location
     sendmail = Workflow.get(workflow.id).get_status(st1.id).items[0]
     assert sendmail.attachments == [
-        'form_var_upload_raw',
-        'form_var_upload2_raw',
+        '{{form_var_upload_raw}}',
+        '{{form_var_upload2_raw}}',
         '{"content":"foo", "filename":"bar.txt"}',
     ]
+
     # remove all backoffice fields
     workflow = Workflow.get(workflow.id)
     workflow.backoffice_fields_formdef.fields = []
     workflow.store()
     resp = app.get(item_url)
-    assert "Attachments (templates or Python expressions)" in resp.text
+    assert "Attachments (templates)" in resp.text
     resp = resp.form.submit('submit')
     assert resp.location
     sendmail = Workflow.get(workflow.id).get_status(st1.id).items[0]
     assert sendmail.attachments == [
-        'form_var_upload_raw',
-        'form_var_upload2_raw',
+        '{{form_var_upload_raw}}',
+        '{{form_var_upload2_raw}}',
         '{"content":"foo", "filename":"bar.txt"}',
     ]
 
diff --git a/wcs/workflows.py b/wcs/workflows.py
index 049d46649..1c4011c9e 100644
--- a/wcs/workflows.py
+++ b/wcs/workflows.py
@@ -2154,6 +2154,19 @@ class WorkflowStatusItem(XmlSerialisable):
             if any(x for x in attribute_value if isinstance(x, int)):
                 setattr(self, roles_attribute, [str(x) for x in attribute_value])
                 changed = True
+        if getattr(self, 'attachments', None):
+            if any(x for x in self.attachments if not x.startswith('{{')):
+                # convert old attachment python expression to templates
+                for field in self.parent.parent.get_backoffice_fields():
+                    if field.key != 'file':
+                        continue
+                    if field.varname:
+                        codename = 'form_var_%s_raw' % field.varname
+                    else:
+                        codename = 'form_f%s' % field.id.replace('-', '_')  # = form_fbo<...>
+                    if codename in self.attachments:
+                        changed = True
+                        self.attachments = ['{{%s}}' % x if x == codename else x for x in self.attachments]
         return changed
 
     def render_as_line(self):
@@ -2250,7 +2263,7 @@ class WorkflowStatusItem(XmlSerialisable):
                 form.add(
                     WidgetList,
                     '%sattachments' % prefix,
-                    title=_('Attachments (templates or Python expressions)'),
+                    title=_('Attachments (templates)'),
                     element_type=StringWidget,
                     value=attachments,
                     add_element_label=_('Add attachment'),
@@ -2568,16 +2581,16 @@ class WorkflowStatusItem(XmlSerialisable):
             if field.key != 'file':
                 continue
             if field.varname:
-                codename = 'form_var_%s_raw' % field.varname
+                codename = '{{form_var_%s_raw}}' % field.varname
             else:
-                codename = 'form_f%s' % field.id.replace('-', '_')  # = form_fbo<...>
+                codename = '{{form_f%s}}' % field.id.replace('-', '_')  # = form_fbo<...>
                 varnameless.append(codename)
             attachments_options.append((codename, field.label, codename))
         # filter: do not consider removed fields without varname
         attachments = [
             attachment
             for attachment in self.attachments or []
-            if ((not attachment.startswith('form_fbo')) or (attachment in varnameless))
+            if ((not attachment.startswith('{{form_fbo')) or (attachment in varnameless))
         ]
         return attachments_options, attachments
 
-- 
2.36.1

