Projet

Général

Profil

0001-admin-add-screen-when-overwriting-a-formdef-and-work.patch

Frédéric Péters, 24 novembre 2016 16:54

Télécharger (17,8 ko)

Voir les différences:

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(-)
tests/test_admin_pages.py
1303 1303
    user = create_superuser(pub)
1304 1304
    role = create_role()
1305 1305

  
1306
    Workflow.wipe()
1307
    workflow = Workflow(name='Workflow One')
1308
    workflow.possible_status = Workflow.get_default_workflow().possible_status
1309
    workflow.store()
1310

  
1306 1311
    FormDef.wipe()
1307 1312
    formdef = FormDef()
1308 1313
    formdef.name = 'form test'
1309 1314
    formdef.table_name = 'xxx'
1310 1315
    formdef.fields = [fields.StringField(id='1', label='1st field', type='string'),
1311 1316
            fields.StringField(id='2', label='2nd field', type='string')]
1317
    formdef.workflow_id = workflow.id
1312 1318
    formdef.store()
1313 1319

  
1314 1320
    formdata = formdef.data_class()()
......
1326 1332
    resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml)
1327 1333
    resp = resp.forms[0].submit()
1328 1334
    assert FormDef.get(formdef_id).fields[0].label == '1st modified field'
1335
    assert FormDef.get(formdef_id).workflow_id == workflow.id
1329 1336

  
1330 1337
    # check with added/removed field
1331 1338
    formdef = FormDef()
......
1333 1340
    formdef.fields = [
1334 1341
            fields.StringField(id='2', label='2nd field', type='string'),
1335 1342
            fields.StringField(id='3', label='3rd field', type='string')]
1343
    formdef.workflow_id = workflow.id
1336 1344
    formdef_xml = ET.tostring(formdef.export_to_xml(include_id=True))
1337 1345

  
1338 1346
    app = login(get_app(pub))
......
1342 1350
    resp = resp.forms[0].submit()
1343 1351
    assert 'The form removes and changes fields' in resp.body
1344 1352
    assert not 'The form has incompatible fields, it may cause data corruption and bugs' in resp.body
1353
    assert resp.form['workflow_id'].tag == 'input'
1354
    assert resp.form['workflow_id'].attrs['type'] == 'hidden'
1345 1355
    resp = resp.forms[0].submit()
1346 1356
    assert FormDef.get(formdef_id).fields[0].id == '2'
1347 1357
    assert FormDef.get(formdef_id).fields[0].label == '2nd field'
1348 1358
    assert FormDef.get(formdef_id).fields[1].id == '3'
1349 1359
    assert FormDef.get(formdef_id).fields[1].label == '3rd field'
1360
    assert FormDef.get(formdef_id).workflow_id == workflow.id
1350 1361

  
1351 1362
    # check with a field of different type
1352 1363
    formdef = FormDef()
......
1354 1365
    formdef.fields = [
1355 1366
            fields.StringField(id='2', label='2nd field', type='string'),
1356 1367
            fields.TextField(id='3', label='3rd field, text', type='text')]
1368
    formdef.workflow_id = workflow.id
1357 1369
    formdef_xml = ET.tostring(formdef.export_to_xml(include_id=True))
1358 1370

  
1359 1371
    app = login(get_app(pub))
......
1364 1376
    assert 'The form removes and changes fields' in resp.body
1365 1377
    assert 'The form has incompatible fields, it may cause data corruption and bugs' in resp.body
1366 1378
    resp.forms[0]['force'] = True
1379
    assert resp.form['workflow_id'].tag == 'input'
1380
    assert resp.form['workflow_id'].attrs['type'] == 'hidden'
1367 1381
    resp = resp.forms[0].submit()
1368 1382
    assert FormDef.get(formdef_id).fields[1].id == '3'
1369 1383
    assert FormDef.get(formdef_id).fields[1].label == '3rd field, text'
1370 1384
    assert FormDef.get(formdef_id).fields[1].type == 'text'
1385
    assert FormDef.get(formdef_id).workflow_id == workflow.id
1371 1386

  
1372 1387
    # check we kept stable references
1373 1388
    assert FormDef.get(formdef_id).url_name == 'form-test'
1374 1389
    assert FormDef.get(formdef_id).table_name == 'xxx'
1375 1390

  
1391
def test_form_overwrite_workflow_confirmation(pub):
1392
    user = create_superuser(pub)
1393
    role = create_role()
1394

  
1395
    Workflow.wipe()
1396
    workflow = Workflow(name='Workflow One')
1397
    workflow.possible_status = Workflow.get_default_workflow().possible_status
1398
    workflow.store()
1399

  
1400
    FormDef.wipe()
1401
    formdef = FormDef()
