Projet

Général

Profil

0001-backoffice-list-related-forms-and-cards-in-inspect-v.patch

Lauréline Guérin, 14 septembre 2020 17:54

Télécharger (18,7 ko)

Voir les différences:

Subject: [PATCH] backoffice: list related forms and cards in inspect view
 (#43359)

 tests/test_backoffice_pages.py | 215 ++++++++++++++++++++++++++++++++-
 wcs/backoffice/management.py   |  29 ++++-
 wcs/formdata.py                |  68 +++++++++++
 wcs/wf/external_workflow.py    |  32 +----
 4 files changed, 301 insertions(+), 43 deletions(-)
tests/test_backoffice_pages.py
3 3
import json
4 4
import os
5 5
import re
6
import shutil
7 6
import time
8
import hashlib
9 7
import random
10 8
import xml.etree.ElementTree as ET
11 9
import zipfile
......
18 16
except ImportError:
19 17
    xlwt = None
20 18

  
21
from django.utils import six
22 19
from django.utils.six import StringIO, BytesIO
23 20
from django.utils.six.moves.urllib import parse as urllib
24 21
from django.utils.six.moves.urllib import parse as urlparse
25 22

  
26 23
from webtest import Upload
27 24

  
28
from quixote import cleanup, get_publisher, get_response
25
from quixote import get_publisher
29 26
from quixote.http_request import Upload as QuixoteUpload
30 27
from wcs.qommon import ods
31 28
from wcs.api_utils import sign_url
32 29
from wcs.blocks import BlockDef
33
from wcs.qommon import errors, sessions
34 30
from wcs.qommon.form import PicklableUpload
35 31
from wcs.qommon.form import UploadedFile
36 32
from wcs.qommon.ident.password_accounts import PasswordAccount
37 33
from wcs.qommon.http_request import HTTPRequest
38
from wcs.qommon.substitution import CompatibilityNamesDict
39 34
from wcs.roles import Role, logged_users_role
40 35
from wcs.workflows import (Workflow, CommentableWorkflowStatusItem,
41 36
        ChoiceWorkflowStatusItem, EditableWorkflowStatusItem,
......
5417 5412
    assert 'Invalid block tag' in resp.text
5418 5413

  
5419 5414

  
5415
def test_inspect_page_with_related_objects(pub):
5416
    if not pub.is_using_postgresql():
5417
        pytest.skip('this requires SQL')
5418
        return
5419

  
5420
    user = create_user(pub, is_admin=True)
5421

  
5422
    FormDef.wipe()
5423
    CardDef.wipe()
5424

  
5425
    # test ExternalWorkflowGlobalAction
5426
    external_wf = Workflow(name='External Workflow')
5427
    st1 = external_wf.add_status(name='New')
5428
    action = external_wf.add_global_action('Delete', 'delete')
5429
    action.append_item('remove')
5430
    trigger = action.append_trigger('webservice')
5431
    trigger.identifier = 'delete'
5432
    external_wf.store()
5433

  
5434
    external_formdef = FormDef()
5435
    external_formdef.name = 'External Form'
5436
    external_formdef.fields = [
5437
        fields.StringField(id='0', label='string', varname='form_string'),
5438
    ]
5439
    external_formdef.workflow = external_wf
5440
    external_formdef.store()
5441

  
5442
    external_carddef = CardDef()
5443
    external_carddef.name = 'External Card'
5444
    external_carddef.fields = [
5445
        fields.StringField(id='0', label='string', varname='card_string'),
5446
    ]
5447
    external_carddef.backoffice_submission_roles = user.roles
5448
    external_carddef.workflow = external_wf
5449
    external_carddef.store()
5450

  
5451
    wf = Workflow(name='External actions')
5452
    st1 = wf.add_status('Create external formdata')
5453
    create_formdata = CreateFormdataWorkflowStatusItem()
5454
    create_formdata.label = 'create linked form'
5455
    create_formdata.formdef_slug = external_formdef.url_name
5456
    create_formdata.varname = 'created_form'
5457
    create_formdata.id = '_create_form'
5458
    mappings = [
5459
        Mapping(field_id='0', expression='{{ form_var_string }}')
5460
    ]
5461
    create_formdata.mappings = mappings
5462
    create_formdata.parent = st1
5463

  
5464
    create_carddata = CreateCarddataWorkflowStatusItem()
5465
    create_carddata.label = 'create linked card'
5466
    create_carddata.formdef_slug = external_carddef.url_name
5467
    create_carddata.varname = 'created_card'
5468
    create_carddata.id = '_create_card'
5469
    create_carddata.mappings = mappings
5470
    create_carddata.parent = st1
5471

  
5472
    st1.items.append(create_formdata)
5473
    st1.items.append(create_carddata)
5474

  
5475
    global_action = wf.add_global_action('Delete external linked object', 'delete')
5476
    action = global_action.append_item('external_workflow_global_action')
5477
    action.slug = 'formdef:%s' % external_formdef.url_name
5478
    action.trigger_id = 'action:%s' % trigger.identifier
5479
    wf.store()
5480

  
5481
    formdef = FormDef()
5482
    formdef.name = 'External action form'
5483
    formdef.fields = [
5484
        fields.StringField(id='0', label='string', varname='string'),
5485
    ]
5486
    formdef.workflow = wf
5487
    formdef.store()
5488

  
5489
    carddef = CardDef()
5490
    carddef.name = 'External action card'
5491
    carddef.fields = [
5492
        fields.StringField(id='0', label='string', varname='string'),
5493
    ]
5494
    carddef.backoffice_submission_roles = user.roles
5495
    carddef.workflow = wf
5496
    carddef.store()
5497

  
5498
    assert formdef.data_class().count() == 0
5499
    assert carddef.data_class().count() == 0
5500
    assert external_formdef.data_class().count() == 0
5501
    assert external_carddef.data_class().count() == 0
5502

  
5503
    formdata = formdef.data_class()()
5504
    formdata.data = {'0': 'test form'}
5505
    formdata.user = user
5506
    formdata.store()
5507
    formdata.just_created()
5508
    formdata.perform_workflow()
5509

  
5510
    assert formdef.data_class().count() == 1
5511
    assert carddef.data_class().count() == 0
5512
    # related form and card
5513
    assert external_formdef.data_class().count() == 1
5514
    assert external_carddef.data_class().count() == 1
5515

  
5516
    app = login(get_app(pub))
5517
    resp = app.get('/backoffice/management/external-action-form/1/inspect')
5518
    assert 'Related Forms/Cards' in resp.text
5519
    # related form and card
5520
    assert '<li><a href="http://example.net/backoffice/management/external-form/1/">External Form #1-1</a></li>' in resp.text
5521
    assert '<li><a href="http://example.net/backoffice/data/external-card/1/">External Card #1-1</a></li>' in resp.text
5522
    # check related form
5523
    resp = app.get('/backoffice/management/external-form/1/')
5524
    assert '<h3>Original form</h3><p><a href="http://example.net/backoffice/management/external-action-form/1/">External action form #2-1</a></p>' in resp.text
5525
    resp = app.get('/backoffice/management/external-form/1/inspect')
5526
    # parent
5527
    assert '<li><a href="http://example.net/backoffice/management/external-action-form/1/">External action form #2-1</a></li>' in resp.text
5528
    # check related card
5529
    resp = app.get('/backoffice/data/external-card/1/')
5530
    assert '<h3>Original form</h3><p><a href="http://example.net/backoffice/management/external-action-form/1/">External action form #2-1</a></p>' in resp.text
5531
    resp = app.get('/backoffice/data/external-card/1/inspect')
5532
    # parent
5533
    assert '<li><a href="http://example.net/backoffice/management/external-action-form/1/">External action form #2-1</a></li>' in resp.text
5534

  
5535
    formdef.data_class().wipe()
5536
    carddef.data_class().wipe()
5537
    external_formdef.data_class().wipe()
5538
    external_carddef.data_class().wipe()
5539

  
5540
    carddata = carddef.data_class()()
5541
    carddata.data = {'0': 'test card'}
5542
    carddata.user = user
5543
    carddata.store()
5544
    carddata.just_created()
5545
    carddata.perform_workflow()
5546

  
5547
    assert formdef.data_class().count() == 0
5548
    assert carddef.data_class().count() == 1
5549
    # related form and card
5550
    assert external_formdef.data_class().count() == 1
5551
    assert external_carddef.data_class().count() == 1
5552

  
5553
    resp = app.get('/backoffice/data/external-action-card/1/inspect')
5554
    assert 'Related Forms/Cards' in resp.text
5555
    # related form and card
5556
    assert '<li><a href="http://example.net/backoffice/management/external-form/2/">External Form #1-2</a></li>' in resp.text
5557
    assert '<li><a href="http://example.net/backoffice/data/external-card/2/">External Card #1-2</a></li>' in resp.text
5558
    # check related form
5559
    resp = app.get('/backoffice/management/external-form/2/')
5560
    assert '<h3>Original card</h3><p><a href="http://example.net/backoffice/data/external-action-card/1/">External action card #2-1</a></p>' in resp.text
5561
    resp = app.get('/backoffice/management/external-form/2/inspect')
5562
    # parent
5563
    assert '<li><a href="http://example.net/backoffice/data/external-action-card/1/">External action card #2-1</a></li>' in resp.text
5564
    # check related card
5565
    resp = app.get('/backoffice/data/external-card/2/')
5566
    assert '<h3>Original card</h3><p><a href="http://example.net/backoffice/data/external-action-card/1/">External action card #2-1</a></p>' in resp.text
5567
    resp = app.get('/backoffice/data/external-card/2/inspect')
5568
    # parent
5569
    assert '<li><a href="http://example.net/backoffice/data/external-action-card/1/">External action card #2-1</a></li>' in resp.text
5570

  
5571
    FormDef.wipe()
5572
    CardDef.wipe()
5573
    Workflow.wipe()
5574

  
5575
    # test linked Card in datasource
5576
    wf = Workflow(name='WF')
5577
    st1 = wf.add_status('NEW')
5578
    wf.store()
5579
    wfc = Workflow(name='WFC')
5580
    wfc.add_status('NEW')
5581
    wfc.store()
5582

  
5583
    carddef = CardDef()
5584
    carddef.name = 'CARD A'
5585
    carddef.fields = [
5586
        fields.StringField(id='0', label='string', varname='string'),
5587
    ]
5588
    carddef.backoffice_submission_roles = user.roles
5589
    carddef.workflow = wfc
5590
    carddef.store()
5591

  
5592
    datasource = {'type': 'carddef:%s' % carddef.url_name}
5593
    formdef = FormDef()
5594
    formdef.name = 'FORM A'
5595
    formdef.fields = [
5596
        fields.ItemField(
5597
            id='0', label='Card',
5598
            type='item', varname='card',
5599
            data_source=datasource),
5600
    ]
5601
    formdef.workflow = wf
5602
    formdef.store()
5603

  
5604
    carddata = carddef.data_class()()
5605
    carddata.data = {'0': 'Text'}
5606
    carddata.store()
5607

  
5608
    formdata = formdef.data_class()()
5609
    formdata.data = {'0': '1'}
5610
    formdata.store()
5611
    formdata.just_created()
5612
    formdata.perform_workflow()
5613

  
5614
    assert formdef.data_class().count() == 1
5615
    assert carddef.data_class().count() == 1
5616

  
5617
    resp = app.get('/backoffice/management/form-a/1/inspect')
5618
    assert 'Related Forms/Cards' in resp.text
5619
    # related card
5620
    assert '<li><a href="http://example.net/backoffice/data/card-a/1/">CARD A #1-1</a></li>' in resp.text
5621

  
5622

  
5420 5623
def test_workflow_jump_previous(pub):
5421 5624
    user = create_user(pub)
5422 5625
    create_environment(pub)
wcs/backoffice/management.py
2740 2740
            extra_context = formdata.submission_context or {}
2741 2741
            r += htmltext('<div class="extra-context">')
2742 2742
            if extra_context.get('orig_formdef_id'):
2743
                r += htmltext('<h3>%s</h3>') % _('Original form')
2743
                object_type = extra_context.get('orig_object_type', 'formdef')
2744
                if object_type == 'formdef':
2745
                    r += htmltext('<h3>%s</h3>') % _('Original form')
2746
                    object_class = FormDef
2747
                else:
2748
                    r += htmltext('<h3>%s</h3>') % _('Original card')
2749
                    object_class = CardDef
2744 2750
                try:
2745
                    orig_formdata = FormDef.get(extra_context.get('orig_formdef_id')
2746
                            ).data_class().get(extra_context.get('orig_formdata_id'))
2751
                    orig_formdata = object_class.get(
2752
                        extra_context.get('orig_formdef_id')
2753
                    ).data_class().get(extra_context.get('orig_formdata_id'))
2747 2754
                except KeyError:
2748 2755
                    r += htmltext('<p>%s</p>') % _('(deleted)')
2749 2756
                else:
2750
                    r += htmltext('<p><a href="%s">%s %s</a></p>') % (
2757
                    r += htmltext('<p><a href="%s">%s</a></p>') % (
2751 2758
                             orig_formdata.get_url(backoffice=True),
2752
                             orig_formdata.formdef.name,
2753
                             orig_formdata.get_display_id())
2759
                             orig_formdata.get_display_name())
2754 2760
            if formdata.submission_channel:
2755 2761
                r += htmltext('<h3>%s</h3>') % '%s: %s' % (
2756 2762
                        _('Channel'), formdata.get_submission_channel_label())
......
3141 3147
            r += htmltext('</ul>')
3142 3148
            r += htmltext('</div>')
3143 3149

  
3150
        children = list(self.filled.iter_target_datas())
3151
        if children:
3152
            r += htmltext('<div id="inspect-related" class="section">')
3153
            r += htmltext('<h2>%s</h2>') % _('Related Forms/Cards')
3154
            r += htmltext('<ul class="form-inspector biglist">')
3155
            for child in children:
3156
                r += htmltext('<li><a href="%s">%s</a></li>') % (
3157
                    child.get_url(backoffice=True), child.get_display_name())
3158
            r += htmltext('</ul>')
3159
            r += htmltext('</div>')
3160

  
3144 3161
        return r.getvalue()
3145 3162

  
3146 3163
    def inspect_tool(self):
wcs/formdata.py
1195 1195
            for part in evo.parts or []:
1196 1196
                yield part
1197 1197

  
1198
    def iter_target_datas(self, objectdef=None, object_type=None, status_item=None):
1199
        # objectdef, object_type and status_item are provided when called from a workflow action
1200
        from wcs.wf.create_formdata import LinkedFormdataEvolutionPart
1201
        from wcs.logged_errors import LoggedError
1202
        from .carddef import CardDef
1203
        from .formdef import FormDef
1204

  
1205
        parent = self.get_parent()
1206
        if parent and object_type:
1207
            # looking for a parent of a specific type (workflow action)
1208
            parent_identifier = '%s:%s' % (parent.formdef.xml_root_node, parent.formdef.url_name)
1209
            if parent_identifier == object_type:
1210
                yield parent
1211
        elif parent:
1212
            # looking for any parent (inspect page)
1213
            yield parent
1214

  
1215
        data_ids = []
1216
        # search linked objects in data sources
1217
        for field in self.get_formdef().get_all_fields():
1218
            linked_id = self.data.get(field.id)
1219
            if not linked_id:
1220
                continue
1221
            data_source = getattr(field, 'data_source', None)
1222
            if data_source and object_type:
1223
                # looking for a data_source of a specific type (workflow action)
1224
                if data_source['type'] == object_type:
1225
                    data_ids.append((data_source['type'], linked_id))
1226
            elif data_source:
1227
                # looking for any data_source (inspect page)
1228
                data_ids.append((data_source['type'], linked_id))
1229

  
1230
        # search in evolution
1231
        for part in self.iter_evolution_parts():
1232
            is_linked = isinstance(part, LinkedFormdataEvolutionPart)
1233
            part_identifier = '%s:%s' % (part.formdef.xml_root_node, part.formdef.url_name)
1234
            if is_linked and object_type:
1235
                # looking for an object of a specific type (workflow action)
1236
                if part_identifier == object_type:
1237
                    data_ids.append((part_identifier, part.formdata_id))
1238
            elif is_linked:
1239
                # looking for any object (inspect page)
1240
                data_ids.append((part_identifier, part.formdata_id))
1241

  
1242
        for (slug, target_id) in data_ids:
1243
            if object_type:
1244
                # workflow action
1245
                try:
1246
                    yield objectdef.data_class().get(target_id)
1247
                except KeyError as e:
1248
                    # use custom error message depending on target type
1249
                    LoggedError.record(_('Could not find linked "%(object_name)s" object by id %(object_id)s') % {
1250
                        'object_name': objectdef.name, 'object_id': target_id},
1251
                        formdata=self, status_item=self, exception=e)
1252
            else:
1253
                # inspect page
1254
                try:
1255
                    obj_type, slug = slug.split(':')
1256
                    if obj_type == 'formdef':
1257
                        obj_class = FormDef
1258
                    elif obj_type == 'carddef':
1259
                        obj_class = CardDef
1260
                    yield obj_class.get_by_urlname(slug).data_class().get(target_id)
1261
                except ValueError:
1262
                    pass
1263
                except KeyError:
1264
                    pass
1265

  
1198 1266
    def __getattr__(self, attr):
1199 1267
        try:
1200 1268
            return self.__dict__[attr]
wcs/wf/external_workflow.py
22 22
from wcs.logged_errors import LoggedError
23 23
from wcs.workflows import WorkflowStatusItem, perform_items, register_item_class
24 24
from wcs.workflows import WorkflowGlobalActionWebserviceTrigger, Workflow
25
from wcs.wf.create_formdata import LinkedFormdataEvolutionPart
26 25
from wcs.carddef import CardDef
27 26
from wcs.formdef import FormDef
28 27

  
......
115 114
        return _('not completed')
116 115

  
117 116
    def iter_target_datas(self, formdata, objectdef):
118
        parent = formdata.get_parent()
119
        if parent:
120
            parent_identifier = '%s:%s' % (parent.formdef.xml_root_node,
121
                    parent.formdef.url_name)
122
            if parent_identifier == self.slug:
123
                yield parent
124

  
125
        data_ids = []
126
        # search linked objects in data sources
127
        for field in formdata.get_formdef().get_all_fields():
128
            if getattr(field, 'data_source', None) and field.data_source['type'] == self.slug:
129
                linked_id = formdata.data.get(field.id)
130
                if linked_id:
131
                    data_ids.append(linked_id)
132

  
133
        # search in evolution
134
        for part in formdata.iter_evolution_parts():
135
            if isinstance(part, LinkedFormdataEvolutionPart):
136
                part_identifier = '%s:%s' % (part.formdef.xml_root_node, part.formdef.url_name)
137
                if part_identifier == self.slug:
138
                    data_ids.append(part.formdata_id)
139

  
140
        for target_id in data_ids:
141
            try:
142
                yield objectdef.data_class().get(target_id)
143
            except KeyError as e:
144
                # use custom error message depending on target type
145
                LoggedError.record(_('Could not find linked "%(object_name)s" object by id %(object_id)s') % {
146
                    'object_name': objectdef.name, 'object_id': target_id},
147
                    formdata=formdata, status_item=self, exception=e)
117
        yield from formdata.iter_target_datas(objectdef=objectdef, object_type=self.slug, status_item=self)
148 118

  
149 119
    def get_parameters(self):
150 120
        return ('slug', 'trigger_id', 'condition')
151
-