0001-backoffice-list-related-forms-and-cards-in-inspect-v.patch
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 |
- |