Projet

Général

Profil

0001-workflows-report-labels-of-deleted-fields-in-create-.patch

Frédéric Péters, 29 avril 2022 14:55

Télécharger (7,99 ko)

Voir les différences:

Subject: [PATCH] workflows: report labels of deleted fields in create
 form/card action (#60696)

 tests/admin_pages/test_workflow.py | 49 ++++++++++++++++++++++++++++++
 tests/workflow/test_formdata.py    | 17 ++++++++++-
 wcs/wf/create_formdata.py          | 27 ++++++++++++++--
 3 files changed, 89 insertions(+), 4 deletions(-)
tests/admin_pages/test_workflow.py
2731 2731
    assert "syntax error: Could not parse the remainder: '{{' from '{{'" in resp
2732 2732

  
2733 2733

  
2734
def test_workflows_create_formdata_deleted_field(pub):
2735
    create_superuser(pub)
2736

  
2737
    FormDef.wipe()
2738
    target_formdef = FormDef()
2739
    target_formdef.name = 'target form'
2740
    target_formdef.enable_tracking_codes = True
2741
    target_formdef.fields = [
2742
        fields.StringField(id='0', label='string1', varname='foo'),
2743
        fields.StringField(id='1', label='string2', varname='bar'),
2744
    ]
2745
    target_formdef.store()
2746

  
2747
    Workflow.wipe()
2748
    wf = Workflow(name='create-formdata')
2749

  
2750
    st2 = wf.add_status('Resubmit')
2751

  
2752
    create_formdata = CreateFormdataWorkflowStatusItem()
2753
    create_formdata.id = '_create_formdata'
2754
    create_formdata.formdef_slug = target_formdef.url_name
2755
    create_formdata.mappings = [
2756
        Mapping(field_id='0', expression='{{ "a" }}'),
2757
        Mapping(field_id='1', expression='{{ "b" }}'),
2758
    ]
2759
    create_formdata.parent = st2
2760
    st2.items.append(create_formdata)
2761

  
2762
    wf.store()
2763

  
2764
    app = login(get_app(pub))
2765
    # edit/submit to get field labels into cache
2766
    resp = app.get('/backoffice/workflows/%s/status/%s/items/_create_formdata/' % (wf.id, st2.id))
2767
    resp = resp.form.submit(name='submit')
2768

  
2769
    # remove field
2770
    target_formdef.fields = [
2771
        fields.StringField(id='1', label='string2', varname='bar'),
2772
    ]
2773
    target_formdef.store()
2774

  
2775
    resp = app.get('/backoffice/workflows/%s/status/%s/items/_create_formdata/' % (wf.id, st2.id))
2776
    assert resp.form['mappings$element1$field_id'].options == [
2777
        ('', False, '---'),
2778
        ('1', False, 'string2'),
2779
        ('0', True, '❗ string1 (deleted field)'),
2780
    ]
2781

  
2782

  
2734 2783
def test_workflows_create_carddata_action_config(pub):
2735 2784
    create_superuser(pub)
2736 2785

  
tests/workflow/test_formdata.py
106 106
        errors = two_pubs.loggederror_class.select()
107 107
        assert len(errors) == 2
108 108
        assert 'form_var_toto_string' in errors[0].exception_message
109
        assert 'Missing field' in errors[1].summary
109
        assert errors[1].summary == 'Missing field: unknown (1), unknown (2)'
110 110
        assert errors[0].formdata_id == str(target_formdef.data_class().select()[0].id)
111 111
        assert errors[1].formdata_id == str(target_formdef.data_class().select()[0].id)
112 112

  
113
    if two_pubs.is_using_postgresql():
114
        # add field labels cache
115
        two_pubs.loggederror_class.wipe()
116
        target_formdef.data_class().wipe()
117
        create.formdef_slug = target_formdef.url_name
118
        create.cached_field_labels = {'0': 'field0', '1': 'field1', '2': 'field2'}
119
        wf.store()
120
        del source_formdef._workflow
121
        formdata.perform_workflow()
122
        assert target_formdef.data_class().count() == 1
123

  
124
        errors = two_pubs.loggederror_class.select()
125
        assert len(errors) == 2
126
        assert errors[1].summary == 'Missing field: field1, field2'
127

  
113 128
    # no tracking code has been created
114 129
    created_formdata = target_formdef.data_class().select()[0]
115 130
    assert created_formdata.tracking_code is None
wcs/wf/create_formdata.py
22 22
from quixote.html import htmltext
23 23

  
24 24
from wcs.formdef import FormDef
25
from wcs.qommon import _
25
from wcs.qommon import _, ngettext
26 26
from wcs.qommon.form import (
27 27
    CheckboxWidget,
28 28
    CompositeWidget,
......
48 48

  
49 49

  
50 50
class MappingWidget(CompositeWidget):
51
    def __init__(self, name, value=None, to_formdef=None, **kwargs):
51
    def __init__(self, name, value=None, to_formdef=None, cached_field_labels=None, **kwargs):
52 52
        value = value or Mapping(None, '')
53 53
        self.accept_empty_value = kwargs.pop('accept_empty_value', False)
54 54
        super().__init__(name, value, **kwargs)
55 55

  
56 56
        to_fields = self._fields_to_options(to_formdef)
57 57

  
58
        if value and value.field_id not in [x[0] for x in to_fields]:
59
            old_label = (cached_field_labels or {}).get(value.field_id) or _('Unknown')
60
            error_option = '❗ %s (%s)' % (old_label, _('deleted field'))
61
            to_fields.append((value.field_id, error_option, value.field_id))
58 62
        self.add(
59 63
            SingleSelectWidget, name='field_id', title=_('Field'), value=value.field_id, options=to_fields
60 64
        )
......
101 105
            value.sort(key=lambda mapping: self.ranks.get(str(mapping.field_id), 9999))
102 106

  
103 107
        accept_empty_value = kwargs.pop('accept_empty_value', False)
108
        cached_field_labels = kwargs.pop('cached_field_labels', None)
104 109
        super().__init__(
105 110
            name,
106 111
            element_type=MappingWidget,
107 112
            element_kwargs={
108 113
                'to_formdef': to_formdef,
109 114
                'accept_empty_value': accept_empty_value,
115
                'cached_field_labels': cached_field_labels,
110 116
            },
111 117
            **kwargs,
112 118
        )
......
312 318
    varname = None
313 319
    map_fields_by_varname = False
314 320
    attach_to_history = False
321
    cached_field_labels = None
315 322

  
316 323
    def migrate(self):
317 324
        changed = super().migrate()
......
404 411
                accept_empty_value=self.accept_empty_value,
405 412
                to_formdef=formdef,
406 413
                value=self.mappings,
414
                cached_field_labels=self.cached_field_labels,
407 415
            )
408 416
            if form.is_submitted() and get_request().form.get('map_fields_by_varname') != 'yes':
409 417
                # do not validate form if formdef is changed and there is no mappings
......
453 461
        else:
454 462
            form.ERROR_NOTICE = Form.ERROR_NOTICE
455 463

  
464
    def submit_admin_form(self, form):
465
        super().submit_admin_form(form)
466
        # keep a cache of field labels, to be used in case of errors if fields are removed
467
        mapped_field_ids = [x.field_id for x in self.mappings or []]
468
        if self.formdef:
469
            self.cached_field_labels = {
470
                x.id: x.label for x in self.formdef.get_widget_fields() if x.id in mapped_field_ids
471
            }
472

  
456 473
    def get_mappings_parameter_view_value(self):
457 474
        to_id_fields = {str(field.id): field for field in self.formdef.get_widget_fields()}
458 475
        result = []
......
661 678
                )
662 679

  
663 680
        if missing_fields:
664
            summary = _('Missing field %r') % missing_fields
681
            labels = [(self.cached_field_labels or {}).get(x, 'unknown (%s)' % x) for x in missing_fields]
682
            summary = '%s %s' % (
683
                ngettext('Missing field:', 'Missing fields:', len(labels)),
684
                ', '.join(sorted(labels)),
685
            )
665 686
            get_publisher().record_error(summary, formdata=src, status_item=self)
666 687

  
667 688
    def _set_value(self, formdata, field, value):
668
-