0003-backoffice-formdata-display-fields-in-block-field-46.patch
tests/backoffice_pages/test_columns.py | ||
---|---|---|
423 | 423 | |
424 | 424 | |
425 | 425 |
def test_backoffice_block_columns(pub): |
426 |
if not pub.is_using_postgresql(): |
|
427 |
pytest.skip('this requires SQL') |
|
428 |
return |
|
429 | ||
426 | 430 |
pub.user_class.wipe() |
427 | 431 |
create_superuser(pub) |
428 | 432 |
pub.role_class.wipe() |
429 | 433 |
role = pub.role_class(name='test') |
430 | 434 |
role.store() |
431 | 435 | |
436 |
CardDef.wipe() |
|
437 |
carddef = CardDef() |
|
438 |
carddef.name = 'foo' |
|
439 |
carddef.fields = [ |
|
440 |
fields.StringField(id='1', label='First Name', type='string', varname='first_name'), |
|
441 |
fields.StringField(id='2', label='Last Name', type='string', varname='last_name'), |
|
442 |
] |
|
443 |
carddef.digest_templates = {'default': '{{ form_var_first_name }} {{ form_var_last_name }}'} |
|
444 |
carddef.store() |
|
445 |
carddef.data_class().wipe() |
|
446 |
card = carddef.data_class()() |
|
447 |
card.data = { |
|
448 |
'1': 'Foo', |
|
449 |
'2': 'Bar', |
|
450 |
} |
|
451 |
card.store() |
|
452 | ||
432 | 453 |
BlockDef.wipe() |
433 | 454 |
block = BlockDef() |
434 | 455 |
block.name = 'foobar' |
435 | 456 |
block.fields = [ |
436 | 457 |
fields.StringField(id='123', required=True, label='Test', type='string'), |
458 |
fields.ItemField(id='456', label='card field', type='item', data_source={'type': 'carddef:foo'}), |
|
437 | 459 |
] |
438 | 460 |
block.store() |
439 | 461 | |
... | ... | |
446 | 468 |
formdef.workflow_roles = {'_receiver': role.id} |
447 | 469 |
formdef.store() |
448 | 470 | |
471 |
data_class = formdef.data_class() |
|
472 |
data_class.wipe() |
|
473 | ||
474 |
formdata = data_class() |
|
475 |
formdata.data = { |
|
476 |
'8': { |
|
477 |
'data': [{'123': 'blah', '456': card.id, '456_display': card.default_digest}], |
|
478 |
'schema': {}, # not important here |
|
479 |
}, |
|
480 |
'8_display': 'blah', |
|
481 |
} |
|
482 |
formdata.just_created() |
|
483 |
formdata.jump_status('new') |
|
484 |
formdata.store() |
|
485 | ||
449 | 486 |
app = login(get_app(pub)) |
450 | 487 |
resp = app.get('/backoffice/management/form-title/') |
451 |
# check Block / Test is not part of the possible columns |
|
452 | 488 |
assert [x.text_content() for x in resp.pyquery('#columns-filter label')] == [ |
453 | 489 |
'Number', |
454 | 490 |
'Created', |
... | ... | |
456 | 492 |
'User Label', |
457 | 493 |
'Status', |
458 | 494 |
'Block', |
495 |
'Block / Test', |
|
496 |
'Block / card field', |
|
459 | 497 |
'Anonymised', |
460 | 498 |
] |
499 |
resp.forms['listing-settings']['8-123'].checked = True |
|
500 |
resp.forms['listing-settings']['8-456'].checked = True |
|
501 |
resp = resp.forms['listing-settings'].submit() |
|
502 |
assert '<th><span>Block / Test</span></th>' in resp |
|
503 |
assert '<th><span>Block / card field</span></th>' in resp |
|
504 |
assert resp.text.count('<tr') == 2 |
|
505 |
assert '<td>blah</td>' in resp |
|
506 |
assert '<td>Foo Bar</td>' in resp |
tests/backoffice_pages/test_filters.py | ||
---|---|---|
980 | 980 | |
981 | 981 |
app = login(get_app(pub)) |
982 | 982 |
resp = app.get('/backoffice/management/form-title/') |
983 |
assert '<label><input type="checkbox" name="1"/>Block Data / String</label>' not in resp
|
|
984 |
assert '<label><input type="checkbox" name="2"/>Block Data / Item</label>' not in resp
|
|
985 |
assert '<label><input type="checkbox" name="3"/>Block Data / Bool</label>' not in resp
|
|
986 |
assert '<label><input type="checkbox" name="4"/>Block Data / Date</label>' not in resp
|
|
987 |
assert '<label><input type="checkbox" name="5"/>Block Data / Email</label>' not in resp
|
|
983 |
assert '<label><input type="checkbox" name="0-1"/>Block Data / String</label>' in resp
|
|
984 |
assert '<label><input type="checkbox" name="0-2"/>Block Data / Item</label>' in resp
|
|
985 |
assert '<label><input type="checkbox" name="0-3"/>Block Data / Bool</label>' in resp
|
|
986 |
assert '<label><input type="checkbox" name="0-4"/>Block Data / Date</label>' in resp
|
|
987 |
assert '<label><input type="checkbox" name="0-5"/>Block Data / Email</label>' in resp
|
|
988 | 988 | |
989 | 989 |
# string |
990 | 990 |
resp = app.get('/backoffice/management/form-title/') |
wcs/backoffice/management.py | ||
---|---|---|
993 | 993 |
get_request().is_json_marker = True |
994 | 994 |
field_id = get_request().form.get('filter_field_id') |
995 | 995 |
for filter_field in self.get_formdef_fields(): |
996 |
is_in_block_field = getattr(filter_field, 'block_field', None) |
|
997 |
filter_field.contextual_id = filter_field.id |
|
998 |
if is_in_block_field: |
|
999 |
filter_field.contextual_id = '%s-%s' % (filter_field.block_field.id, filter_field.id) |
|
1000 | 996 |
if filter_field.contextual_id == field_id: |
1001 | 997 |
break |
1002 | 998 |
else: |
... | ... | |
1054 | 1050 |
continue |
1055 | 1051 |
filter_fields.append(field) |
1056 | 1052 | |
1057 |
# add contextual_id/contextual_varname attributes |
|
1058 |
# they are id/varname for normal fields |
|
1059 |
# but in case of blocks they are concatenation of block id/varname + field id/varname |
|
1060 |
is_in_block_field = getattr(field, 'block_field', None) |
|
1061 |
field.contextual_id = field.id |
|
1062 |
field.contextual_varname = None |
|
1063 |
if is_in_block_field: |
|
1064 |
field.contextual_id = '%s-%s' % (field.block_field.id, field.id) |
|
1053 |
if getattr(field, 'block_field', None): |
|
1065 | 1054 |
field.label = '%s / %s' % (field.block_field.label, field.label) |
1066 |
if field.varname and field.block_field.varname: |
|
1067 |
field.contextual_varname = '%s_%s' % (field.block_field.varname, field.varname) |
|
1068 |
else: |
|
1069 |
field.contextual_varname = field.varname |
|
1070 | 1055 | |
1071 | 1056 |
if get_request().form: |
1072 | 1057 |
field.enabled = ('filter-%s' % field.contextual_id in get_request().form) or ( |
... | ... | |
1351 | 1336 |
for field in sorted(self.get_formdef_fields(), key=get_column_position): |
1352 | 1337 |
if not hasattr(field, 'get_view_value'): |
1353 | 1338 |
continue |
1354 |
if getattr(field, 'block_field', None): |
|
1355 |
# fields from blocks cannot yet be added as column |
|
1356 |
continue |
|
1357 | 1339 |
classnames = '' |
1358 | 1340 |
attrs = '' |
1359 | 1341 |
if isinstance(field, RelatedField): |
... | ... | |
1366 | 1348 |
attrs = 'data-field-id="%s"' % field.id |
1367 | 1349 |
seen_parents.add(field.id) |
1368 | 1350 |
r += htmltext('<li class="%s" %s><span class="handle">⣿</span>' % (classnames, attrs)) |
1369 |
r += htmltext('<label><input type="checkbox" name="%s"') % field.id |
|
1351 |
r += htmltext('<label><input type="checkbox" name="%s"') % field.contextual_id
|
|
1370 | 1352 |
if field.id in field_ids: |
1371 | 1353 |
r += htmltext(' checked="checked"') |
1372 | 1354 |
r += htmltext('/>') |
... | ... | |
1565 | 1547 | |
1566 | 1548 |
def iter_fields(fields, block_field=None): |
1567 | 1549 |
for field in fields: |
1550 |
# add contextual_id/contextual_varname attributes |
|
1551 |
# they are id/varname for normal fields |
|
1552 |
# but in case of blocks they are concatenation of block id/varname + field id/varname |
|
1553 |
field.contextual_id = field.id |
|
1554 |
field.contextual_varname = None |
|
1568 | 1555 |
if block_field: |
1569 | 1556 |
if field.key == 'items': |
1570 | 1557 |
# not yet |
1571 | 1558 |
continue |
1572 | 1559 |
field.block_field = block_field |
1560 |
field.contextual_id = '%s-%s' % (field.block_field.id, field.id) |
|
1561 |
if field.varname and field.block_field.varname: |
|
1562 |
field.contextual_varname = '%s_%s' % ( |
|
1563 |
field.block_field.varname, |
|
1564 |
field.varname, |
|
1565 |
) |
|
1566 |
else: |
|
1567 |
field.contextual_varname = field.varname |
|
1573 | 1568 |
yield field |
1574 | 1569 |
if not get_publisher().is_using_postgresql(): |
1575 | 1570 |
continue |
1576 | 1571 |
if field.key == 'block': |
1577 | 1572 |
yield from iter_fields(field.block.fields, block_field=field) |
1578 | 1573 |
continue |
1574 |
if block_field: |
|
1575 |
continue |
|
1579 | 1576 |
if not ( |
1580 | 1577 |
field.type == 'item' |
1581 | 1578 |
and field.data_source |
... | ... | |
1615 | 1612 | |
1616 | 1613 |
fields = [] |
1617 | 1614 |
for field in self.get_formdef_fields(): |
1618 |
if field.id in field_ids: |
|
1615 |
if field.contextual_id in field_ids:
|
|
1619 | 1616 |
fields.append(field) |
1620 | 1617 | |
1621 | 1618 |
if 'columns-order' in get_request().form or self.view: |
... | ... | |
1681 | 1678 | |
1682 | 1679 |
filter_field_key = None |
1683 | 1680 | |
1684 |
is_in_block_field = getattr(filter_field, 'block_field', None) |
|
1685 |
filter_field.contextual_id = filter_field.id |
|
1686 |
filter_field.contextual_varname = None |
|
1687 |
if is_in_block_field: |
|
1688 |
filter_field.contextual_id = '%s-%s' % (filter_field.block_field.id, filter_field.id) |
|
1689 |
if filter_field.varname and filter_field.block_field.varname: |
|
1690 |
filter_field.contextual_varname = '%s_%s' % ( |
|
1691 |
filter_field.block_field.varname, |
|
1692 |
filter_field.varname, |
|
1693 |
) |
|
1694 |
else: |
|
1695 |
filter_field.contextual_varname = filter_field.varname |
|
1696 | ||
1697 | 1681 |
if filter_field.contextual_varname: |
1698 | 1682 |
# if this is a field with a varname and filter-%(varname)s is |
1699 | 1683 |
# present in the query string, enable this filter. |
... | ... | |
1771 | 1755 |
else: |
1772 | 1756 |
raise RequestError('Invalid value "%s" for "%s"' % (filter_field_value, filter_field_key)) |
1773 | 1757 | |
1774 |
if is_in_block_field:
|
|
1758 |
if getattr(filter_field, 'block_field', None):
|
|
1775 | 1759 |
criterias.append( |
1776 | 1760 |
sql.ArrayContains( |
1777 | 1761 |
'f%s' % filter_field.block_field.id, |
... | ... | |
3433 | 3417 |
class FakeField: |
3434 | 3418 |
def __init__(self, id, type_, label, addable=True): |
3435 | 3419 |
self.id = id |
3420 |
self.contextual_id = self.id |
|
3436 | 3421 |
self.type = type_ |
3437 | 3422 |
self.label = force_text(label) |
3438 | 3423 |
self.fake = True |
3439 | 3424 |
self.varname = id.replace('-', '_') |
3425 |
self.contextual_varname = self.varname |
|
3440 | 3426 |
self.store_display_value = None |
3441 | 3427 |
self.addable = addable |
3442 | 3428 | |
... | ... | |
3471 | 3457 |
def id(self): |
3472 | 3458 |
return '%s$%s' % (self.parent_field_id, self.related_field.id) |
3473 | 3459 | |
3460 |
@property |
|
3461 |
def contextual_id(self): |
|
3462 |
return self.id |
|
3463 | ||
3474 | 3464 |
@property |
3475 | 3465 |
def label(self): |
3476 | 3466 |
return '%s - %s' % (self.parent_field.label, self.related_field.label) |
wcs/formdata.py | ||
---|---|---|
797 | 797 |
return None |
798 | 798 | |
799 | 799 |
def get_field_view_value(self, field, max_length=None): |
800 |
# return the value of the given field, with special handling for "fake" |
|
801 |
# field types that are shortcuts to internal properties. |
|
802 |
if field.type == 'id': |
|
803 |
return self.get_display_id() |
|
804 |
if field.type == 'display_name': |
|
805 |
return self.get_display_name() |
|
806 |
if field.type == 'time': |
|
807 |
return misc.localstrftime(self.receipt_time) |
|
808 |
if field.type == 'last_update_time': |
|
809 |
return misc.localstrftime(self.last_update_time) |
|
810 |
if field.type == 'user-label': |
|
811 |
return self.get_user_label() or '-' |
|
812 |
if field.type == 'status': |
|
813 |
return self.get_status_label() |
|
814 |
if field.type == 'submission_channel': |
|
815 |
return self.get_submission_channel_label() |
|
816 |
if field.type == 'submission_agent': |
|
817 |
try: |
|
818 |
agent_user = self.submission_agent_id |
|
819 |
return get_publisher().user_class.get(agent_user).display_name |
|
820 |
except (KeyError, TypeError): |
|
821 |
return '-' |
|
822 |
if field.type == 'anonymised': |
|
823 |
return _('Yes') if self.anonymised else _('No') |
|
824 | ||
825 |
field_value = self.data.get(field.id) |
|
826 |
if field_value is None: |
|
827 |
return '' |
|
828 |
if max_length is not None: |
|
829 |
# if max_length is set the target is a backoffice listing/table, |
|
830 |
# return an html value, appropriately shortened. |
|
831 |
field_value = self.data.get('%s_display' % field.id, field_value) |
|
832 |
return field.get_view_short_value(field_value, max_length) |
|
833 |
else: |
|
834 |
# otherwise return the actual "raw" field value |
|
835 |
return field_value |
|
800 |
def get_value(field, data): |
|
801 |
# return the value of the given field, with special handling for "fake" |
|
802 |
# field types that are shortcuts to internal properties. |
|
803 |
if field.type == 'id': |
|
804 |
return self.get_display_id() |
|
805 |
if field.type == 'display_name': |
|
806 |
return self.get_display_name() |
|
807 |
if field.type == 'time': |
|
808 |
return misc.localstrftime(self.receipt_time) |
|
809 |
if field.type == 'last_update_time': |
|
810 |
return misc.localstrftime(self.last_update_time) |
|
811 |
if field.type == 'user-label': |
|
812 |
return self.get_user_label() or '-' |
|
813 |
if field.type == 'status': |
|
814 |
return self.get_status_label() |
|
815 |
if field.type == 'submission_channel': |
|
816 |
return self.get_submission_channel_label() |
|
817 |
if field.type == 'submission_agent': |
|
818 |
try: |
|
819 |
agent_user = self.submission_agent_id |
|
820 |
return get_publisher().user_class.get(agent_user).display_name |
|
821 |
except (KeyError, TypeError): |
|
822 |
return '-' |
|
823 |
if field.type == 'anonymised': |
|
824 |
return _('Yes') if self.anonymised else _('No') |
|
825 | ||
826 |
field_value = data.get(field.id) |
|
827 |
if field_value is None: |
|
828 |
return '' |
|
829 |
if max_length is not None: |
|
830 |
# if max_length is set the target is a backoffice listing/table, |
|
831 |
# return an html value, appropriately shortened. |
|
832 |
field_value = data.get('%s_display' % field.id, field_value) |
|
833 |
return field.get_view_short_value(field_value, max_length) |
|
834 |
else: |
|
835 |
# otherwise return the actual "raw" field value |
|
836 |
return field_value |
|
837 | ||
838 |
if getattr(field, 'block_field', None): |
|
839 |
data = self.data.get(field.block_field.id) or {} |
|
840 |
return ', '.join(get_value(field, d) for d in data.get('data') or []) |
|
841 |
return get_value(field, self.data) |
|
836 | 842 | |
837 | 843 |
def update_workflow_data(self, dict): |
838 | 844 |
if not self.workflow_data: |
wcs/forms/backoffice.py | ||
---|---|---|
105 | 105 |
' <span id="info-all-rows"><label><input type="checkbox" name="select[]" value="_all"/> %s</label></span></th>' |
106 | 106 |
) % _('Run selected action on all pages') |
107 | 107 |
for f in fields: |
108 |
field_sort_key = None |
|
109 | 108 |
if getattr(f, 'fake', False): |
110 | 109 |
field_sort_key = f.id |
111 | 110 |
if f.id == 'time': |
112 | 111 |
field_sort_key = 'receipt_time' |
113 | 112 |
elif f.id in ('user-label', 'submission_agent'): |
114 | 113 |
field_sort_key = None |
115 |
elif getattr(f, 'is_related_field', False): |
|
114 |
elif getattr(f, 'is_related_field', False) or getattr(f, 'block_field', None):
|
|
116 | 115 |
field_sort_key = None |
117 | 116 |
else: |
118 |
field_sort_key = 'f%s' % f.id |
|
117 |
field_sort_key = 'f%s' % f.contextual_id
|
|
119 | 118 | |
120 | 119 |
if field_sort_key and using_postgresql: |
121 | 120 |
r += htmltext('<th data-field-sort-key="%s">') % field_sort_key |
122 | 121 |
else: |
123 | 122 |
r += htmltext('<th>') |
123 |
if getattr(f, 'block_field', None): |
|
124 |
f.label = '%s / %s' % (f.block_field.label, f.label) |
|
124 | 125 |
if len(f.label) < 20: |
125 | 126 |
r += htmltext('<span>%s</span>') % f.label |
126 | 127 |
else: |
127 |
- |