Projet

Général

Profil

0002-create_formdata-add-automatic-mapping-by-varnames-39.patch

Benjamin Dauvergne, 11 février 2020 18:45

Télécharger (9,48 ko)

Voir les différences:

Subject: [PATCH 2/2] create_formdata: add automatic mapping by varnames
 (#39656)

 tests/test_backoffice_pages.py | 82 +++++++++++++++++++++++++++++++++-
 wcs/wf/create_formdata.py      | 52 ++++++++++++++++++---
 2 files changed, 125 insertions(+), 9 deletions(-)
tests/test_backoffice_pages.py
5737 5737
    wf.store()
5738 5738
    source_formdef.workflow_id = wf.id
5739 5739
    source_formdef.store()
5740
    source_formdef.data_class().wipe()
5741
    target_formdef.data_class().wipe()
5742
    LoggedError.wipe()
5740 5743
    return locals()
5741 5744

  
5742 5745

  
5743 5746
def test_backoffice_create_formdata_backoffice_submission(create_formdata):
5744
    create_formdata['source_formdef'].data_class().wipe()
5745
    create_formdata['target_formdef'].data_class().wipe()
5747
    # create submitting user
5748
    user = create_formdata['pub'].user_class()
5749
    user.name = 'Jean Darmette'
5750
    user.email = 'jean.darmette@triffouilis.fr'
5751
    user.store()
5752

  
5753
    # create source formdata
5754
    formdata = create_formdata['source_formdef'].data_class()()
5755
    upload = PicklableUpload('/foo/bar', content_type='text/plain')
5756
    upload.receive([b'hello world'])
5757
    formdata.data = {
5758
        '0': 'coucou',
5759
        '1': upload,
5760
    }
5761
    formdata.user = user
5762
    formdata.just_created()
5763
    formdata.store()
5764
    formdata.perform_workflow()
5765

  
5766
    # agent login and go to backoffice management pages
5767
    app = get_app(create_formdata['pub'])
5768
    app = login(app)
5769
    resp = app.get(create_formdata['source_formdef'].get_url(backoffice=True))
5770

  
5771
    # click on first available formdata
5772
    resp = resp.click(href='%s/' % formdata.id)
5773
    target_data_class = create_formdata['target_formdef'].data_class()
5774
    assert target_data_class.count() == 0
5775
    # resubmit it through backoffice submission
5776
    resp = resp.form.submit(name='button_resubmit')
5777
    assert LoggedError.count() == 0
5778
    assert target_data_class.count() == 1
5779
    target_formdata = target_data_class.select()[0]
5780

  
5781
    assert target_formdata.submission_context == {
5782
        'agent_id': str(create_formdata['admin'].id),
5783
        'orig_formdata_id': '1',
5784
        'orig_formdef_id': '1'
5785
    }
5786
    assert target_formdata.user.id == user.id
5787
    assert target_formdata.status == 'draft'
5788
    assert resp.location == 'http://example.net/backoffice/management/target-form/%s/' % target_formdata.id
5789
    resp = resp.follow()
5790
    assert resp.location == 'http://example.net/backoffice/submission/target-form/%s/' % target_formdata.id
5791
    resp = resp.follow()
5792
    # second redirect with magic-token
5793
    resp = resp.follow()
5794
    resp = resp.form.submit(name='submit')  # -> validation
5795
    resp = resp.form.submit(name='submit')  # -> submission
5796
    target_formdata = target_data_class.get(id=target_formdata.id)
5797
    assert target_formdata.user.id == user.id
5798
    assert target_formdata.status == 'wf-new'
5799
    resp = resp.follow()
5800
    pq = resp.pyquery.remove_namespaces()
5801
    assert pq('.field-type-string .value').text() == 'coucou'
5802
    assert pq('.field-type-file .value').text() == 'bar'
5803

  
5804

  
5805
def test_backoffice_create_formdata_map_fields_by_varname(create_formdata):
5806
    create_formdata['create_formdata'].map_fields_by_varname = True
5807
    create_formdata['create_formdata'].mappings  = []
5808
    create_formdata['wf'].store()
5809
    create_formdata['source_formdef'].fields = [
5810
        fields.StringField(id='0', label='string', varname='string0'),
5811
        fields.FileField(id='1', label='file', type='file', varname='file1'),
5812
        fields.StringField(id='2', label='string', varname='string2', required=False),
5813
        fields.FileField(id='3', label='file', type='file', varname='file3', required=False),
5814
    ]
5815
    create_formdata['source_formdef'].store()
5816
    create_formdata['target_formdef'].fields = [
5817
        fields.StringField(id='0', label='string', varname='string0'),
5818
        fields.FileField(id='1', label='file', type='file', varname='file1'),
5819
        fields.StringField(id='2', label='string', varname='string2', required=False),
5820
        fields.FileField(id='3', label='file', type='file', varname='file3', required=False),
5821
    ]
5822
    create_formdata['target_formdef'].store()
5746 5823

  
5747 5824
    # create submitting user
5748 5825
    user = create_formdata['pub'].user_class()
......
5774 5851
    assert target_data_class.count() == 0
5775 5852
    # resubmit it through backoffice submission
5776 5853
    resp = resp.form.submit(name='button_resubmit')
5854
    assert LoggedError.count() == 0
5777 5855
    assert target_data_class.count() == 1
5778 5856
    target_formdata = target_data_class.select()[0]
5779 5857

  
wcs/wf/create_formdata.py
18 18
import xml.etree.ElementTree as ET
19 19

  
20 20
from quixote import get_request, get_session, get_publisher
21
from quixote.html import htmltext
21 22

  
22 23
from django.utils.functional import cached_property
23 24

  
24 25
from wcs.qommon import _
25 26
from wcs.qommon.form import (WidgetListAsTable, CompositeWidget,
26 27
                             SingleSelectWidget, ComputedExpressionWidget,
27
                             CheckboxWidget, StringWidget, VarnameWidget)
28
                             CheckboxWidget, VarnameWidget, HtmlWidget)
