From 1d1c3c9e46ef61ccc514503cd90a0e5d34d8b88c Mon Sep 17 00:00:00 2001 From: Thomas NOEL Date: Wed, 4 Oct 2017 11:40:47 +0200 Subject: [PATCH 2/2] workflow: allow to send generated docs in backoffice field (#19188) --- tests/test_form_pages.py | 67 ++++++++++++++++++++++++++++++++++++++++++++++- tests/test_workflows.py | 64 ++++++++++++++++++++++++++++++++++++++++++++ wcs/wf/export_to_model.py | 35 +++++++++++++++++++++++-- 3 files changed, 163 insertions(+), 3 deletions(-) diff --git a/tests/test_form_pages.py b/tests/test_form_pages.py index 8e53909d..304a0eff 100644 --- a/tests/test_form_pages.py +++ b/tests/test_form_pages.py @@ -19,7 +19,8 @@ from quixote.http_request import Upload as QuixoteUpload from wcs.qommon.form import UploadedFile from wcs.qommon.ident.password_accounts import PasswordAccount from wcs.formdef import FormDef -from wcs.workflows import Workflow, EditableWorkflowStatusItem, DisplayMessageWorkflowStatusItem +from wcs.workflows import (Workflow, EditableWorkflowStatusItem, + DisplayMessageWorkflowStatusItem, WorkflowBackofficeFieldsFormDef) from wcs.wf.export_to_model import ExportToModel, transform_to_pdf from wcs.wf.jump import JumpWorkflowStatusItem from wcs.wf.attachment import AddAttachmentWorkflowStatusItem @@ -2551,6 +2552,70 @@ def test_formdata_generated_document_non_interactive(pub): assert formdef.data_class().count() == 1 assert formdef.data_class().select()[0].status == 'wf-st2' +def test_formdata_generated_document_to_backoffice_field(pub): + create_user_and_admin(pub) + wf = Workflow(name='status') + wf.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(wf) + wf.backoffice_fields_formdef.fields = [ + fields.FileField(id='bo1', label='bo field 1', type='file'), + fields.StringField(id='bo2', label='bo field 2', type='string'), + ] + + st1 = wf.add_status('Status1', 'st1') + export_to = ExportToModel() + export_to.method = 'non-interactive' + template_filename = os.path.join(os.path.dirname(__file__), 'template.odt') + template = open(template_filename).read() + upload = QuixoteUpload('/foo/template.odt', content_type='application/octet-stream') + upload.fp = StringIO.StringIO() + upload.fp.write(template) + upload.fp.seek(0) + export_to.model_file = UploadedFile(pub.app_dir, None, upload) + export_to.id = '_export_to' + export_to.attach_to_history = True + export_to.backoffice_filefield_id = 'bo1' + st1.items.append(export_to) + export_to.parent = st1 + + assert export_to.get_backoffice_filefield_options() == [('bo1', 'bo field 1', 'bo1')] + + jump = JumpWorkflowStatusItem() + jump.status = 'st2' + st1.items.append(jump) + jump.parent = st1 + wf.add_status('Status2', 'st2') + wf.store() + + formdef = create_formdef() + formdef.workflow_id = wf.id + formdef.fields = [fields.TextField(id='0', label='comment', type='text', varname='comment')] + formdef.store() + formdef.data_class().wipe() + + resp = login(get_app(pub), username='foo', password='foo').get('/test/') + resp.form['f0'] = 'Hello\n\nWorld.' + resp = resp.forms[0].submit('submit') + assert 'Check values then click submit.' in resp.body + resp = resp.forms[0].submit('submit') + assert resp.status_int == 302 + resp = resp.follow() + assert 'The form has been recorded' in resp.body + + # get the two generated files from backoffice: in backoffice fields + # (export_to.backoffice_filefield_id), and in history (export_to.attach_to_history) + for index in (0, 1): + resp = login(get_app(pub), username='admin', password='admin').get( + '/backoffice/management/test/1/') + resp = resp.click('template.odt', index=index) + assert resp.location.endswith('/template.odt') + resp = resp.follow() + assert resp.content_type == 'application/octet-stream' + with open(os.path.join(os.path.dirname(__file__), 'template-out.odt')) as f: + assert_equal_zip(StringIO.StringIO(resp.body), f) + + assert formdef.data_class().count() == 1 + assert formdef.data_class().select()[0].status == 'wf-st2' + def test_formdata_form_file_download(pub): create_user(pub) wf = Workflow(name='status') diff --git a/tests/test_workflows.py b/tests/test_workflows.py index c551d1fa..73411ca2 100644 --- a/tests/test_workflows.py +++ b/tests/test_workflows.py @@ -2124,6 +2124,70 @@ def test_export_to_model_image(pub): # check the original image has been left assert zinfo.file_size == 580 +def test_export_to_model_backoffice_field(pub): + wf = Workflow(name='email with attachments') + wf.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(wf) + wf.backoffice_fields_formdef.fields = [ + FileField(id='bo1', label='bo field 1', type='file', varname='backoffice_file1'), + ] + st1 = wf.add_status('Status1') + wf.store() + formdef = FormDef() + formdef.name = 'foo-export-to-bofile' + formdef.fields = [ + StringField(id='1', label='String', type='string', varname='string'), + ] + formdef.workflow_id = wf.id + formdef.store() + formdata = formdef.data_class()() + formdata.data = {} + formdata.just_created() + formdata.store() + pub.substitutions.feed(formdata) + + item = ExportToModel() + item.method = 'non-interactive' + template_filename = os.path.join(os.path.dirname(__file__), 'template.odt') + template = open(template_filename).read() + upload = QuixoteUpload('/foo/template.odt', content_type='application/octet-stream') + upload.fp = StringIO.StringIO() + upload.fp.write(template) + upload.fp.seek(0) + item.model_file = UploadedFile(pub.app_dir, None, upload) + item.parent = st1 + item.backoffice_filefield_id = 'bo1' + item.perform(formdata) + + assert 'bo1' in formdata.data + fbo1 = formdata.data['bo1'] + assert fbo1.base_filename == 'template.odt' + assert fbo1.content_type == 'application/octet-stream' + zfile = zipfile.ZipFile(fbo1.get_file()) + assert 'foo-export-to-bofile' in zfile.read('content.xml') + + # no more 'bo1' backoffice field: do nothing + formdata = formdef.data_class()() + formdata.data = {} + formdata.just_created() + formdata.store() + pub.substitutions.feed(formdata) + # id is not bo1: + wf.backoffice_fields_formdef.fields = [ + FileField(id='bo2', label='bo field 2', type='file'), + ] + item.perform(formdata) + assert formdata.data == {} + # field is not a field file: + wf.backoffice_fields_formdef.fields = [ + StringField(id='bo1', label='bo field 1', type='string'), + ] + item.perform(formdata) + assert formdata.data == {} + # no field at all: + wf.backoffice_fields_formdef.fields = [] + item.perform(formdata) + assert formdata.data == {} + def test_global_timeouts(pub): FormDef.wipe() Workflow.wipe() diff --git a/wcs/wf/export_to_model.py b/wcs/wf/export_to_model.py index df765007..4250038b 100644 --- a/wcs/wf/export_to_model.py +++ b/wcs/wf/export_to_model.py @@ -34,7 +34,7 @@ from qommon import ezt from qommon.form import (SingleSelectWidget, WidgetList, CheckboxWidget, StringWidget, UploadWidget, WysiwygTextWidget, Upload, UploadedFile, UploadValidationError, VarnameWidget, - RadiobuttonsWidget) + RadiobuttonsWidget, PicklableUpload) from qommon.errors import PublishError import qommon @@ -212,6 +212,7 @@ class ExportToModel(WorkflowStatusItem): convert_to_pdf = False push_to_portfolio = False method = 'interactive' + backoffice_filefield_id = None def render_as_line(self): if self.model_file: @@ -276,13 +277,20 @@ class ExportToModel(WorkflowStatusItem): def get_parameters(self): parameters = ('method', 'by', 'label', 'model_file', 'attach_to_history', - 'backoffice_info_text', 'varname') + 'backoffice_info_text', 'varname', 'backoffice_filefield_id') if transform_to_pdf is not None: parameters += ('convert_to_pdf',) if has_portfolio(): parameters += ('push_to_portfolio',) return parameters + def get_backoffice_filefield_options(self): + options = [] + for field in self.parent.parent.get_backoffice_fields(): + if field.key == 'file': + options.append((field.id, field.label, field.id)) + return options + def add_parameters_widgets(self, form, parameters, prefix='', formdef=None): methods = collections.OrderedDict( @@ -322,6 +330,13 @@ class ExportToModel(WorkflowStatusItem): form.add(CheckboxWidget, '%sconvert_to_pdf' % prefix, title=_('Convert generated file to PDF'), value=self.convert_to_pdf) + if 'backoffice_filefield_id' in parameters: + options = self.get_backoffice_filefield_options() + if options: + form.add(SingleSelectWidget, '%sbackoffice_filefield_id' % prefix, + title=_('Store in a backoffice file field'), + value=self.backoffice_filefield_id, + options=[(None, '---', None)] + options) if 'attach_to_history' in parameters: form.add(CheckboxWidget, '%sattach_to_history' % prefix, title=_('Attach generated file to the form history'), @@ -516,6 +531,15 @@ class ExportToModel(WorkflowStatusItem): return self.perform_real(formdata, formdata.evolution[-1]) + def store_in_backoffice_filefield(self, formdata, filename, content_type, content): + filefield = [x for x in self.parent.parent.get_backoffice_fields() + if x.id == self.backoffice_filefield_id and x.key == 'file'] + if filefield: + upload = PicklableUpload(filename, content_type) + upload.receive([content]) + formdata.data[self.backoffice_filefield_id] = upload + formdata.store() + def perform_real(self, formdata, evo): outstream = self.apply_template_to_formdata(formdata) filename = self.model_file.base_filename @@ -532,5 +556,12 @@ class ExportToModel(WorkflowStatusItem): content_type=content_type, varname=self.varname)) formdata.store() + if self.backoffice_filefield_id: + outstream.seek(0) + self.store_in_backoffice_filefield( + formdata, + filename, + content_type, + outstream.read()) register_item_class(ExportToModel) -- 2.14.2