From 4b6257f63827efcc60211bf86882d73e88333392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Mon, 7 Mar 2016 15:01:03 +0100 Subject: [PATCH] workflows: add new action to submit the current formdata anew (#9419) --- tests/test_backoffice_pages.py | 67 +++++++++++++++++++++++- tests/utilities.py | 1 + wcs/backoffice/management.py | 12 +++++ wcs/wf/resubmit.py | 116 +++++++++++++++++++++++++++++++++++++++++ wcs/workflows.py | 1 + 5 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 wcs/wf/resubmit.py diff --git a/tests/test_backoffice_pages.py b/tests/test_backoffice_pages.py index 1eedcbe..b68aa67 100644 --- a/tests/test_backoffice_pages.py +++ b/tests/test_backoffice_pages.py @@ -17,9 +17,12 @@ from qommon.ident.password_accounts import PasswordAccount from wcs.qommon.http_request import HTTPRequest from wcs.roles import Role from wcs.workflows import (Workflow, CommentableWorkflowStatusItem, - ChoiceWorkflowStatusItem, EditableWorkflowStatusItem) + ChoiceWorkflowStatusItem, EditableWorkflowStatusItem, + JumpOnSubmitWorkflowStatusItem) from wcs.wf.dispatch import DispatchWorkflowStatusItem from wcs.wf.wscall import WebserviceCallStatusItem +from wcs.wf.register_comment import RegisterCommenterWorkflowStatusItem +from wcs.wf.resubmit import ResubmitWorkflowStatusItem from wcs.categories import Category from wcs.formdef import FormDef from wcs import fields @@ -1770,3 +1773,65 @@ def test_backoffice_advisory_lock(pub): assert 'Be warned this form is also being' in resp.body assert not '(unlock actions)' in resp.body assert len(resp.forms) == 1 + +def test_backoffice_resubmit(pub): + user = create_user(pub) + create_environment(pub) + + wf = Workflow(name='resubmit') + st1 = wf.add_status('Status1') + st2 = wf.add_status('Status2') + + resubmit = ResubmitWorkflowStatusItem() + resubmit.id = '_resubmit' + resubmit.by = [user.roles[0]] + st1.items.append(resubmit) + resubmit.parent = st1 + + jump = JumpOnSubmitWorkflowStatusItem() + jump.id = '_jump' + jump.status = st2.id + st1.items.append(jump) + jump.parent = st1 + + register_comment = RegisterCommenterWorkflowStatusItem() + register_comment.id = '_register' + register_comment.comment = '

resubmitted

' + st2.items.append(register_comment) + register_comment.parent = st2 + + wf.store() + + formdef = FormDef.get_by_urlname('form-title') + formdef.fields[0].varname = 'foo' + formdef.workflow_id = wf.id + formdef.store() + + formdef2 = FormDef() + formdef2.name = 'form title bis' + formdef2.backoffice_submission_roles = user.roles[:] + formdef2.fields = [ + fields.StringField(id='2', label='1st field', type='string', varname='foo') + ] + formdef2.store() + formdef2.data_class().wipe() + + formdata = formdef.data_class()() + formdata.just_created() + formdata.data= {'1': 'XXX'} + formdata.store() + + app = login(get_app(pub)) + resp = app.get(formdata.get_url(backoffice=True)) + resp.form['resubmit'].value = formdef2.id + resp = resp.form.submit('button_resubmit') + resp = resp.follow() + assert 'resubmitted' in resp.body + assert formdef2.data_class().select()[0].status == 'draft' + assert formdef2.data_class().select()[0].data == {'2': 'XXX'} + resp = resp.click('resubmitted') + resp = resp.follow() + resp = resp.follow() + assert resp.form['f2'].value == 'XXX' + assert 'Original form' in resp.body + assert formdata.get_url(backoffice=True) in resp.body diff --git a/tests/utilities.py b/tests/utilities.py index fd60a9d..454d7f3 100644 --- a/tests/utilities.py +++ b/tests/utilities.py @@ -97,6 +97,7 @@ def create_temporary_pub(sql_mode=False): fd = file(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') fd.write('[options]\n') fd.write('formdef-captcha-option = true\n') + fd.write('workflow-resubmit-action = true\n') if sql_mode: fd.write('postgresql = true\n') conn = psycopg2.connect(user=os.environ['USER']) diff --git a/wcs/backoffice/management.py b/wcs/backoffice/management.py index 058d2b2..c700247 100644 --- a/wcs/backoffice/management.py +++ b/wcs/backoffice/management.py @@ -1645,6 +1645,18 @@ class FormBackOfficeStatusPage(FormStatusPage): if formdata.submission_context or formdata.submission_channel: extra_context = formdata.submission_context or {} r += htmltext('
') + if extra_context.get('orig_formdef_id'): + r += htmltext('

%s

') % _('Original form') + try: + formdata = FormDef.get(extra_context.get('orig_formdef_id') + ).data_class().get(extra_context.get('orig_formdata_id')) + except KeyError: + r += htmltext('

%s

') % _('(deleted)') + else: + r += htmltext('

%s %s

') % ( + formdata.get_url(backoffice=True), + formdata.formdef.name, + formdata.get_display_id()) if formdata.submission_channel: r += htmltext('

%s

') % '%s: %s' % ( _('Channel'), formdata.get_submission_channel_label()) diff --git a/wcs/wf/resubmit.py b/wcs/wf/resubmit.py new file mode 100644 index 0000000..075d79b --- /dev/null +++ b/wcs/wf/resubmit.py @@ -0,0 +1,116 @@ +# w.c.s. - web application for online forms +# Copyright (C) 2005-2016 Entr'ouvert +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . + +from quixote import get_publisher + +from wcs.workflows import WorkflowStatusItem, register_item_class +from wcs.formdef import FormDef +from wcs.qommon.form import (WidgetList, SingleSelectWidget, StringWidget, + WysiwygTextWidget) + + +class ResubmitWorkflowStatusItem(WorkflowStatusItem): + description = N_('Resubmit') + key = 'resubmit' + endpoint = False + waitpoint = True + ok_in_global_action = False + + by = [] + label = None + backoffice_info_text = None + + @classmethod + def is_available(cls): + return get_publisher().has_site_option('workflow-resubmit-action') + + def render_as_line(self): + if self.by: + return _('Allow resubmit by %s') % self.render_list_of_roles(self.by) + else: + return _('Allow resubmit (not completed)') + + def fill_form(self, form, formdata, user): + label = self.label + if not label: + label = _('Resubmit') + list_forms = [(x.id, x.name, x.id) for x in FormDef.select(order_by='name') + if x.backoffice_submission_roles] + form.add(SingleSelectWidget, 'resubmit', title=_('Form'), + required=True, options=list_forms) + form.add_submit('button%s' % self.id, label) + form.get_widget('button%s' % self.id).backoffice_info_text = self.backoffice_info_text + + def submit_form(self, form, formdata, user, evo): + if form.get_submit() != 'button%s' % self.id: + return + formdef_id = form.get_widget('resubmit').parse() + formdef = FormDef.get(formdef_id) + new_formdata = formdef.data_class()() + new_formdata.status = 'draft' + new_formdata.user_id = formdata.user_id + new_formdata.submission_context = formdata.submission_context + new_formdata.submission_channel = formdata.submission_channel + new_formdata.backoffice_submission = True + if not new_formdata.submission_context: + new_formdata.submission_context = {} + new_formdata.submission_context['orig_formdef_id'] = formdata.formdef.id + new_formdata.submission_context['orig_formdata_id'] = formdata.id + new_formdata.data = {} + + field_dict = {} + for field in formdata.formdef.fields: + if not field.varname: + continue + field_dict['%s-%s' % (field.varname, field.type)] = field.id + + for field in formdef.fields: + field_dict_key = '%s-%s' % (field.varname, field.type) + orig_formdata_field_id = field_dict.get(field_dict_key) + if orig_formdata_field_id is None: + continue + for suffix in ('', '_raw', '_structured'): + old_key = '%s%s' % (orig_formdata_field_id, suffix) + new_key = '%s%s' % (field.id, suffix) + if not old_key in formdata.data: + continue + new_formdata.data[new_key] = formdata.data[old_key] + + new_formdata.store() + + workflow_data = {'resubmit_formdata_backoffice_url': new_formdata.get_url(backoffice=True)} + formdata.update_workflow_data(workflow_data) + formdata.store() + + def add_parameters_widgets(self, form, parameters, prefix='', formdef=None): + if 'by' in parameters: + form.add(WidgetList, '%sby' % prefix, title=_('By'), element_type=SingleSelectWidget, + value=self.by, + add_element_label=_('Add Role'), + element_kwargs={'render_br': False, + 'options': [(None, '---', None)] + self.get_list_of_roles()}) + if 'label' in parameters: + form.add(StringWidget, '%slabel' % prefix, title=_('Button Label'), + value=self.label or _('Resubmit')) + if 'backoffice_info_text' in parameters: + form.add(WysiwygTextWidget, '%sbackoffice_info_text' % prefix, + title=_('Information Text for Backoffice'), + value=self.backoffice_info_text) + + def get_parameters(self): + return ('by', 'label', 'backoffice_info_text') + +register_item_class(ResubmitWorkflowStatusItem) diff --git a/wcs/workflows.py b/wcs/workflows.py index 8d28081..49f4338 100644 --- a/wcs/workflows.py +++ b/wcs/workflows.py @@ -1960,5 +1960,6 @@ def load_extra(): import wf.register_comment import wf.anonymise import wf.export_to_model + import wf.resubmit from wf.export_to_model import ExportToModel -- 2.7.0