28 29

  
29 30
from wcs.logged_errors import LoggedError
30 31
from wcs.workflows import WorkflowStatusItem, register_item_class
......
32 33

  
33 34

  
34 35
class Mapping(object):
36
    field_id = None
37
    expression = None
38

  
35 39
    def __init__(self, field_id, expression):
36 40
        self.field_id = field_id
37 41
        self.expression = expression
......
178 182
    keep_submission_context = False
179 183
    mappings = None
180 184
    varname = None
185
    map_fields_by_varname = False
181 186

  
182 187
    @classmethod
183 188
    def is_available(cls, workflow=None):
......
237 242
                     title=_('Identifier'), value=self.varname,
238 243
                     hint=_('This is used to get linked forms in expressions.'),
239 244
                     advanced=not(bool(self.varname)))
245
        if 'map_fields_by_varname' in parameters and self.formdef:
246
            form.add(CheckboxWidget, '%smap_fields_by_varname' % prefix,
247
                     title=_('Map fields by varname'),
248
                     value=self.map_fields_by_varname,
249
                     advanced=(
250
                         self.map_fields_by_varname == CreateFormdataWorkflowStatusItem.map_fields_by_varname))
251
            if self.map_fields_by_varname:
252
                common_varnames = [htmltext('<tt>%s</tt>') % varname for varname in self._common_varnames()]
253
                common_varnames = htmltext(', ').join(common_varnames)
254
                form.widgets.append(
255
                    HtmlWidget(
256
                        htmltext(
257
                            '<div class="infonotice">%s %s</div>') % (_('Common varnames:'), common_varnames)))
258

  
259
    def _common_varnames(self):
260
        '''Compute common varnames between the targeted formdef and all formdefs related to the parent workflow.'''
261
        assert self.formdef
262
        varnames = set(field.varname
263
                       for formdef in self.parent.parent.formdefs()
264
                       for field in formdef.get_widget_fields() if field.varname)
265
        return sorted(varnames & set(field.varname for field in self.formdef.get_widget_fields() if field.varname))
240 266

  
241 267
    def submit_admin_form(self, form):
242 268
        self.mappings = []
243 269
        super(CreateFormdataWorkflowStatusItem, self).submit_admin_form(form)
244 270

  
245 271
    def get_parameters(self):
246
        return ('formdef_slug', 'mappings', 'draft', 'backoffice_submission',
272
        return ('formdef_slug', 'map_fields_by_varname', 'mappings', 'draft', 'backoffice_submission',
247 273
                'keep_user', 'keep_submission_context', 'varname')
248 274

  
249 275
    def perform(self, formdata):
......
292 318
        formdata.store()
293 319

  
294 320
    def apply_mappings(self, dest, src):
295
        if not self.mappings:
296
            return
297

  
298
        # field.id can be serialized to xml, so we must alwat convert them to str when matching
321
        if self.map_fields_by_varname:
322
            fields_by_varname = {field.varname: field for field in self.formdef.get_widget_fields() if field.varname}
323
            for field in src.formdef.get_widget_fields():
324
                dest_field = fields_by_varname.get(field.varname)
325
                if dest_field is None:
326
                    continue
327
                try:
328
                    self._set_value(
329
                        formdata=dest,
330
                        field=dest_field,
331
                        value=src.data.get(field.id))
332
                except Exception as e:
333
                    LoggedError.record('Could copy field by varname for %s' % field.varname,
334
                                       formdata=src, status_item=self, exception=e)
335

  
336
        # field.id can be serialized to xml, so we must always convert them to
337
        # str when matching
299 338
        to_id_fields = {str(field.id): field for field in self.formdef.get_widget_fields()}
300

  
301 339
        missing_fields = []
302 340

  
303 341
        for mapping in self.mappings:
304
-