From e3780f06cff5911981492c6cf7969ca4279f4d54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Thu, 24 Nov 2016 16:53:33 +0100 Subject: [PATCH] admin: add screen when overwriting a formdef and workflows mismatches (#14076) --- tests/test_admin_pages.py | 55 +++++++++++++ wcs/admin/forms.py | 204 +++++++++++++++++++++++++--------------------- 2 files changed, 168 insertions(+), 91 deletions(-) diff --git a/tests/test_admin_pages.py b/tests/test_admin_pages.py index f53f527..823735a 100644 --- a/tests/test_admin_pages.py +++ b/tests/test_admin_pages.py @@ -1303,12 +1303,18 @@ def test_form_overwrite(pub): user = create_superuser(pub) role = create_role() + Workflow.wipe() + workflow = Workflow(name='Workflow One') + workflow.possible_status = Workflow.get_default_workflow().possible_status + workflow.store() + FormDef.wipe() formdef = FormDef() formdef.name = 'form test' formdef.table_name = 'xxx' formdef.fields = [fields.StringField(id='1', label='1st field', type='string'), fields.StringField(id='2', label='2nd field', type='string')] + formdef.workflow_id = workflow.id formdef.store() formdata = formdef.data_class()() @@ -1326,6 +1332,7 @@ def test_form_overwrite(pub): resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml) resp = resp.forms[0].submit() assert FormDef.get(formdef_id).fields[0].label == '1st modified field' + assert FormDef.get(formdef_id).workflow_id == workflow.id # check with added/removed field formdef = FormDef() @@ -1333,6 +1340,7 @@ def test_form_overwrite(pub): formdef.fields = [ fields.StringField(id='2', label='2nd field', type='string'), fields.StringField(id='3', label='3rd field', type='string')] + formdef.workflow_id = workflow.id formdef_xml = ET.tostring(formdef.export_to_xml(include_id=True)) app = login(get_app(pub)) @@ -1342,11 +1350,14 @@ def test_form_overwrite(pub): resp = resp.forms[0].submit() assert 'The form removes and changes fields' in resp.body assert not 'The form has incompatible fields, it may cause data corruption and bugs' in resp.body + assert resp.form['workflow_id'].tag == 'input' + assert resp.form['workflow_id'].attrs['type'] == 'hidden' resp = resp.forms[0].submit() assert FormDef.get(formdef_id).fields[0].id == '2' assert FormDef.get(formdef_id).fields[0].label == '2nd field' assert FormDef.get(formdef_id).fields[1].id == '3' assert FormDef.get(formdef_id).fields[1].label == '3rd field' + assert FormDef.get(formdef_id).workflow_id == workflow.id # check with a field of different type formdef = FormDef() @@ -1354,6 +1365,7 @@ def test_form_overwrite(pub): formdef.fields = [ fields.StringField(id='2', label='2nd field', type='string'), fields.TextField(id='3', label='3rd field, text', type='text')] + formdef.workflow_id = workflow.id formdef_xml = ET.tostring(formdef.export_to_xml(include_id=True)) app = login(get_app(pub)) @@ -1364,15 +1376,58 @@ def test_form_overwrite(pub): assert 'The form removes and changes fields' in resp.body assert 'The form has incompatible fields, it may cause data corruption and bugs' in resp.body resp.forms[0]['force'] = True + assert resp.form['workflow_id'].tag == 'input' + assert resp.form['workflow_id'].attrs['type'] == 'hidden' resp = resp.forms[0].submit() assert FormDef.get(formdef_id).fields[1].id == '3' assert FormDef.get(formdef_id).fields[1].label == '3rd field, text' assert FormDef.get(formdef_id).fields[1].type == 'text' + assert FormDef.get(formdef_id).workflow_id == workflow.id # check we kept stable references assert FormDef.get(formdef_id).url_name == 'form-test' assert FormDef.get(formdef_id).table_name == 'xxx' +def test_form_overwrite_workflow_confirmation(pub): + user = create_superuser(pub) + role = create_role() + + Workflow.wipe() + workflow = Workflow(name='Workflow One') + workflow.possible_status = Workflow.get_default_workflow().possible_status + workflow.store() + + FormDef.wipe() + formdef = FormDef() + formdef.workflow = workflow + formdef.name = 'form test' + formdef.table_name = 'xxx' + formdef.fields = [fields.StringField(id='1', label='1st field', type='string'), + fields.StringField(id='2', label='2nd field', type='string')] + formdef.store() + + formdef_xml = ET.tostring(formdef.export_to_xml(include_id=True)) + + workflow.remove_self() + workflow.id = 'xxx' # change workflow id + workflow.store() + formdef.workflow = workflow + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/%s/' % formdef.id) + resp = resp.click(href='overwrite') + resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml) + resp = resp.form.submit() + + # the workflow was different, there is a confirmation page checking for the + # workflow to use. + assert resp.form['workflow_id'].tag == 'select' + assert resp.form['workflow_id'].value == 'xxx' # old value by default + resp = resp.form.submit() + assert FormDef.get(formdef.id).workflow_id == 'xxx' + + def test_form_comment_with_error_in_wscall(pub): create_superuser(pub) NamedWsCall.wipe() diff --git a/wcs/admin/forms.py b/wcs/admin/forms.py index 617017b..c8e3019 100644 --- a/wcs/admin/forms.py +++ b/wcs/admin/forms.py @@ -835,6 +835,7 @@ class FormDefPage(Directory): form.add(UrlWidget, 'url', title=_('Address'), required=False, size=50) form.add_hidden('new_formdef', required=False) form.add_hidden('force', required=False) + form.add_hidden('workflow_id', required=False) form.add_submit('submit', _('Submit')) form.add_submit('cancel', _('Cancel')) if form.get_widget('cancel').parse(): @@ -900,6 +901,8 @@ class FormDefPage(Directory): if form.get_widget('new_formdef').parse(): # it's been through the summary page. if form.get_widget('force').parse(): + if form.get_widget('workflow_id').parse(): + new_formdef.workflow_id = form.get_widget('workflow_id') # doing it! self.overwrite_by_formdef(new_formdef) return redirect('.') @@ -921,9 +924,15 @@ class FormDefPage(Directory): elif new_fields.get(field_id) != field_type: different_type_fields.append(field_id) - if removed_fields or different_type_fields: + # 3. compare workflow + different_workflow = None + if self.formdef.workflow.name != new_formdef.workflow.name: + different_workflow = self.formdef.workflow + + if removed_fields or different_type_fields or different_workflow: return self.overwrite_warning_summary(new_formdef, - removed_fields, different_type_fields) + removed_fields, different_type_fields, + different_workflow) self.overwrite_by_formdef(new_formdef) return redirect('.') @@ -935,103 +944,116 @@ class FormDefPage(Directory): self.formdef = new_formdef self.formdef.store() - def overwrite_warning_summary(self, new_formdef, removed_fields, different_type_fields): + def overwrite_warning_summary(self, new_formdef, removed_fields, + different_type_fields, different_workflow): self.html_top(title = _('Overwrite')) get_response().breadcrumb.append( ('overwrite', _('Overwrite')) ) r = TemplateIO(html=True) - r += htmltext('

%s

') % _('Overwrite') - r += htmltext('

%s

') % _('Summary of changes') - - r += htmltext('

%s

') % _( - 'The form removes and changes fields, you should review the ' - 'changes carefully.') - - current_fields_list = [str(x.id) for x in self.formdef.fields] - new_fields_list = [str(x.id) for x in new_formdef.fields] - - current_fields = {} - new_fields = {} - for field in self.formdef.fields: - current_fields[field.id] = field - for field in new_formdef.fields: - new_fields[field.id] = field - - r += htmltext('
') - r += htmltext('
') - r += htmltext('') - def ellipsize_html(field): - return misc.ellipsize(field.unhtmled_label, 60) - - for diffinfo in difflib.ndiff(current_fields_list, new_fields_list): - if diffinfo[0] == '?': - # detail line, ignored - continue - field_id = diffinfo[2:].split()[0] - if diffinfo[0] == ' ': - # unchanged line - label1 = ellipsize_html(current_fields.get(field_id)) - label2 = ellipsize_html(new_fields.get(field_id)) - if current_fields.get(field_id) and new_fields.get(field_id) and \ - current_fields.get(field_id).type != new_fields.get(field_id).type: - r += htmltext('') - if current_fields.get(field_id) and new_fields.get(field_id) and \ - ET.tostring(current_fields.get(field_id).export_to_xml('utf-8')) != \ - ET.tostring(new_fields.get(field_id).export_to_xml('utf-8')): - r += htmltext('') - else: - r += htmltext('') - r += htmltext('') % (label1, label2) - elif diffinfo[0] == '-': - # removed field - label1 = ellipsize_html(current_fields.get(field_id)) - if current_fields.get(field_id) and new_fields.get(field_id) and \ - current_fields.get(field_id).type != new_fields.get(field_id).type: - r += htmltext('') - else: - r += htmltext('') - r += htmltext('') % label1 - elif diffinfo[0] == '+': - # added field - label2 = ellipsize_html(new_fields.get(field_id)) - if current_fields.get(field_id) and new_fields.get(field_id) and \ - current_fields.get(field_id).type != new_fields.get(field_id).type: - r += htmltext('') - else: - r += htmltext('') - r += htmltext('') % label2 - - r += htmltext('
!
~
%s %s
!
-%s
!
+ %s
') - r += htmltext('
') - - r += htmltext('
') - r += htmltext('') - r += htmltext('') % ( - _('Added field')) - r += htmltext('
+%s
') - r += htmltext('') - r += htmltext('') % ( - _('Removed field')) - r += htmltext('
-%s
') - r += htmltext('') - r += htmltext('') % ( - _('Modified field')) - r += htmltext('
~%s
') - r += htmltext('') % ( - _('Incompatible field')) - r += htmltext('
!%s
') - r += htmltext('
') # .legend - r += htmltext('
') - get_request().method = 'GET' get_request().form = {} form = Form(enctype='multipart/form-data', use_tokens=False) - if different_type_fields: - form.widgets.append(HtmlWidget('

%s

' % _( - 'The form has incompatible fields, it may cause data corruption and bugs.'))) - form.add(CheckboxWidget, 'force', title=_('Overwrite nevertheless')) + + r += htmltext('

%s

') % _('Overwrite') + + if removed_fields or different_type_fields: + r += htmltext('

%s

') % _('Summary of changes') + r += htmltext('

%s

') % _( + 'The form removes and changes fields, you should review the ' + 'changes carefully.') + + current_fields_list = [str(x.id) for x in self.formdef.fields] + new_fields_list = [str(x.id) for x in new_formdef.fields] + + current_fields = {} + new_fields = {} + for field in self.formdef.fields: + current_fields[field.id] = field + for field in new_formdef.fields: + new_fields[field.id] = field + + r += htmltext('
') + r += htmltext('
') + r += htmltext('') + def ellipsize_html(field): + return misc.ellipsize(field.unhtmled_label, 60) + + for diffinfo in difflib.ndiff(current_fields_list, new_fields_list): + if diffinfo[0] == '?': + # detail line, ignored + continue + field_id = diffinfo[2:].split()[0] + if diffinfo[0] == ' ': + # unchanged line + label1 = ellipsize_html(current_fields.get(field_id)) + label2 = ellipsize_html(new_fields.get(field_id)) + if current_fields.get(field_id) and new_fields.get(field_id) and \ + current_fields.get(field_id).type != new_fields.get(field_id).type: + r += htmltext('') + if current_fields.get(field_id) and new_fields.get(field_id) and \ + ET.tostring(current_fields.get(field_id).export_to_xml('utf-8')) != \ + ET.tostring(new_fields.get(field_id).export_to_xml('utf-8')): + r += htmltext('') + else: + r += htmltext('') + r += htmltext('') % (label1, label2) + elif diffinfo[0] == '-': + # removed field + label1 = ellipsize_html(current_fields.get(field_id)) + if current_fields.get(field_id) and new_fields.get(field_id) and \ + current_fields.get(field_id).type != new_fields.get(field_id).type: + r += htmltext('') + else: + r += htmltext('') + r += htmltext('') % label1 + elif diffinfo[0] == '+': + # added field + label2 = ellipsize_html(new_fields.get(field_id)) + if current_fields.get(field_id) and new_fields.get(field_id) and \ + current_fields.get(field_id).type != new_fields.get(field_id).type: + r += htmltext('') + else: + r += htmltext('') + r += htmltext('') % label2 + + r += htmltext('
!
~
%s %s
!
-%s
!
+ %s
') + r += htmltext('
') + + r += htmltext('
') + r += htmltext('') + r += htmltext('') % ( + _('Added field')) + r += htmltext('
+%s
') + r += htmltext('') + r += htmltext('') % ( + _('Removed field')) + r += htmltext('
-%s
') + r += htmltext('') + r += htmltext('') % ( + _('Modified field')) + r += htmltext('
~%s
') + r += htmltext('') % ( + _('Incompatible field')) + r += htmltext('
!%s
') + r += htmltext('
') # .legend + r += htmltext('
') + + if different_type_fields: + form.widgets.append(HtmlWidget('

%s

' % _( + 'The form has incompatible fields, it may cause data corruption and bugs.'))) + form.add(CheckboxWidget, 'force', title=_('Overwrite nevertheless')) + else: + form.add_hidden('force', 'ok') + + if different_workflow: + workflows = get_workflows(condition=lambda x: x.possible_status) + get_request().form['workflow_id'] = different_workflow.id + form.add(SingleSelectWidget, 'workflow_id', + title=_('Workflow'), + options=[(None, _('Default Workflow'), '')] + workflows) else: - form.add_hidden('force', 'ok') + form.add_hidden('workflow_id', '') + form.add_hidden('new_formdef', ET.tostring(new_formdef.export_to_xml(include_id=True))) form.add_submit('submit', _('Submit')) form.add_submit('cancel', _('Cancel')) -- 2.10.2