1402
    formdef.workflow = workflow
1403
    formdef.name = 'form test'
1404
    formdef.table_name = 'xxx'
1405
    formdef.fields = [fields.StringField(id='1', label='1st field', type='string'),
1406
            fields.StringField(id='2', label='2nd field', type='string')]
1407
    formdef.store()
1408

  
1409
    formdef_xml = ET.tostring(formdef.export_to_xml(include_id=True))
1410

  
1411
    workflow.remove_self()
1412
    workflow.id = 'xxx' # change workflow id
1413
    workflow.store()
1414
    formdef.workflow = workflow
1415
    formdef.store()
1416

  
1417
    app = login(get_app(pub))
1418
    resp = app.get('/backoffice/forms/%s/' % formdef.id)
1419
    resp = resp.click(href='overwrite')
1420
    resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml)
1421
    resp = resp.form.submit()
1422

  
1423
    # the workflow was different, there is a confirmation page checking for the
1424
    # workflow to use.
1425
    assert resp.form['workflow_id'].tag == 'select'
1426
    assert resp.form['workflow_id'].value == 'xxx' # old value by default
1427
    resp = resp.form.submit()
1428
    assert FormDef.get(formdef.id).workflow_id == 'xxx'
1429

  
1430

  
1376 1431
def test_form_comment_with_error_in_wscall(pub):
1377 1432
    create_superuser(pub)
1378 1433
    NamedWsCall.wipe()
wcs/admin/forms.py
835 835
        form.add(UrlWidget, 'url', title=_('Address'), required=False, size=50)
836 836
        form.add_hidden('new_formdef', required=False)
837 837
        form.add_hidden('force', required=False)
838
        form.add_hidden('workflow_id', required=False)
838 839
        form.add_submit('submit', _('Submit'))
839 840
        form.add_submit('cancel', _('Cancel'))
840 841
        if form.get_widget('cancel').parse():
......
900 901
        if form.get_widget('new_formdef').parse():
901 902
            # it's been through the summary page.
902 903
            if form.get_widget('force').parse():
904
                if form.get_widget('workflow_id').parse():
905
                    new_formdef.workflow_id = form.get_widget('workflow_id')
903 906
                # doing it!
904 907
                self.overwrite_by_formdef(new_formdef)
905 908
                return redirect('.')
......
921 924
            elif new_fields.get(field_id) != field_type:
922 925
                different_type_fields.append(field_id)
923 926

  
924
        if removed_fields or different_type_fields:
927
        # 3. compare workflow
928
        different_workflow = None
929
        if self.formdef.workflow.name != new_formdef.workflow.name:
930
            different_workflow = self.formdef.workflow
931

  
932
        if removed_fields or different_type_fields or different_workflow:
925 933
            return self.overwrite_warning_summary(new_formdef,
926
                    removed_fields, different_type_fields)
934
                    removed_fields, different_type_fields,
935
                    different_workflow)
927 936

  
928 937
        self.overwrite_by_formdef(new_formdef)
929 938
        return redirect('.')
......
935 944
        self.formdef = new_formdef
936 945
        self.formdef.store()
937 946

  
938
    def overwrite_warning_summary(self, new_formdef, removed_fields, different_type_fields):
947
    def overwrite_warning_summary(self, new_formdef, removed_fields,
948
            different_type_fields, different_workflow):
939 949
        self.html_top(title = _('Overwrite'))
940 950
        get_response().breadcrumb.append( ('overwrite', _('Overwrite')) )
941 951
        r = TemplateIO(html=True)
942 952

  
943
        r += htmltext('<h2>%s</h2>') % _('Overwrite')
944
        r += htmltext('<h3>%s</h3>') % _('Summary of changes')
945

  
946
        r += htmltext('<p>%s</p>') % _(
947
                'The form removes and changes fields, you should review the '
948
                'changes carefully.')
949

  
950
        current_fields_list = [str(x.id) for x in self.formdef.fields]
951
        new_fields_list = [str(x.id) for x in new_formdef.fields]
952

  
953
        current_fields = {}
954
        new_fields = {}
955
        for field in self.formdef.fields:
956
            current_fields[field.id] = field
957
        for field in new_formdef.fields:
958
            new_fields[field.id] = field
959

  
960
        r += htmltext('<div id="form-diff">')
961
        r += htmltext('<div>')
962
        r += htmltext('<table id="table-diff">')
963
        def ellipsize_html(field):
964
            return misc.ellipsize(field.unhtmled_label, 60)
965

  
966
        for diffinfo in difflib.ndiff(current_fields_list, new_fields_list):
967
            if diffinfo[0] == '?':
968
                # detail line, ignored
969
                continue
970
            field_id = diffinfo[2:].split()[0]
