From 51d935656a8105963e7afff428d402cfb37c7758 Mon Sep 17 00:00:00 2001
From: Nicolas ROCHE
Date: Tue, 27 Apr 2021 11:15:01 +0200
Subject: [PATCH] api: include attachment evolution parts in {card,form}data
fetch API (#53253)
---
tests/api/test_formdata.py | 57 +++++++++++++++++++++++++++++++++++++-
wcs/formdata.py | 15 ++++++++--
wcs/wf/register_comment.py | 2 +-
wcs/wf/wscall.py | 2 +-
wcs/workflows.py | 12 ++++++++
5 files changed, 82 insertions(+), 6 deletions(-)
diff --git a/tests/api/test_formdata.py b/tests/api/test_formdata.py
index b2e8af642..bef2e18ca 100644
--- a/tests/api/test_formdata.py
+++ b/tests/api/test_formdata.py
@@ -24,7 +24,12 @@ from wcs.qommon import ods
from wcs.qommon.http_request import HTTPRequest
from wcs.qommon.ident.password_accounts import PasswordAccount
from wcs.qommon.upload_storage import PicklableUpload
-from wcs.workflows import EditableWorkflowStatusItem, Workflow, WorkflowBackofficeFieldsFormDef
+from wcs.workflows import (
+ AttachmentEvolutionPart,
+ EditableWorkflowStatusItem,
+ Workflow,
+ WorkflowBackofficeFieldsFormDef,
+)
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app, login
from .utils import sign_uri
@@ -464,6 +469,56 @@ def test_formdata_with_workflow_data(pub, local_user):
assert base64.decodebytes(force_bytes(resp.json['workflow']['data']['blah2']['content'])) == b'test'
+def test_formdata_with_evolution_part_attachment(pub, local_user):
+ pub.role_class.wipe()
+ role = pub.role_class(name='test')
+ role.id = '123'
+ role.store()
+
+ local_user.roles = [role.id]
+ local_user.store()
+
+ FormDef.wipe()
+ formdef = FormDef()
+ formdef.name = 'test'
+ formdef.fields = []
+ workflow = Workflow.get_default_workflow()
+ workflow.id = '2'
+ workflow.store()
+ formdef.workflow_id = workflow.id
+ formdef.workflow_roles = {'_receiver': role.id}
+ formdef.store()
+
+ formdef.data_class().wipe()
+ formdata = formdef.data_class()()
+ formdata.just_created()
+ formdata.status = 'wf-new'
+ formdata.evolution[-1].status = 'wf-new'
+ formdata.evolution[-1].parts = [
+ AttachmentEvolutionPart(
+ 'hello.txt', fp=io.BytesIO(b'test'), content_type='text/plain', varname='testfile'
+ )
+ ]
+ formdata.store()
+
+ resp = get_app(pub).get(sign_uri('/api/forms/test/%s/' % formdata.id, user=local_user))
+ assert len(resp.json['evolution']) == 1
+ assert len(resp.json['evolution'][0]['parts']) == 1
+ part = resp.json['evolution'][0]['parts'][0]
+ assert part['filename'] == 'hello.txt'
+ assert part['content_type'] == 'text/plain'
+ assert 'content' in part
+ assert base64.decodebytes(force_bytes(part['content'])) == b'test'
+
+ resp = get_app(pub).get(sign_uri('/api/forms/test/%s/?anonymise' % formdata.id, user=local_user))
+ assert len(resp.json['evolution']) == 1
+ assert 'parts' not in resp.json['evolution']
+
+ # check this doesn't get into list of forms API
+ resp = get_app(pub).get(sign_uri('/api/forms/test/list?full=on', user=local_user))
+ assert 'hello.txt' not in resp.text
+
+
def test_api_list_formdata(pub, local_user):
pub.role_class.wipe()
role = pub.role_class(name='test')
diff --git a/wcs/formdata.py b/wcs/formdata.py
index 8fea86fac..59fcf1b04 100644
--- a/wcs/formdata.py
+++ b/wcs/formdata.py
@@ -159,7 +159,7 @@ class Evolution:
self._display_parts = l
return self._display_parts
- def get_json_export_dict(self, user, anonymise=False):
+ def get_json_export_dict(self, user, anonymise=False, include_files=True):
data = {
'time': datetime.datetime(*self.time[:6]) if self.time else None,
'last_jump_datetime': self.last_jump_datetime,
@@ -180,7 +180,10 @@ class Evolution:
parts = []
for part in self.parts or []:
if hasattr(part, 'get_json_export_dict'):
- parts.append(part.get_json_export_dict(anonymise=anonymise))
+ d = part.get_json_export_dict(anonymise=anonymise, include_files=include_files)
+ if d:
+ parts.append(d)
+
if parts:
data['parts'] = parts
return data
@@ -1213,7 +1216,13 @@ class FormData(StorableObject):
if self.evolution:
evolution = data['evolution'] = []
for evo in self.evolution:
- evolution.append(evo.get_json_export_dict(None if anonymise else user, anonymise=anonymise))
+ evolution.append(
+ evo.get_json_export_dict(
+ user=None if anonymise else user,
+ anonymise=anonymise,
+ include_files=include_files,
+ )
+ )
if self.geolocations:
data['geolocations'] = {}
diff --git a/wcs/wf/register_comment.py b/wcs/wf/register_comment.py
index 8549713ec..655b936dc 100644
--- a/wcs/wf/register_comment.py
+++ b/wcs/wf/register_comment.py
@@ -69,7 +69,7 @@ class JournalEvolutionPart:
+ htmltext('
')
)
- def get_json_export_dict(self, anonymise=False):
+ def get_json_export_dict(self, anonymise=False, include_files=True):
d = {
'type': 'workflow-comment',
'to': self.to,
diff --git a/wcs/wf/wscall.py b/wcs/wf/wscall.py
index 6fd8d792c..b22a5c722 100644
--- a/wcs/wf/wscall.py
+++ b/wcs/wf/wscall.py
@@ -94,7 +94,7 @@ class JournalWsCallErrorPart:
r += htmltext('')
return r.getvalue()
- def get_json_export_dict(self, anonymise=False):
+ def get_json_export_dict(self, anonymise=False, include_files=True):
d = {
'type': 'wscall-error',
}
diff --git a/wcs/workflows.py b/wcs/workflows.py
index 4b6416c0d..677d406f4 100644
--- a/wcs/workflows.py
+++ b/wcs/workflows.py
@@ -271,6 +271,18 @@ class AttachmentEvolutionPart:
else:
return htmltext('%s
' % self.orig_filename)
+ def get_json_export_dict(self, anonymise=False, include_files=True):
+ if not include_files or anonymise:
+ return None
+ d = {
+ 'type': 'workflow-attachment',
+ 'content_type': self.content_type,
+ 'filename': self.base_filename,
+ }
+ with open(self.filename, 'rb') as fd:
+ d['content'] = base64.encodebytes(fd.read())
+ return d
+
@classmethod
def get_substitution_variables(cls, formdata):
return {