From b01fc14dd8bfbd6c542ef6ebcf059c4e5a1366d8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laur=C3=A9line=20Gu=C3=A9rin?= <zebuline@entrouvert.com>
Date: Tue, 15 Nov 2022 16:45:31 +0100
Subject: [PATCH] api: add include-workflow-data param (#71330)

---
 tests/api/test_carddata.py   | 10 ++++++++++
 tests/api/test_formdata.py   | 15 +++++++++++++--
 wcs/backoffice/management.py | 14 +++++++++++++-
 wcs/formdata.py              | 10 +++++++---
 4 files changed, 43 insertions(+), 6 deletions(-)

diff --git a/tests/api/test_carddata.py b/tests/api/test_carddata.py
index c0d0ac9b6..7b93055be 100644
--- a/tests/api/test_carddata.py
+++ b/tests/api/test_carddata.py
@@ -7,6 +7,7 @@ from wcs.admin.settings import UserFieldsFormDef
 from wcs.api_access import ApiAccess
 from wcs.carddef import CardDef
 from wcs.qommon.http_request import HTTPRequest
+from wcs.qommon.upload_storage import PicklableUpload
 
 from ..utilities import clean_temporary_pub, create_temporary_pub, get_app
 from .utils import sign_uri
@@ -120,6 +121,11 @@ def test_carddata_include_params(pub, local_user, auth):
     carddata.data = {'1': 'FOO BAR'}
     carddata.user_id = local_user.id
     carddata.just_created()
+    upload = PicklableUpload('test.txt', 'text/plain', 'ascii')
+    upload.receive([b'test'])
+    upload2 = PicklableUpload('test.txt', 'text/plain', 'ascii')
+    upload2.receive([b'test'])
+    carddata.workflow_data = {'blah': upload, 'blah2': upload2, 'xxx': 23}
     carddata.store()
 
     ApiAccess.wipe()
@@ -163,6 +169,10 @@ def test_carddata_include_params(pub, local_user, auth):
     assert 'submission' in resp.json['data'][0]
     resp = get_url('/api/cards/test/list?include-workflow=on')
     assert 'workflow' in resp.json['data'][0]
+    assert 'data' not in resp.json['data'][0]['workflow']
+    resp = get_url('/api/cards/test/list?include-workflow-data=on')
+    assert 'workflow' in resp.json['data'][0]
+    assert 'data' in resp.json['data'][0]['workflow']
 
 
 def test_carddata_user_fields(pub, local_user):
diff --git a/tests/api/test_formdata.py b/tests/api/test_formdata.py
index 79d9fd7c4..7e39b96ff 100644
--- a/tests/api/test_formdata.py
+++ b/tests/api/test_formdata.py
@@ -283,6 +283,7 @@ def test_formdata_user_fields(pub, local_user):
         '?include-roles=on',
         '?include-submission=on',
         '?include-workflow=on',
+        '?include-workflow-data=on',
     ]:
         resp = get_app(pub).get(sign_uri('/api/forms/test/list%s' % params, user=local_user))
         assert 'user' not in resp.json[0]
@@ -336,6 +337,7 @@ def test_formdata_submission_fields(pub, local_user):
         '?include-evolution=on',
         '?include-roles=on',
         '?include-workflow=on',
+        '?include-workflow-data=on',
     ]:
         resp = get_app(pub).get(sign_uri('/api/forms/test/list%s' % params, user=local_user))
         assert 'submission' not in resp.json[0]
@@ -569,12 +571,18 @@ def test_formdata_with_workflow_data(pub, local_user):
         '?include-evolution=on',
         '?include-roles=on',
         '?include-submission=on',
+        '?include-workflow=on',
     ]:
         resp = get_app(pub).get(sign_uri('/api/forms/test/list%s' % params, user=local_user))
-        assert 'workflow' not in resp.json[0]
-    for params in ['?full=on', '?include-workflow=on']:
+        if 'workflow' in params:
+            assert 'workflow' in resp.json[0]
+            assert 'data' not in resp.json[0]['workflow']
+        else:
+            assert 'workflow' not in resp.json[0]
+    for params in ['?full=on', '?include-workflow-data=on']:
         resp = get_app(pub).get(sign_uri('/api/forms/test/list%s' % params, user=local_user))
         assert 'workflow' in resp.json[0]
+        assert 'data' in resp.json[0]['workflow']
 
 
 def test_formdata_with_evolution_part_attachment(pub, local_user):
@@ -629,6 +637,7 @@ def test_formdata_with_evolution_part_attachment(pub, local_user):
         '?include-roles=on',
         '?include-submission=on',
         '?include-workflow=on',