971
            if diffinfo[0] == ' ':
972
                # unchanged line
973
                label1 = ellipsize_html(current_fields.get(field_id))
974
                label2 = ellipsize_html(new_fields.get(field_id))
975
                if current_fields.get(field_id) and new_fields.get(field_id) and \
976
                        current_fields.get(field_id).type != new_fields.get(field_id).type:
977
                    r += htmltext('<tr class="type-change"><td class="indicator">!</td>')
978
                if current_fields.get(field_id) and new_fields.get(field_id) and \
979
                        ET.tostring(current_fields.get(field_id).export_to_xml('utf-8')) != \
980
                        ET.tostring(new_fields.get(field_id).export_to_xml('utf-8')):
981
                    r += htmltext('<tr class="modified-field"><td class="indicator">~</td>')
982
                else:
983
                    r += htmltext('<tr><td class="indicator"></td>')
984
                r += htmltext('<td>%s</td> <td>%s</td></tr>') % (label1, label2)
985
            elif diffinfo[0] == '-':
986
                # removed field
987
                label1 = ellipsize_html(current_fields.get(field_id))
988
                if current_fields.get(field_id) and new_fields.get(field_id) and \
989
                        current_fields.get(field_id).type != new_fields.get(field_id).type:
990
                    r += htmltext('<tr class="type-change"><td class="indicator">!</td>')
991
                else:
992
                    r += htmltext('<tr class="removed-field"><td class="indicator">-</td>')
993
                r += htmltext('<td>%s</td> <td></td></tr>') % label1
994
            elif diffinfo[0] == '+':
995
                # added field
996
                label2 = ellipsize_html(new_fields.get(field_id))
997
                if current_fields.get(field_id) and new_fields.get(field_id) and \
998
                        current_fields.get(field_id).type != new_fields.get(field_id).type:
999
                    r += htmltext('<tr class="type-change"><td class="indicator">!</td>')
1000
                else:
1001
                    r += htmltext('<tr class="added-field"><td class="indicator">+</td>')
1002
                r += htmltext('<td></td> <td>%s</td></tr>') % label2
1003

  
1004
        r += htmltext('</table>')
1005
        r += htmltext('</div>')
1006

  
1007
        r += htmltext('<div id="legend">')
1008
        r += htmltext('<table>')
1009
        r += htmltext('<tr class="added-field"><td class="indicator">+</td><td>%s</td></tr>') % (
1010
                _('Added field'))
1011
        r += htmltext('</table>')
1012
        r += htmltext('<table>')
1013
        r += htmltext('<tr class="removed-field"><td class="indicator">-</td><td>%s</td></tr>') % (
1014
                _('Removed field'))
1015
        r += htmltext('</table>')
1016
        r += htmltext('<table>')
1017
        r += htmltext('<tr class="modified-field"><td class="indicator">~</td><td>%s</td></tr>') % (
1018
                _('Modified field'))
1019
        r += htmltext('<table>')
1020
        r += htmltext('<tr class="type-change"><td class="indicator">!</td><td>%s</td></tr>') % (
1021
                _('Incompatible field'))
1022
        r += htmltext('</table>')
1023
        r += htmltext('</div>') # .legend
1024
        r += htmltext('</div>')
1025

  
1026 953
        get_request().method = 'GET'
1027 954
        get_request().form = {}
1028 955
        form = Form(enctype='multipart/form-data', use_tokens=False)
1029
        if different_type_fields:
1030
            form.widgets.append(HtmlWidget('<div class="errornotice"><p>%s</p></div>' % _(
1031
                'The form has incompatible fields, it may cause data corruption and bugs.')))
1032
            form.add(CheckboxWidget, 'force', title=_('Overwrite nevertheless'))
956

  
957
        r += htmltext('<h2>%s</h2>') % _('Overwrite')
958

  
959
        if removed_fields or different_type_fields:
960
            r += htmltext('<h3>%s</h3>') % _('Summary of changes')
961
            r += htmltext('<p>%s</p>') % _(
962
                    'The form removes and changes fields, you should review the '
963
                    'changes carefully.')
964

  
965
            current_fields_list = [str(x.id) for x in self.formdef.fields]
966
            new_fields_list = [str(x.id) for x in new_formdef.fields]
967

  
968
            current_fields = {}
969
            new_fields = {}
970
            for field in self.formdef.fields:
971
                current_fields[field.id] = field
972
            for field in new_formdef.fields:
973
                new_fields[field.id] = field
974

  
975
            r += htmltext('<div id="form-diff">')
976
            r += htmltext('<div>')
977
            r += htmltext('<table id="table-diff">')
978
            def ellipsize_html(field):
979
                return misc.ellipsize(field.unhtmled_label, 60)
