workflows: filter attachment with target roles on comment (#54081)
This commit is contained in:
parent
101a8ebbca
commit
235740a742
|
@ -12,6 +12,7 @@ import zipfile
|
|||
import pytest
|
||||
from django.utils.encoding import force_bytes
|
||||
from quixote import get_publisher
|
||||
from webtest import Upload
|
||||
|
||||
from wcs import fields
|
||||
from wcs.api_access import ApiAccess
|
||||
|
@ -24,6 +25,7 @@ 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.wf.register_comment import RegisterCommenterWorkflowStatusItem
|
||||
from wcs.workflows import (
|
||||
AttachmentEvolutionPart,
|
||||
EditableWorkflowStatusItem,
|
||||
|
@ -508,6 +510,7 @@ def test_formdata_with_evolution_part_attachment(pub, local_user):
|
|||
assert part['filename'] == 'hello.txt'
|
||||
assert part['content_type'] == 'text/plain'
|
||||
assert 'content' in part
|
||||
assert 'to' 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))
|
||||
|
@ -519,6 +522,70 @@ def test_formdata_with_evolution_part_attachment(pub, local_user):
|
|||
assert 'hello.txt' not in resp.text
|
||||
|
||||
|
||||
def test_formdata_with_evolution_part_attachment_to(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()
|
||||
|
||||
workflow = Workflow(name='test')
|
||||
st1 = workflow.add_status('Status1', 'st1')
|
||||
|
||||
add_to_journal = RegisterCommenterWorkflowStatusItem()
|
||||
add_to_journal.id = '_add_to_journal'
|
||||
add_to_journal.comment = 'HELLO WORLD'
|
||||
add_to_journal.attachments = ['form_var_file_raw']
|
||||
add_to_journal.to = [role.id]
|
||||
st1.items.append(add_to_journal)
|
||||
|
||||
workflow.store()
|
||||
|
||||
FormDef.wipe()
|
||||
formdef = FormDef()
|
||||
formdef.name = 'test'
|
||||
formdef.workflow_id = workflow.id
|
||||
formdef.workflow_roles = {'_receiver': role.id}
|
||||
formdef.fields = [fields.FileField(id='1', label='File1', type='file', varname='file')]
|
||||
formdef.store()
|
||||
formdef.data_class().wipe()
|
||||
|
||||
resp = get_app(pub).get('/test/')
|
||||
resp.forms[0]['f1$file'] = Upload('hello.txt', b'foobar', 'text/plain')
|
||||
resp = resp.forms[0].submit('submit')
|
||||
assert 'Check values then click submit.' in resp.text
|
||||
resp = resp.forms[0].submit('submit')
|
||||
assert resp.status_int == 302
|
||||
resp = resp.follow()
|
||||
assert 'The form has been recorded' in resp.text
|
||||
|
||||
formdata = formdef.data_class().select()[0]
|
||||
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']) == 2
|
||||
assert resp.json['evolution'][0]['parts'][1]['type'] == 'workflow-comment'
|
||||
part = resp.json['evolution'][0]['parts'][0]
|
||||
assert part['type'] == 'workflow-attachment'
|
||||
assert part['filename'] == 'hello.txt'
|
||||
assert part['content_type'] == 'text/plain'
|
||||
assert part['to'] == ['123']
|
||||
assert 'content' in part
|
||||
assert base64.decodebytes(force_bytes(part['content'])) == b'foobar'
|
||||
|
||||
resp = get_app(pub).get(sign_uri('/api/forms/test/%s/?anonymise' % formdata.id, user=local_user))
|
||||
assert len(resp.json['evolution']) == 1
|
||||
assert len(resp.json['evolution'][0]['parts']) == 1
|
||||
assert resp.json['evolution'][0]['parts'][0]['type'] == 'workflow-comment'
|
||||
|
||||
# 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 len(resp.json[0]['evolution']) == 1
|
||||
assert len(resp.json[0]['evolution'][0]['parts']) == 1
|
||||
assert resp.json[0]['evolution'][0]['parts'][0]['type'] == 'workflow-comment'
|
||||
|
||||
|
||||
def test_api_list_formdata(pub, local_user):
|
||||
pub.role_class.wipe()
|
||||
role = pub.role_class(name='test')
|
||||
|
|
|
@ -1640,3 +1640,78 @@ def test_formdata_evolution_registercommenter_to(pub):
|
|||
resp = app.get('/test/%s/' % formdata.id)
|
||||
resp.status_int = 200
|
||||
assert resp.html.find('div', {'id': 'evolution-log'}).find('p').text == 'Hello World'
|
||||
|
||||
|
||||
def test_formdata_evolution_registercommenter_to_with_attachment(pub):
|
||||
user = create_user(pub)
|
||||
|
||||
pub.role_class.wipe()
|
||||
role1 = pub.role_class(name='role the user does not have')
|
||||
role1.store()
|
||||
role2 = pub.role_class(name='role the user does have')
|
||||
role2.store()
|
||||
user.roles = [role2.id]
|
||||
user.store()
|
||||
|
||||
wf = Workflow(name='status')
|
||||
st1 = wf.add_status('Status1', 'st1')
|
||||
|
||||
comment = RegisterCommenterWorkflowStatusItem()
|
||||
comment.id = '1'
|
||||
comment.comment = 'Hello all'
|
||||
comment.attachments = ['form_var_file1_raw']
|
||||
comment.to = None
|
||||
st1.items.append(comment)
|
||||
comment.parent = st1
|
||||
|
||||
comment = RegisterCommenterWorkflowStatusItem()
|
||||
comment.id = '2'
|
||||
comment.comment = 'Hello role1'
|
||||
comment.attachments = ['form_var_file2_raw']
|
||||
comment.to = [role1.id]
|
||||
st1.items.append(comment)
|
||||
comment.parent = st1
|
||||
|
||||
comment = RegisterCommenterWorkflowStatusItem()
|
||||
comment.id = '3'
|
||||
comment.comment = 'Hello role2'
|
||||
comment.attachments = ['form_var_file3_raw']
|
||||
comment.to = [role2.id]
|
||||
st1.items.append(comment)
|
||||
comment.parent = st1
|
||||
|
||||
wf.store()
|
||||
|
||||
FormDef.wipe()
|
||||
formdef = FormDef()
|
||||
formdef.name = 'test'
|
||||
formdef.workflow_id = wf.id
|
||||
formdef.fields = [
|
||||
fields.FileField(id='1', label='File1', type='file', varname='file1'),
|
||||
fields.FileField(id='2', label='File2', type='file', varname='file2'),
|
||||
fields.FileField(id='3', label='File3', type='file', varname='file3'),
|
||||
]
|
||||
formdef.store()
|
||||
formdef.data_class().wipe()
|
||||
|
||||
app = login(get_app(pub), username='foo', password='foo')
|
||||
resp = app.get('/test/')
|
||||
resp.forms[0]['f1$file'] = Upload('to-all.txt', b'foobar', 'text/plain')
|
||||
resp.forms[0]['f2$file'] = Upload('to-role1.txt', b'foobar', 'text/plain')
|
||||
resp.forms[0]['f3$file'] = Upload('to-role2.txt', b'foobar', 'text/plain')
|
||||
resp = resp.forms[0].submit('submit')
|
||||
assert 'Check values then click submit.' in resp.text
|
||||
resp = resp.forms[0].submit('submit')
|
||||
assert resp.status_int == 302
|
||||
resp = resp.follow()
|
||||
assert 'The form has been recorded' in resp.text
|
||||
|
||||
formdata = formdef.data_class().select()[0]
|
||||
assert len(formdata.evolution[0].parts) == 6
|
||||
|
||||
resp = app.get('/test/%s/' % formdata.id)
|
||||
resp.status_int = 200
|
||||
assert [x.a.text for x in resp.html.find_all('p', {'class': 'wf-attachment'})] == [
|
||||
'to-all.txt',
|
||||
'to-role2.txt',
|
||||
]
|
||||
|
|
|
@ -1294,6 +1294,102 @@ def test_register_comment_to(pub):
|
|||
assert '<p>d2</p>' in [str(x) for x in display_parts()]
|
||||
|
||||
|
||||
def test_register_comment_to_with_attachment(pub):
|
||||
workflow = Workflow(name='register comment to with attachment')
|
||||
st1 = workflow.add_status('Status1', 'st1')
|
||||
|
||||
role = pub.role_class(name='foorole')
|
||||
role.store()
|
||||
role2 = pub.role_class(name='no-one-role')
|
||||
role2.store()
|
||||
user = pub.user_class(name='baruser')
|
||||
user.roles = []
|
||||
user.store()
|
||||
|
||||
upload1 = PicklableUpload('all.txt', 'text/plain')
|
||||
upload1.receive([b'barfoo'])
|
||||
upload2 = PicklableUpload('to-role.txt', 'text/plain')
|
||||
upload2.receive([b'barfoo'])
|
||||
upload3 = PicklableUpload('to-submitter.txt', 'text/plain')
|
||||
upload3.receive([b'barfoo'])
|
||||
upload4 = PicklableUpload('to-role-or-submitter.txt', 'text/plain')
|
||||
upload4.receive([b'barfoo'])
|
||||
|
||||
FormDef.wipe()
|
||||
formdef = FormDef()
|
||||
formdef.url_name = 'foobar'
|
||||
formdef.fields = [
|
||||
FileField(id='1', label='File1', type='file', varname='file1'),
|
||||
FileField(id='2', label='File2', type='file', varname='file2'),
|
||||
FileField(id='3', label='File3', type='file', varname='file3'),
|
||||
FileField(id='4', label='File4', type='file', varname='file4'),
|
||||
]
|
||||
formdef._workflow = workflow
|
||||
formdef.store()
|
||||
|
||||
formdata = formdef.data_class()()
|
||||
formdata.data = {'1': upload1, '2': upload2, '3': upload3, '4': upload4}
|
||||
formdata.just_created()
|
||||
assert formdata.status == 'wf-st1'
|
||||
pub.substitutions.feed(formdata)
|
||||
|
||||
register_commenter = RegisterCommenterWorkflowStatusItem()
|
||||
register_commenter.parent = st1
|
||||
st1.items.append(register_commenter)
|
||||
|
||||
def display_parts():
|
||||
formdata.evolution[-1]._display_parts = None # invalidate cache
|
||||
return [str(x) for x in formdata.evolution[-1].display_parts()]
|
||||
|
||||
register_commenter.comment = 'all'
|
||||
register_commenter.attachments = ['form_var_file1_raw']
|
||||
register_commenter.to = None
|
||||
register_commenter.perform(formdata)
|
||||
|
||||
register_commenter.comment = 'to-role'
|
||||
register_commenter.attachments = ['form_var_file2_raw']
|
||||
register_commenter.to = [role.id]
|
||||
register_commenter.perform(formdata)
|
||||
|
||||
register_commenter.comment = 'to-submitter'
|
||||
register_commenter.attachments = ['form_var_file3_raw']
|
||||
register_commenter.to = ['_submitter']
|
||||
register_commenter.perform(formdata)
|
||||
|
||||
register_commenter.comment = 'to-role-or-submitter'
|
||||
register_commenter.attachments = ['form_var_file4_raw']
|
||||
register_commenter.to = [role.id, '_submitter']
|
||||
register_commenter.perform(formdata)
|
||||
|
||||
assert len(formdata.evolution[-1].parts) == 8
|
||||
|
||||
assert user.roles == []
|
||||
assert len(display_parts()) == 2
|
||||
assert 'all.txt' in display_parts()[0]
|
||||
assert display_parts()[1] == '<p>all</p>'
|
||||
|
||||
pub._request._user = user
|
||||
user.roles = [role.id]
|
||||
assert len(display_parts()) == 6
|
||||
assert 'all.txt' in display_parts()[0]
|
||||
assert 'to-role.txt' in display_parts()[2]
|
||||
assert 'to-role-or-submitter.txt' in display_parts()[4]
|
||||
|
||||
user.roles = []
|
||||
formdata.user_id = user.id
|
||||
assert len(display_parts()) == 6
|
||||
assert 'all.txt' in display_parts()[0]
|
||||
assert 'to-submitter.txt' in display_parts()[2]
|
||||
assert 'to-role-or-submitter.txt' in display_parts()[4]
|
||||
|
||||
user.roles = [role.id]
|
||||
assert len(display_parts()) == 8
|
||||
assert 'all.txt' in display_parts()[0]
|
||||
assert 'to-role.txt' in display_parts()[2]
|
||||
assert 'to-submitter.txt' in display_parts()[4]
|
||||
assert 'to-role-or-submitter.txt' in display_parts()[6]
|
||||
|
||||
|
||||
def test_email(pub, emails):
|
||||
pub.substitutions.feed(MockSubstitutionVariables())
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ class RegisterCommenterWorkflowStatusItem(WorkflowStatusItem):
|
|||
def get_parameters(self):
|
||||
return ('comment', 'to', 'attachments', 'condition')
|
||||
|
||||
def attach_uploads_to_formdata(self, formdata, uploads):
|
||||
def attach_uploads_to_formdata(self, formdata, uploads, to):
|
||||
if not formdata.evolution[-1].parts:
|
||||
formdata.evolution[-1].parts = []
|
||||
for upload in uploads:
|
||||
|
@ -120,7 +120,7 @@ class RegisterCommenterWorkflowStatusItem(WorkflowStatusItem):
|
|||
# useless but required to restore upload.fp from serialized state,
|
||||
# needed by AttachmentEvolutionPart.from_upload()
|
||||
upload.get_file_pointer()
|
||||
formdata.evolution[-1].add_part(AttachmentEvolutionPart.from_upload(upload))
|
||||
formdata.evolution[-1].add_part(AttachmentEvolutionPart.from_upload(upload, to=to))
|
||||
except Exception:
|
||||
get_publisher().notify_of_exception(sys.exc_info(), context='[comment/attachments]')
|
||||
continue
|
||||
|
@ -133,7 +133,7 @@ class RegisterCommenterWorkflowStatusItem(WorkflowStatusItem):
|
|||
# (with substitution vars)
|
||||
if self.attachments:
|
||||
uploads = self.convert_attachments_to_uploads()
|
||||
self.attach_uploads_to_formdata(formdata, uploads)
|
||||
self.attach_uploads_to_formdata(formdata, uploads, self.to)
|
||||
formdata.store() # store and invalidate cache, so references can be used in the comment message.
|
||||
|
||||
# the comment can use attachments done above
|
||||
|
|
|
@ -216,6 +216,7 @@ class AttachmentEvolutionPart(EvolutionPart):
|
|||
varname=None,
|
||||
storage=None,
|
||||
storage_attrs=None,
|
||||
to=None,
|
||||
):
|
||||
self.base_filename = base_filename
|
||||
self.orig_filename = orig_filename or base_filename
|
||||
|
@ -225,9 +226,10 @@ class AttachmentEvolutionPart(EvolutionPart):
|
|||
self.varname = varname
|
||||
self.storage = storage
|
||||
self.storage_attrs = storage_attrs
|
||||
self.to = to
|
||||
|
||||
@classmethod
|
||||
def from_upload(cls, upload, varname=None):
|
||||
def from_upload(cls, upload, varname=None, to=None):
|
||||
return AttachmentEvolutionPart(
|
||||
upload.base_filename,
|
||||
getattr(upload, 'fp', None),
|
||||
|
@ -237,6 +239,7 @@ class AttachmentEvolutionPart(EvolutionPart):
|
|||
varname=varname,
|
||||
storage=getattr(upload, 'storage', None),
|
||||
storage_attrs=getattr(upload, 'storage_attrs', None),
|
||||
to=to,
|
||||
)
|
||||
|
||||
def get_file_pointer(self):
|
||||
|
@ -291,6 +294,7 @@ class AttachmentEvolutionPart(EvolutionPart):
|
|||
'type': 'workflow-attachment',
|
||||
'content_type': self.content_type,
|
||||
'filename': self.base_filename,
|
||||
'to': self.to,
|
||||
}
|
||||
fd = self.get_file_pointer()
|
||||
if fd:
|
||||
|
|
Loading…
Reference in New Issue