From a152248545e6aa06c170781d2dfd55c14d976a57 Mon Sep 17 00:00:00 2001 From: Valentin Deniaud Date: Tue, 14 Dec 2021 10:05:02 +0100 Subject: [PATCH] workflows: copy action from one status to another (#57894) --- tests/admin_pages/test_workflow.py | 92 +++++++++++++++++++ tests/test_snapshots.py | 7 ++ wcs/admin/workflows.py | 42 ++++++++- wcs/qommon/static/css/dc2/admin.scss | 4 +- .../wcs/backoffice/workflow-status.html | 1 + 5 files changed, 143 insertions(+), 3 deletions(-) diff --git a/tests/admin_pages/test_workflow.py b/tests/admin_pages/test_workflow.py index b7538fbde..70950bf26 100644 --- a/tests/admin_pages/test_workflow.py +++ b/tests/admin_pages/test_workflow.py @@ -470,6 +470,98 @@ def test_workflows_order_status(pub): assert Workflow.get(workflow.id).possible_status[2].id == status1_id +def test_workflows_copy_status_item(pub): + create_superuser(pub) + Workflow.wipe() + workflow = Workflow(name='foo') + st1 = workflow.add_status('Status1') + workflow.add_status('Status2') + st3 = workflow.add_status('Status3') + + item = SendmailWorkflowStatusItem() + item.to = ['_submitter'] + item.subject = 'bla' + st1.items.append(item) + item.parent = st1 + workflow.store() + + create_superuser(pub) + app = login(get_app(pub)) + + resp = app.get('/backoffice/workflows/%s/status/%s/' % (workflow.id, st1.id)) + resp = resp.click('Copy') + resp.form['status'] = 'Status3' + resp = resp.form.submit() + assert resp.location == 'http://example.net/backoffice/workflows/%s/status/%s/' % (workflow.id, st1.id) + + resp = app.get('/backoffice/workflows/%s/status/%s/' % (workflow.id, st3.id)) + resp = resp.click('Email') + assert resp.form['to$element0$choice'].value == '_submitter' + assert resp.form['subject'].value == 'bla' + + resp = app.get('/backoffice/workflows/%s/status/%s/' % (workflow.id, st3.id)) + resp = resp.click('Copy') + resp.form['status'] = 'Status1' + resp = resp.form.submit() + assert resp.location == 'http://example.net/backoffice/workflows/%s/status/%s/' % (workflow.id, st3.id) + + resp = app.get('/backoffice/workflows/%s/status/%s/' % (workflow.id, st1.id)) + assert len(resp.pyquery('#items-list li')) == 2 + assert 'items/1/' in resp.text + assert 'items/2/' in resp.text + + +def test_workflows_copy_status_item_create_document(pub): + create_superuser(pub) + Workflow.wipe() + + workflow = Workflow(name='foo') + st1 = workflow.add_status('Status1') + st2 = workflow.add_status('Status2') + workflow.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/workflows/%s/status/%s/' % (workflow.id, st1.id)) + + resp.forms[0]['action-formdata-action'] = 'Document Creation' + resp = resp.forms[0].submit() + resp = resp.follow() + + resp = resp.click('Document Creation') + resp.form['model_file$file'] = Upload('test.rtf', b'Model content') + resp = resp.form.submit('submit').follow().follow() + resp = resp.click('Document Creation') + resp_model_content = resp.click('test.rtf') + assert resp_model_content.body == b'Model content' + + resp = app.get('/backoffice/workflows/%s/status/%s/' % (workflow.id, st1.id)) + resp = resp.click('Copy') + resp.form['status'] = 'Status2' + resp = resp.form.submit() + + resp = app.get('/backoffice/workflows/%s/status/%s/' % (workflow.id, st2.id)) + resp = resp.click('Document Creation') + resp_model_content = resp.click('test.rtf') + assert resp_model_content.body == b'Model content' + + # modify file in initial status + resp = app.get('/backoffice/workflows/%s/status/%s/' % (workflow.id, st1.id)) + resp = resp.click('Document Creation') + resp.form['model_file$file'] = Upload('test2.rtf', b'Something else') + resp.form['model_file$orexisting'].checked = False + resp = resp.form.submit('submit').follow().follow() + + resp = resp.click('Document Creation') + resp_model_content = resp.click('test2.rtf') + assert resp_model_content.body == b'Something else' + + # check file is not changed in the copied item + resp = app.get('/backoffice/workflows/%s/status/%s/' % (workflow.id, st2.id)) + resp = resp.click('Document Creation') + resp_model_content = resp.click('test.rtf') + assert resp_model_content.body == b'Model content' + + def test_workflows_delete(pub): Workflow.wipe() workflow = Workflow(name='foo') diff --git a/tests/test_snapshots.py b/tests/test_snapshots.py index 6e7d2fb7c..3fe440287 100644 --- a/tests/test_snapshots.py +++ b/tests/test_snapshots.py @@ -867,6 +867,7 @@ def test_snaphost_workflow_status_item_comments(pub): Workflow.wipe() workflow = Workflow(name='test') workflow.add_status(name='baz') + workflow.add_status(name='hop') workflow.store() app = login(get_app(pub)) @@ -889,6 +890,11 @@ def test_snaphost_workflow_status_item_comments(pub): resp = resp.follow() resp = resp.follow() + resp = resp.click(href='items/1/copy') + resp.form['status'] = 'hop' + resp = resp.forms[0].submit('submit') + resp = resp.follow() + resp = resp.click(href='items/1/delete') resp = resp.form.submit('submit') @@ -899,6 +905,7 @@ def test_snaphost_workflow_status_item_comments(pub): ] assert comments == [ 'Deletion of action "Webservice (foo)" in status "baz"', + 'Copy of action "Webservice (foo)" from status "baz" to status "hop"', 'Change in action "Webservice (foo)" in status "baz"', 'Change in action "Webservice" in status "baz"', 'New action "Webservice" in status "baz"', diff --git a/wcs/admin/workflows.py b/wcs/admin/workflows.py index 7edf55a93..77ff1599d 100644 --- a/wcs/admin/workflows.py +++ b/wcs/admin/workflows.py @@ -14,6 +14,7 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, see . +import copy import io import json import textwrap @@ -373,7 +374,7 @@ class WorkflowUI: class WorkflowItemPage(Directory): - _q_exports = ['', 'delete'] + _q_exports = ['', 'delete', 'copy'] def __init__(self, workflow, parent, component, html_top): try: @@ -452,6 +453,45 @@ class WorkflowItemPage(Directory): ) return redirect('../../') + def copy(self): + form = Form(enctype='multipart/form-data') + destinations = [(x.id, x.name) for x in self.workflow.possible_status] + + form.add(SingleSelectWidget, 'status', title=_('Target status'), options=destinations) + + form.add_submit('copy', _('Copy')) + form.add_submit('cancel', _('Cancel')) + if form.get_widget('cancel').parse(): + return redirect('../../') + if not form.is_submitted() or form.has_errors(): + get_response().breadcrumb.append(('copy', _('Copy'))) + self.html_top(title=_('Copy Item')) + r = TemplateIO(html=True) + r += htmltext('

%s

') % _('Copy Item') + r += form.render() + return r.getvalue() + else: + status_id = form.get_widget('status').parse() + destination_status = self.workflow.get_status(status_id) + + item = self.item.export_to_xml('utf-8') + item_type = item.attrib['type'] + new_item = destination_status.append_item(item_type) + new_item.parent = destination_status + new_item.init_with_xml(item, 'utf-8') + + self.workflow.store( + comment=_( + 'Copy of action "%(description)s" from status "%(from_status)s" to status "%(destination_status)s"' + ) + % { + 'description': self.item.render_as_line(), + 'from_status': self.parent.name, + 'destination_status': destination_status.name, + } + ) + return redirect('../../') + def _q_lookup(self, component): t = self.item.q_admin_lookup(self.workflow, self.parent, component, self.html_top) if t: diff --git a/wcs/qommon/static/css/dc2/admin.scss b/wcs/qommon/static/css/dc2/admin.scss index ad630ed79..3433fca12 100644 --- a/wcs/qommon/static/css/dc2/admin.scss +++ b/wcs/qommon/static/css/dc2/admin.scss @@ -1,7 +1,7 @@ $primary-color: #386ede; $secondary-color: #00d6eb; $string-color: str-slice($primary-color + '', 2); -$actions: add, duplicate, edit, jump, remove; +$actions: add, duplicate, edit, jump, remove, copy; @mixin clearfix { &::after { @@ -2076,7 +2076,7 @@ div#side { // w.c.s. steps in backoffice submission &.view { margin-top: 2px; } - &.remove, &.add, &.edit, &.duplicate, &.jump { + &.remove, &.add, &.edit, &.duplicate, &.jump, &.copy { padding: 0; border: 0; background: transparent; diff --git a/wcs/templates/wcs/backoffice/workflow-status.html b/wcs/templates/wcs/backoffice/workflow-status.html index 2f1c4971f..1c7c7d4ae 100644 --- a/wcs/templates/wcs/backoffice/workflow-status.html +++ b/wcs/templates/wcs/backoffice/workflow-status.html @@ -37,6 +37,7 @@ {% endwith %} {% if not workflow.is_readonly %} {% trans "Edit" %} + {% trans "Copy" %} {% trans "Delete" %} {% endif %}

-- 2.30.2