980

  
981
            for diffinfo in difflib.ndiff(current_fields_list, new_fields_list):
982
                if diffinfo[0] == '?':
983
                    # detail line, ignored
984
                    continue
985
                field_id = diffinfo[2:].split()[0]
986
                if diffinfo[0] == ' ':
987
                    # unchanged line
988
                    label1 = ellipsize_html(current_fields.get(field_id))
989
                    label2 = ellipsize_html(new_fields.get(field_id))
990
                    if current_fields.get(field_id) and new_fields.get(field_id) and \
991
                            current_fields.get(field_id).type != new_fields.get(field_id).type:
992
                        r += htmltext('<tr class="type-change"><td class="indicator">!</td>')
993
                    if current_fields.get(field_id) and new_fields.get(field_id) and \
994
                            ET.tostring(current_fields.get(field_id).export_to_xml('utf-8')) != \
995
                            ET.tostring(new_fields.get(field_id).export_to_xml('utf-8')):
996
                        r += htmltext('<tr class="modified-field"><td class="indicator">~</td>')
997
                    else:
998
                        r += htmltext('<tr><td class="indicator"></td>')
999
                    r += htmltext('<td>%s</td> <td>%s</td></tr>') % (label1, label2)
1000
                elif diffinfo[0] == '-':
1001
                    # removed field
1002
                    label1 = ellipsize_html(current_fields.get(field_id))
1003
                    if current_fields.get(field_id) and new_fields.get(field_id) and \
1004
                            current_fields.get(field_id).type != new_fields.get(field_id).type:
1005
                        r += htmltext('<tr class="type-change"><td class="indicator">!</td>')
1006
                    else:
1007
                        r += htmltext('<tr class="removed-field"><td class="indicator">-</td>')
1008
                    r += htmltext('<td>%s</td> <td></td></tr>') % label1
1009
                elif diffinfo[0] == '+':
1010
                    # added field
1011
                    label2 = ellipsize_html(new_fields.get(field_id))
1012
                    if current_fields.get(field_id) and new_fields.get(field_id) and \
1013
                            current_fields.get(field_id).type != new_fields.get(field_id).type:
1014
                        r += htmltext('<tr class="type-change"><td class="indicator">!</td>')
1015
                    else:
1016
                        r += htmltext('<tr class="added-field"><td class="indicator">+</td>')
1017
                    r += htmltext('<td></td> <td>%s</td></tr>') % label2
1018

  
1019
            r += htmltext('</table>')
1020
            r += htmltext('</div>')
1021

  
1022
            r += htmltext('<div id="legend">')
1023
            r += htmltext('<table>')
1024
            r += htmltext('<tr class="added-field"><td class="indicator">+</td><td>%s</td></tr>') % (
1025
                    _('Added field'))
1026
            r += htmltext('</table>')
1027
            r += htmltext('<table>')
1028
            r += htmltext('<tr class="removed-field"><td class="indicator">-</td><td>%s</td></tr>') % (
1029
                    _('Removed field'))
1030
            r += htmltext('</table>')
1031
            r += htmltext('<table>')
1032
            r += htmltext('<tr class="modified-field"><td class="indicator">~</td><td>%s</td></tr>') % (
1033
                    _('Modified field'))
1034
            r += htmltext('<table>')
1035
            r += htmltext('<tr class="type-change"><td class="indicator">!</td><td>%s</td></tr>') % (
1036
                    _('Incompatible field'))
1037
            r += htmltext('</table>')
1038
            r += htmltext('</div>') # .legend
1039
            r += htmltext('</div>')
1040

  
1041
            if different_type_fields:
1042
                form.widgets.append(HtmlWidget('<div class="errornotice"><p>%s</p></div>' % _(
1043
                    'The form has incompatible fields, it may cause data corruption and bugs.')))
1044
                form.add(CheckboxWidget, 'force', title=_('Overwrite nevertheless'))
1045
            else:
1046
                form.add_hidden('force', 'ok')
1047

  
1048
        if different_workflow:
1049
            workflows = get_workflows(condition=lambda x: x.possible_status)
1050
            get_request().form['workflow_id'] = different_workflow.id
1051
            form.add(SingleSelectWidget, 'workflow_id',
1052
                    title=_('Workflow'),
1053
                    options=[(None, _('Default Workflow'), '')] + workflows)
1033 1054
        else:
1034
            form.add_hidden('force', 'ok')
1055
            form.add_hidden('workflow_id', '')
1056

  
1035 1057
        form.add_hidden('new_formdef', ET.tostring(new_formdef.export_to_xml(include_id=True)))
1036 1058
        form.add_submit('submit', _('Submit'))
1037 1059
        form.add_submit('cancel', _('Cancel'))
1038
-