+        '?include-workflow-data=on',
     ]:
         resp = get_app(pub).get(sign_uri('/api/forms/test/list%s' % params, user=local_user))
         assert 'evolution' not in resp.json[0]
@@ -703,6 +712,7 @@ def test_formdata_with_evolution_part_attachment_to(pub, local_user):
         '?include-roles=on',
         '?include-submission=on',
         '?include-workflow=on',
+        '?include-workflow-data=on',
     ]:
         resp = get_app(pub).get(sign_uri('/api/forms/test/list%s' % params, user=local_user))
         assert 'evolution' not in resp.json[0]
@@ -785,6 +795,7 @@ def test_formdata_with_roles(pub, local_user):
         '?include-evolution=on',
         '?include-submission=on',
         '?include-workflow=on',
+        '?include-workflow-data=on',
     ]:
         resp = get_app(pub).get(sign_uri('/api/forms/test/list%s' % params, user=local_user))
         assert 'roles' not in resp.json[0]
diff --git a/wcs/backoffice/management.py b/wcs/backoffice/management.py
index 6892217ba..27e6cd378 100644
--- a/wcs/backoffice/management.py
+++ b/wcs/backoffice/management.py
@@ -2468,7 +2468,15 @@ class FormPage(FormdefDirectoryBase):
         include_roles = get_request().form.get('include-roles') == 'on' or full
         include_submission = get_request().form.get('include-submission') == 'on' or full
         include_workflow = get_request().form.get('include-workflow') == 'on' or full
-        if include_fields or include_evolution or include_roles or include_submission or include_workflow:
+        include_workflow_data = get_request().form.get('include-workflow-data') == 'on' or full
+        if (
+            include_fields
+            or include_evolution
+            or include_roles
+            or include_submission
+            or include_workflow
+            or include_workflow_data
+        ):
             output = JsonFileExportAfterJob(self.formdef).create_json_export(
                 items,
                 user=user,
@@ -2481,6 +2489,7 @@ class FormPage(FormdefDirectoryBase):
                 include_fields=include_fields,
                 include_unnamed_fields=False,
                 include_workflow=include_workflow,
+                include_workflow_data=include_workflow_data,
             )
         else:
             output = [
@@ -4329,6 +4338,7 @@ class JsonFileExportAfterJob(CsvExportAfterJob):
         include_fields,
         include_unnamed_fields,
         include_workflow,
+        include_workflow_data,
     ):
         # noqa pylint: disable=too-many-arguments
         formdef = self.kwargs['formdef_class'].get(self.kwargs['formdef_id'])
@@ -4379,6 +4389,7 @@ class JsonFileExportAfterJob(CsvExportAfterJob):
                 include_fields=include_fields,
                 include_unnamed_fields=include_unnamed_fields,
                 include_workflow=include_workflow,
+                include_workflow_data=include_workflow_data,
             )
             data.pop('digests')
             if digest_key:
@@ -4402,6 +4413,7 @@ class JsonFileExportAfterJob(CsvExportAfterJob):
                     include_fields=True,
                     include_unnamed_fields=True,
                     include_workflow=True,
+                    include_workflow_data=True,
                 )
             },
             indent=2,
diff --git a/wcs/formdata.py b/wcs/formdata.py
index e75f4e72a..5d09b1b96 100644
--- a/wcs/formdata.py
+++ b/wcs/formdata.py
@@ -1364,6 +1364,7 @@ class FormData(StorableObject):
         include_fields=True,
         include_unnamed_fields=False,
         include_workflow=True,
+        include_workflow_data=True,
     ):
         # noqa pylint: disable=too-many-arguments
         data = {}
@@ -1411,9 +1412,6 @@ class FormData(StorableObject):
             wf_real_status = self.get_status()
             if wf_real_status:
                 data['workflow']['real_status'] = {'id': wf_real_status.id, 'name': wf_real_status.name}
-            # Workflow data have unknown purpose, do not store them in anonymised export
-            if self.workflow_data and not anonymise:
-                data['workflow']['data'] = self.workflow_data
             if self.formdef.workflow.get_backoffice_fields():
                 data['workflow']['fields'] = self.get_json_dict(
                     self.formdef.workflow.get_backoffice_fields(),
@@ -1421,6 +1419,12 @@ class FormData(StorableObject):
                     anonymise=anonymise,
                     include_unnamed_fields=include_unnamed_fields,
                 )
+        if include_workflow_data:
+            # Workflow data have unknown purpose, do not store them in anonymised export
+            if self.workflow_data and not anonymise:
+                if 'workflow' not in data:
+                    data['workflow'] = {}
+                data['workflow']['data'] = self.workflow_data
 
         if include_roles:
             # add a roles dictionary, with workflow functions and two special
-- 
2.35.1

