Projet

Général

Profil

0001-workflows-add-live-conditions-to-workflow-form-actio.patch

Frédéric Péters, 04 juin 2019 08:53

Télécharger (28,5 ko)

Voir les différences:

Subject: [PATCH] workflows: add live conditions to workflow form action
 (#32960)

 tests/test_backoffice_pages.py | 113 +++++++++++++++++++++++++++++++++
 wcs/fields.py                  |  10 +--
 wcs/formdata.py                |  10 ++-
 wcs/formdef.py                 |  32 ++++++++++
 wcs/forms/common.py            |  70 +++++++++++++++++++-
 wcs/forms/root.py              |  60 +----------------
 wcs/wf/attachment.py           |   2 +-
 wcs/wf/export_to_model.py      |   2 +-
 wcs/wf/form.py                 |  25 +++++---
 wcs/wf/resubmit.py             |   2 +-
 wcs/workflows.py               |  61 ++++++++++--------
 11 files changed, 282 insertions(+), 105 deletions(-)
tests/test_backoffice_pages.py
3634 3634
    assert formdef.data_class().get(formdata.id).workflow_data == {
3635 3635
            'blah_var_str': 'blah', 'blah_var_radio': 'c', 'blah_var_radio_raw': 'c'}
3636 3636

  
3637
def test_backoffice_workflow_form_with_conditions(pub):
3638
    user = create_user(pub)
3639
    create_environment(pub)
3640

  
3641
    wf = Workflow.get_default_workflow()
3642
    wf.id = '2'
3643
    wf.store()
3644
    wf = Workflow.get(wf.id)
3645
    status = wf.get_status('new')
3646
    status.items = []
3647
    display_form = FormWorkflowStatusItem()
3648
    display_form.id = '_display_form'
3649
    display_form.by = [user.roles[0]]
3650
    display_form.varname = 'blah'
3651
    display_form.formdef = WorkflowFormFieldsFormDef(item=display_form)
3652
    display_form.formdef.fields = [
3653
            fields.StringField(id='1', label='Test', varname='str', type='string', required=True),
3654
            fields.StringField(id='2', label='Test2', varname='str2', type='string', required=True),
3655
    ]
3656
    status.items.append(display_form)
3657
    display_form.parent = status
3658

  
3659
    wf.store()
3660
    formdef = FormDef.get_by_urlname('form-title')
3661
    formdef.workflow_id = wf.id
3662
    formdef.fields[0].varname = 'plop'
3663
    formdef.store()
3664

  
3665
    for formdata in formdef.data_class().select():
3666
        if formdata.status == 'wf-new':
3667
            break
3668
    app = login(get_app(pub))
3669
    resp = app.get(formdata.get_url(backoffice=True))
3670
    assert 'f1' in resp.form.fields
3671
    assert 'f2' in resp.form.fields
3672

  
3673
    # check with static condition
3674
    display_form.formdef.fields = [
3675
            fields.StringField(id='1', label='Test', varname='str', type='string', required=True),
3676
            fields.StringField(id='2', label='Test2', varname='str2',
3677
                type='string', required=True,
3678
                condition={'type': 'django', 'value': '0'}),
3679
    ]
3680
    wf.store()
3681

  
3682
    resp = login(get_app(pub)).get(formdata.get_url(backoffice=True))
3683
    assert 'f1' in resp.form.fields
3684
    assert 'f2' not in resp.form.fields
3685

  
3686
    # check condition based on formdata
3687
    display_form.formdef.fields = [
3688
            fields.StringField(id='1', label='Test', varname='str', type='string', required=True),
3689
            fields.StringField(id='2', label='Test2', varname='str2',
3690
                type='string', required=True,
3691
                condition={'type': 'django', 'value': 'form_var_plop'}),
3692
    ]
3693
    wf.store()
3694

  
3695
    resp = login(get_app(pub)).get(formdata.get_url(backoffice=True))
3696
    assert 'f1' in resp.form.fields
3697
    assert 'f2' in resp.form.fields
3698

  
3699
    display_form.formdef.fields = [
3700
            fields.StringField(id='1', label='Test', varname='str', type='string', required=True),
3701
            fields.StringField(id='2', label='Test2', varname='str2',
3702
                type='string', required=True,
3703
                condition={'type': 'django', 'value': 'form_var_plop != "xxx"'}),
3704
    ]
3705
    wf.store()
3706

  
3707
    resp = login(get_app(pub)).get(formdata.get_url(backoffice=True))
3708
    assert 'f1' in resp.form.fields
3709
    assert 'f2' in resp.form.fields
3710

  
3711
    # check with live conditions
3712
    display_form.formdef.fields = [
3713
            fields.StringField(id='1', label='Test', varname='str', type='string', required=True),
3714
            fields.StringField(id='2', label='Test2', varname='str2',
3715
                type='string', required=True,
3716
                condition={'type': 'django', 'value': 'blah_var_str == "xxx"'}),
3717
    ]
3718
    wf.store()
3719

  
3720
    resp = login(get_app(pub)).get(formdata.get_url(backoffice=True))
3721
    assert 'f1' in resp.form.fields
3722
    assert 'f2' in resp.form.fields
3723
    assert resp.html.find('div', {'data-field-id': '1'}).attrs['data-live-source'] == 'true'
3724
    assert resp.html.find('div', {'data-field-id': '2'}).attrs.get('style') == 'display: none'
3725
    live_url = resp.html.find('form').attrs['data-live-url']
3726
    resp.form['f1'] = ''
3727
    live_resp = app.post(live_url, params=resp.form.submit_fields())
3728
    assert live_resp.json['result']['1']['visible']
3729
    assert not live_resp.json['result']['2']['visible']
3730

  
3731
    resp.form['f1'] = 'xxx'
3732
    live_resp = app.post(live_url, params=resp.form.submit_fields())
3733
    assert live_resp.json['result']['1']['visible']
3734
    assert live_resp.json['result']['2']['visible']
3735

  
3736
    # check submit doesn't work
3737
    resp = resp.form.submit('submit')
3738
    assert 'There were errors processing your form.' in resp.body
3739

  
3740
    resp.form['f1'] = 'xxx2'
3741
    live_resp = app.post(live_url, params=resp.form.submit_fields())
3742
    assert live_resp.json['result']['1']['visible']
3743
    assert not live_resp.json['result']['2']['visible']
3744

  
3745
    # check submit does work when second field is hidden
3746
    resp = resp.form.submit('submit').follow()
3747

  
3748
    assert formdef.data_class().get(formdata.id).workflow_data == {'blah_var_str': 'xxx2', 'blah_var_str2': None}
3749

  
3637 3750
def test_backoffice_criticality_in_formdef_listing(pub):
3638 3751
    if not pub.is_using_postgresql():
3639 3752
        pytest.skip('this requires SQL')
wcs/fields.py
403 403
        except RuntimeError:
404 404
            return True
405 405

  
406
    def get_referenced_varnames(self, value):
407
        return re.findall(r'\bform[_\.]var[_\.]([a-zA-Z0-9_]+?)(?:_raw|\b)', value or '')
406
    def get_referenced_varnames(self, formdef, value):
407
        return re.findall(r'\b%s[_\.]var[_\.]([a-zA-Z0-9_]+?)(?:_raw|\b)' % formdef.var_prefix, value or '')
408 408

  
409
    def get_condition_varnames(self):
410
        return self.get_referenced_varnames(self.condition['value'])
409
    def get_condition_varnames(self, formdef):
410
        return self.get_referenced_varnames(formdef, self.condition['value'])
411 411

  
412 412
    def has_live_conditions(self, formdef):
413
        varnames = self.get_condition_varnames()
413
        varnames = self.get_condition_varnames(formdef)
414 414
        if not varnames:
415 415
            return False
416 416
        field_position = formdef.fields.index(self)
wcs/formdata.py
525 525
            last_seen_author = evolution_part.who or last_seen_author
526 526
            yield evolution_part
527 527

  
528
    def get_workflow_form(self, user):
528
    def get_workflow_form(self, user, displayed_fields=None):
529 529
        wf_status = self.get_status()
530 530
        if not wf_status:
531 531
            return None
532
        return wf_status.get_action_form(self, user)
532
        return wf_status.get_action_form(self, user, displayed_fields=displayed_fields)
533 533

  
534 534
    def handle_workflow_form(self, user, form):
535 535
        wf_status = self.get_status()
......
537 537
            return None
538 538
        return wf_status.handle_form(form, self, user)
539 539

  
540
    def evaluate_live_workflow_form(self, user, form):
541
        wf_status = self.get_status()
542
        if not wf_status:
543
            return None
544
        wf_status.evaluate_live_form(form, self, user)
545

  
540 546
    def pop_previous_marked_status(self):
541 547
        if not self.workflow_data or not '_markers_stack' in self.workflow_data:
542 548
            return None
wcs/formdef.py
110 110
    # store fields in a separate pickle chunk
111 111
    lightweight = True
112 112

  
113
    # prefix for formdata variables
114
    var_prefix = 'form'
115

  
113 116
    # declarations for serialization
114 117
    TEXT_ATTRIBUTES = ['name', 'url_name', 'description', 'keywords',
115 118
            'publication_date', 'expiration_date', 'internal_identifier',
......
627 630

  
628 631
        return form
629 632

  
633
    def set_live_condition_sources(self, form, fields):
634
        live_condition_fields = {}
635
        for field in fields:
636
            if field.condition:
637
                field.varnames = field.get_condition_varnames(formdef=self)
638
                for varname in field.varnames:
639
                    if not varname in live_condition_fields:
640
                        live_condition_fields[varname] = []
641
                    live_condition_fields[varname].append(field)
642
            if field.key == 'item' and field.data_source:
643
                real_data_source = data_sources.get_real(field.data_source)
644
                if real_data_source.get('type') != 'json':
645
                    continue
646
                varnames = re.findall(r'\bform[_\.]var[_\.]([a-zA-Z0-9_]+?)(?:_raw|\b)',
647
                        real_data_source.get('value'))
648
                for varname in varnames:
649
                    if not varname in live_condition_fields:
650
                        live_condition_fields[varname] = []
651
                    live_condition_fields[varname].append(field)
652
            if field.key == 'comment':
653
                for varname in field.get_referenced_varnames(formdef=self, value=field.label):
654
                    if not varname in live_condition_fields:
655
                        live_condition_fields[varname] = []
656
                    live_condition_fields[varname].append(field)
657

  
658
        for field in fields:
659
            if field.varname in live_condition_fields:
660
                form.get_widget('f%s' % field.id).live_condition_source = True
661

  
630 662
    def get_field_data(self, field, widget):
631 663
        d = {}
632 664
        d[field.id] = widget.parse()
wcs/forms/common.py
21 21
from quixote.directory import Directory
22 22
from quixote.html import TemplateIO, htmltext
23 23

  
24
from wcs import data_sources
24 25
from wcs.api_utils import get_user_from_api_query_string, is_url_signed
25 26
from wcs.fields import WidgetField, FileField
26 27
from wcs.workflows import EditableWorkflowStatusItem
......
114 115

  
115 116

  
116 117
class FormStatusPage(Directory, FormTemplateMixin):
117
    _q_exports_orig = ['', 'download', 'json', 'action']
118
    _q_exports_orig = ['', 'download', 'json', 'action', 'live']
118 119
    _q_extra_exports = []
119 120
    form_page_class = None
120 121

  
......
469 470
        user = self.check_receiver()
470 471
        form = None
471 472

  
473
        submitted_fields = []
472 474
        try:
473
            form = self.filled.get_workflow_form(user)
475
            form = self.filled.get_workflow_form(user, displayed_fields=submitted_fields)
474 476
        except:
475 477
            # XXX: probably because there are mixed forms, with and without
476 478
            # workflow; send a trace nevertheless.
477 479
            get_publisher().notify_of_exception(sys.exc_info(), context='[BACKOFFICE]')
478 480
            form = Form()
479 481

  
480
        if form and form.is_submitted() and not form.has_errors():
482
        if form.is_submitted():
483
            with get_publisher().substitutions.temporary_feed(self.filled, force_mode='lazy'):
484
                # remove fields that could be required but are not visible
485
                self.filled.evaluate_live_workflow_form(user, form)
486
                get_publisher().substitutions.feed(self.filled)
487
                for field in submitted_fields:
488
                    if not field.is_visible(self.filled.data, self.formdef) and 'f%s' % field.id in form._names:
489
                        del form._names['f%s' % field.id]
490

  
491
        if form.is_submitted() and not form.has_errors():
481 492
            url = self.submit(form)
482 493
            get_session().unmark_visited_object(object_key)
483 494
            if url is None:
......
544 555
                    r += htmltext('</div>')
545 556
            if not visitors or me_in_visitors:
546 557
                r += htmltext(self.actions_workflow_messages())
558
                form.attrs['data-live-url'] = self.filled.get_url() + 'live'
547 559
                r += form.render()
548 560
                self.filled.mark_as_being_visited()
549 561

  
......
619 631
            file_url += file.base_filename
620 632
        return redirect(file_url)
621 633

  
634
    @classmethod
635
    def live_process_fields(cls, form, formdata, displayed_fields):
636
        result = {}
637
        for field in displayed_fields:
638
            result[field.id] = {'visible': field.is_visible(formdata.data, formdata.formdef)}
639

  
640
        modified_field_varname = None
641
        for field in displayed_fields:
642
            if field.id == get_request().form.get('modified_field_id'):
643
                modified_field_varname = field.varname
644

  
645
        for field in displayed_fields:
646
            if field.key == 'item' and field.data_source:
647
                data_source = data_sources.get_object(field.data_source)
648
                if data_source.type != 'json':
649
                    continue
650
                varnames = re.findall(r'\bform[_\.]var[_\.]([a-zA-Z0-9_]+?)(?:_raw|\b)',
651
                        data_source.data_source.get('value'))
652
                if (modified_field_varname is None or modified_field_varname in varnames) and (
653
                        field.display_mode == 'autocomplete' and data_source.query_parameter):
654
                    # computed earlier, in perform_more_widget_changes, when the field
655
                    # was added to the form
656
                    result[field.id]['source_url'] = field.url
657
                if modified_field_varname in varnames:
658
                    result[field.id]['items'] = [
659
                            {'id': x[2], 'text': x[1]} for x in field.get_options(mode='lazy')]
660
        for widget in form.widgets:
661
            if not getattr(widget, 'field', None):
662
                continue
663
            if widget.field.key == 'comment':
664
                result[widget.field.id]['content'] = widget.content
665

  
666
        return json.dumps({'result': result})
667

  
668
    def live(self):
669
        get_request().ignore_session = True
670
        # live evaluation of fields
671
        get_response().set_content_type('application/json')
672
        def result_error(reason):
673
            return json.dumps({'result': 'error', 'reason': reason})
674

  
675
        session = get_session()
676
        if not session:
677
            return result_error('missing session')
678

  
679
        displayed_fields = []
680
        user = get_request().user
681
        form = self.filled.get_workflow_form(user, displayed_fields=displayed_fields)
682
        self.filled.evaluate_live_workflow_form(user, form)
683
        get_publisher().substitutions.feed(self.filled)
684
        return self.live_process_fields(form, self.filled, displayed_fields)
685

  
622 686
    def _q_lookup(self, component):
623 687
        if component == 'files':
624 688
            self.check_receiver()
wcs/forms/root.py
386 386
                # always set additional attributes as they will be used for
387 387
                # "live prefill", regardless of existing data.
388 388
                form.get_widget('f%s' % field.id).prefill_attributes = field.get_prefill_attributes()
389
            if field.condition:
390
                field.varnames = field.get_condition_varnames()
391
                for varname in field.varnames:
392
                    if not varname in live_condition_fields:
393
                        live_condition_fields[varname] = []
394
                    live_condition_fields[varname].append(field)
395
            if field.key == 'item' and field.data_source:
396
                real_data_source = data_sources.get_real(field.data_source)
397
                if real_data_source.get('type') != 'json':
398
                    continue
399
                varnames = re.findall(r'\bform[_\.]var[_\.]([a-zA-Z0-9_]+?)(?:_raw|\b)',
400
                        real_data_source.get('value'))
401
                for varname in varnames:
402
                    if not varname in live_condition_fields:
403
                        live_condition_fields[varname] = []
404
                    live_condition_fields[varname].append(field)
405
            if field.key == 'comment':
406
                for varname in field.get_referenced_varnames(field.label):
407
                    if not varname in live_condition_fields:
408
                        live_condition_fields[varname] = []
409
                    live_condition_fields[varname].append(field)
410 389

  
411
        for field in displayed_fields:
412
            if field.varname in live_condition_fields:
413
                form.get_widget('f%s' % field.id).live_condition_source = True
390
        self.formdef.set_live_condition_sources(form, displayed_fields)
414 391

  
415 392
        self.html_top(self.formdef.name)
416 393

  
......
1105 1082
                    displayed_fields=displayed_fields,
1106 1083
                    transient_formdata=formdata)
1107 1084
        formdata.data.update(self.formdef.get_data(form))
1108

  
1109
        result = {}
1110
        for field in displayed_fields:
1111
            result[field.id] = {'visible': field.is_visible(formdata.data, self.formdef)}
1112

  
1113
        modified_field_varname = None
1114
        for field in displayed_fields:
1115
            if field.id == get_request().form.get('modified_field_id'):
1116
                modified_field_varname = field.varname
1117

  
1118
        for field in displayed_fields:
1119
            if field.key == 'item' and field.data_source:
1120
                data_source = data_sources.get_object(field.data_source)
1121
                if data_source.type != 'json':
1122
                    continue
1123
                varnames = re.findall(r'\bform[_\.]var[_\.]([a-zA-Z0-9_]+?)(?:_raw|\b)',
1124
                        data_source.data_source.get('value'))
1125
                if (modified_field_varname is None or modified_field_varname in varnames) and (
1126
                        field.display_mode == 'autocomplete' and data_source.query_parameter):
1127
                    # computed earlier, in perform_more_widget_changes, when the field
1128
                    # was added to the form
1129
                    result[field.id]['source_url'] = field.url
1130
                if modified_field_varname in varnames:
1131
                    result[field.id]['items'] = [
1132
                            {'id': x[2], 'text': x[1]} for x in field.get_options(mode='lazy')]
1133
        for widget in form.widgets:
1134
            if not getattr(widget, 'field', None):
1135
                continue
1136
            if widget.field.key == 'comment':
1137
                result[widget.field.id]['content'] = widget.content
1138

  
1139
        return json.dumps({'result': result})
1085
        return FormStatusPage.live_process_fields(form, formdata, displayed_fields)
1140 1086

  
1141 1087
    def submitted(self, form, existing_formdata = None):
1142 1088
        if existing_formdata: # modifying
......
1678 1624

  
1679 1625

  
1680 1626
class PublicFormStatusPage(FormStatusPage):
1681
    _q_exports_orig = ['', 'download', 'status']
1627
    _q_exports_orig = ['', 'download', 'status', 'live']
1682 1628
    form_page_class = FormPage
1683 1629
    history_templates = ['wcs/front/formdata_history.html', 'wcs/formdata_history.html']
1684 1630
    status_templates = ['wcs/front/formdata_status.html', 'wcs/formdata_status.html']
wcs/wf/attachment.py
100 100
        else:
101 101
            return _('not completed')
102 102

  
103
    def fill_form(self, form, formdata, user):
103
    def fill_form(self, form, formdata, user, **kwargs):
104 104
        if self.display_title:
105 105
            title = self.title or _('Upload File')
106 106
        else:
wcs/wf/export_to_model.py
207 207
        else:
208 208
            return _('no model set')
209 209

  
210
    def fill_form(self, form, formdata, user):
210
    def fill_form(self, form, formdata, user, **kwargs):
211 211
        if not self.method == 'interactive':
212 212
            return
213 213
        label = self.label
wcs/wf/form.py
56 56

  
57 57
class WorkflowFormFieldDefPage(FieldDefPage):
58 58
    section = 'workflows'
59
    blacklisted_attributes = ['condition', 'in_listing']
59
    blacklisted_attributes = ['in_listing']
60 60

  
61 61
    def get_deletion_extra_warning(self):
62 62
        return None
......
66 66
    section = 'workflows'
67 67
    support_import = False
68 68
    blacklisted_types = ['page']
69
    blacklisted_attributes = ['condition']
70 69
    field_def_page_class = WorkflowFormFieldDefPage
71 70

  
72 71

  
......
154 153
            return fields_directory
155 154
        return None
156 155

  
157
    def fill_form(self, form, formdata, user):
156
    def fill_form(self, form, formdata, user, displayed_fields=None, **kwargs):
158 157
        if not self.formdef:
159 158
            return
160
        self.formdef.add_fields_to_form(form)
159
        self.formdef.var_prefix = self.varname
160
        self.formdef.add_fields_to_form(form, displayed_fields=displayed_fields)
161 161
        form.add_submit('submit', _('Submit'))
162 162

  
163 163
        # put varname in a form attribute so it can be used in templates to
......
167 167
        formdata.feed_session()
168 168

  
169 169
        req = get_request()
170
        self.formdef.set_live_condition_sources(form, self.formdef.fields)
171

  
170 172
        for field in self.formdef.fields:
171 173
            if ('f%s' % field.id) in req.form:
172 174
                continue
......
187 189
                form.get_widget('f%s' % field.id).set_value(v)
188 190
                req.form['f%s' % field.id] = v
189 191

  
192
    def evaluate_live_form(self, form, formdata, user):
193
        workflow_data = {}
194
        for k, v in get_dict_with_varnames(
195
                        self.formdef.fields, self.formdef.get_data(form),
196
                        varnames_only=True).items():
197
            workflow_data['%s_%s' % (self.varname, k)] = v
198
        formdata.update_workflow_data(workflow_data)
199

  
190 200
    def submit_form(self, form, formdata, user, evo):
191 201
        if not self.formdef:
192 202
            return
193 203
        if form.get_submit() == 'submit' and not form.has_errors():
194
            workflow_data = {}
195
            for k, v in get_dict_with_varnames(
196
                            self.formdef.fields, self.formdef.get_data(form),
197
                            varnames_only=True).items():
198
                workflow_data['%s_%s' % (self.varname, k)] = v
199
            formdata.update_workflow_data(workflow_data)
204
            self.evaluate_live_form(form, formdata, user)
200 205
            formdata.store()
201 206

  
202 207
    def get_parameters_view(self):
wcs/wf/resubmit.py
46 46
        else:
47 47
            return _('not completed')
48 48

  
49
    def fill_form(self, form, formdata, user):
49
    def fill_form(self, form, formdata, user, **kwargs):
50 50
        label = self.label
51 51
        if not label:
52 52
            label = _('Resubmit')
wcs/workflows.py
1352 1352
                return item
1353 1353
        raise KeyError()
1354 1354

  
1355
    def get_action_form(self, filled, user):
1355
    def get_action_form(self, filled, user, displayed_fields=None):
1356 1356
        form = Form(enctype='multipart/form-data', use_tokens=False)
1357 1357
        form.attrs['id'] = 'wf-actions'
1358 1358
        for item in self.items:
......
1360 1360
                continue
1361 1361
            if not item.check_condition(filled):
1362 1362
                continue
1363
            item.fill_form(form, filled, user)
1363
            item.fill_form(form, filled, user, displayed_fields=displayed_fields)
1364 1364

  
1365 1365
        for action in filled.formdef.workflow.get_global_actions_for_user(filled, user):
1366 1366
            form.add_submit('button-action-%s' % action.id, action.name)
......
1372 1372
        else:
1373 1373
            return None
1374 1374

  
1375
    def handle_form(self, form, filled, user):
1376
        # check for global actions
1377
        for action in filled.formdef.workflow.get_global_actions_for_user(filled, user):
1378
            if 'button-action-%s' % action.id in get_request().form:
1379
                url = perform_items(action.items, filled)
1380
                if url:
1381
                    return url
1382
                return
1383

  
1384
        evo = Evolution()
1385
        evo.time = time.localtime()
1386
        if user:
1387
            if filled.is_submitter(user):
1388
                evo.who = '_submitter'
1389
            else:
1390
                evo.who = user.id
1391
        if not filled.evolution:
1392
            filled.evolution = []
1393

  
1375
    def get_active_items(self, form, filled, user):
1394 1376
        for item in self.items:
1395 1377
            if hasattr(item, 'by'):
1396 1378
                for role in item.by or []:
......
1410 1392
                    continue
1411 1393
            if not item.check_condition(filled):
1412 1394
                continue
1395
            yield item
1396

  
1397
    def evaluate_live_form(self, form, filled, user):
1398
        for item in self.get_active_items(form, filled, user):
1399
            item.evaluate_live_form(form, filled, user)
1400

  
1401
    def handle_form(self, form, filled, user):
1402
        # check for global actions
1403
        for action in filled.formdef.workflow.get_global_actions_for_user(filled, user):
1404
            if 'button-action-%s' % action.id in get_request().form:
1405
                url = perform_items(action.items, filled)
1406
                if url:
1407
                    return url
1408
                return
1409

  
1410
        evo = Evolution()
1411
        evo.time = time.localtime()
1412
        if user:
1413
            if filled.is_submitter(user):
1414
                evo.who = '_submitter'
1415
            else:
1416
                evo.who = user.id
1417
        if not filled.evolution:
1418
            filled.evolution = []
1419

  
1420
        for item in self.get_active_items(form, filled, user):
1413 1421
            next_url = item.submit_form(form, filled, user, evo)
1414 1422
            if next_url is True:
1415 1423
                break
......
1611 1619
    def perform(self, formdata):
1612 1620
        pass
1613 1621

  
1614
    def fill_form(self, form, formdata, user):
1622
    def fill_form(self, form, formdata, user, **kwargs):
1623
        pass
1624

  
1625
    def evaluate_live_form(self, form, formdata, user):
1615 1626
        pass
1616 1627

  
1617 1628
    def submit_form(self, form, formdata, user, evo):
......
2005 2016
        else:
2006 2017
            return _('not completed')
2007 2018

  
2008
    def fill_form(self, form, formdata, user):
2019
    def fill_form(self, form, formdata, user, **kwargs):
2009 2020
        if not 'comment' in [x.name for x in form.widgets]:
2010 2021
            if self.label is None:
2011 2022
                title = _('Comment')
......
2144 2155
        else:
2145 2156
            return _('not completed')
2146 2157

  
2147
    def fill_form(self, form, formdata, user):
2158
    def fill_form(self, form, formdata, user, **kwargs):
2148 2159
        label = self.compute(self.label)
2149 2160
        if not label:
2150 2161
            return
......
2727 2738
        else:
2728 2739
            return _('not completed')
2729 2740

  
2730
    def fill_form(self, form, formdata, user):
2741
    def fill_form(self, form, formdata, user, **kwargs):
2731 2742
        label = self.label
2732 2743
        if not label:
2733 2744
            label = _('Edit Form')
2734
-