0002-general-expose-custom-views-as-data-sources-44155.patch
tests/test_admin_pages.py | ||
---|---|---|
3681 | 3681 |
assert 'a block field' in resp.text |
3682 | 3682 |
resp = resp.click('Edit', href='1/') |
3683 | 3683 |
assert resp.form['max_items'].value == '1' |
3684 | ||
3685 | ||
3686 |
def test_card_custom_view_data_source(pub, studio): |
|
3687 |
from test_backoffice_pages import create_environment, test_carddata_custom_view, create_superuser |
|
3688 |
create_environment(pub) |
|
3689 |
test_carddata_custom_view(pub, studio) |
|
3690 | ||
3691 |
carddef = CardDef.select()[0] |
|
3692 |
carddef.digest_template = '{{ form_var_foo }}' |
|
3693 |
carddef.store() |
|
3694 | ||
3695 |
create_superuser(pub) |
|
3696 |
app = login(get_app(pub)) |
|
3697 |
resp = app.get('/backoffice/data/foo/user-card-view/') |
|
3698 |
resp.forms['listing-settings']['filter-1'].checked = True |
|
3699 |
resp = resp.forms['listing-settings'].submit() |
|
3700 |
resp.forms['listing-settings']['filter-1-value'] = 'FOO 0' |
|
3701 |
resp = resp.forms['listing-settings'].submit() |
|
3702 |
resp.forms['save-custom-view']['visibility'] = 'datasource' |
|
3703 |
resp = resp.forms['save-custom-view'].submit() |
|
3704 |
assert pub.custom_view_class.count() == 1 |
|
3705 |
assert pub.custom_view_class.select()[0].visibility == 'datasource' |
|
3706 | ||
3707 |
formdef = FormDef.get_by_urlname('form-title') |
|
3708 |
resp = app.get('/backoffice/forms/%s/fields/' % formdef.id) |
|
3709 | ||
3710 |
resp.forms[0]['label'] = 'foobar' |
|
3711 |
resp.forms[0]['type'] = 'item' |
|
3712 |
resp = resp.forms[0].submit() |
|
3713 |
resp = resp.follow() |
|
3714 |
formdef = FormDef.get_by_urlname('form-title') |
|
3715 |
resp = resp.click(href='%s/' % formdef.fields[-1].id, index=0) |
|
3716 |
assert 'carddef:foo' in [x[0] for x in resp.form['data_source$type'].options] |
|
3717 |
assert 'carddef:foo:card-view' in [x[0] for x in resp.form['data_source$type'].options] |
|
3718 |
assert len(CardDef.get_data_source_items('carddef:foo')) == 50 |
|
3719 |
assert len(CardDef.get_data_source_items('carddef:foo:card-view')) == 1 |
tests/test_backoffice_pages.py | ||
---|---|---|
6228 | 6228 | |
6229 | 6229 |
card = carddef.data_class()() |
6230 | 6230 |
card.data = {'1': 'plop'} |
6231 |
card.just_created() |
|
6231 | 6232 |
card.store() |
6232 | 6233 | |
6233 | 6234 |
carddef2 = CardDef() |
... | ... | |
7228 | 7229 | |
7229 | 7230 |
card = carddef.data_class()() |
7230 | 7231 |
card.data = {'1': 'plop'} |
7232 |
card.just_created() |
|
7231 | 7233 |
card.store() |
7232 | 7234 | |
7233 | 7235 |
card2 = carddef.data_class()() |
7234 | 7236 |
card2.data = {'1': 'plop2'} |
7237 |
card2.just_created() |
|
7235 | 7238 |
card2.store() |
7236 | 7239 | |
7237 | 7240 |
BlockDef.wipe() |
tests/test_form_pages.py | ||
---|---|---|
5598 | 5598 |
assert formdef.data_class().select()[0].data['0_structured']['name'] == 'bar' |
5599 | 5599 | |
5600 | 5600 | |
5601 |
def test_item_field_from_custom_view_on_cards(pub): |
|
5602 |
Role.wipe() |
|
5603 |
pub.custom_view_class.wipe() |
|
5604 | ||
5605 |
user = create_user(pub) |
|
5606 |
role = Role(name='xxx') |
|
5607 |
role.store() |
|
5608 |
user.roles = [role.id] |
|
5609 |
user.is_admin = True |
|
5610 |
user.store() |
|
5611 | ||
5612 |
formdef = create_formdef() |
|
5613 |
formdef.data_class().wipe() |
|
5614 | ||
5615 |
CardDef.wipe() |
|
5616 |
carddef = CardDef() |
|
5617 |
carddef.name = 'items' |
|
5618 |
carddef.digest_template = '{{form_var_attr}}' |
|
5619 |
carddef.workflow_roles = {'_editor': user.roles[0]} |
|
5620 |
carddef.fields = [ |
|
5621 |
fields.ItemField(id='0', type='item', label='item', varname='item', items=['foo', 'bar', 'baz']), |
|
5622 |
fields.StringField(id='1', type='string', label='string', varname='attr'), |
|
5623 |
] |
|
5624 |
carddef.store() |
|
5625 |
carddef.data_class().wipe() |
|
5626 |
baz_ids = set() |
|
5627 |
for i, value in enumerate(['foo', 'bar', 'baz'] * 10): |
|
5628 |
carddata = carddef.data_class()() |
|
5629 |
carddata.data = { |
|
5630 |
'0': value, |
|
5631 |
'0_display': value, |
|
5632 |
'1': 'attr%s' % i, |
|
5633 |
} |
|
5634 |
carddata.just_created() |
|
5635 |
carddata.store() |
|
5636 |
if value == 'baz': |
|
5637 |
baz_ids.add(str(carddata.id)) |
|
5638 | ||
5639 |
# create custom view |
|
5640 |
app = login(get_app(pub), username='foo', password='foo') |
|
5641 | ||
5642 |
resp = app.get('/backoffice/data/items/') |
|
5643 |
if pub.is_using_postgresql(): |
|
5644 |
assert resp.text.count('<tr') == 21 # thead + 20 items (max per page) |
|
5645 |
else: |
|
5646 |
assert resp.text.count('<tr') == 31 # thead + all items |
|
5647 |
resp.forms['listing-settings']['filter-0'].checked = True |
|
5648 |
resp = resp.forms['listing-settings'].submit() |
|
5649 | ||
5650 |
resp.forms['listing-settings']['filter-0-value'] = 'baz' |
|
5651 |
resp = resp.forms['listing-settings'].submit() |
|
5652 |
assert resp.text.count('<tr') == 11 # thead + 10 items |
|
5653 | ||
5654 |
resp.forms['save-custom-view']['title'] = 'as data source' |
|
5655 |
resp.forms['save-custom-view']['visibility'] = 'datasource' |
|
5656 |
resp = resp.forms['save-custom-view'].submit() |
|
5657 | ||
5658 |
custom_view = pub.custom_view_class.select()[0] |
|
5659 | ||
5660 |
# use custom view as source |
|
5661 |
ds = {'type': 'carddef:%s:%s' % (carddef.url_name, custom_view.slug)} |
|
5662 |
formdef.fields = [fields.ItemField(id='0', label='string', type='item', |
|
5663 |
data_source=ds, display_disabled_items=True)] |
|
5664 |
formdef.store() |
|
5665 | ||
5666 |
resp = get_app(pub).get('/test/') |
|
5667 |
assert len(resp.form['f0'].options) == 10 |
|
5668 |
assert set([x[0] for x in resp.form['f0'].options]) == baz_ids |
|
5669 |
resp = resp.form.submit('submit') # -> validation page |
|
5670 |
resp = resp.form.submit('submit') # -> submit |
|
5671 |
assert formdef.data_class().select()[0].data['0'] in baz_ids |
|
5672 |
assert formdef.data_class().select()[0].data['0_structured']['item'] == 'baz' |
|
5673 | ||
5674 | ||
5601 | 5675 |
def test_item_field_with_disabled_items(http_requests, pub): |
5602 | 5676 |
user = create_user(pub) |
5603 | 5677 |
formdef = create_formdef() |
wcs/backoffice/management.py | ||
---|---|---|
1030 | 1030 |
view = None |
1031 | 1031 |
admin_permission = 'forms' |
1032 | 1032 | |
1033 |
def __init__(self, component=None, formdef=None, view=None): |
|
1033 |
def __init__(self, component=None, formdef=None, view=None, update_breadcrumbs=True):
|
|
1034 | 1034 |
self.view_type = None |
1035 | 1035 |
if component: |
1036 | 1036 |
try: |
1037 | 1037 |
self.formdef = FormDef.get_by_urlname(component) |
1038 | 1038 |
except KeyError: |
1039 | 1039 |
raise errors.TraversalError() |
1040 |
get_response().breadcrumb.append((component + '/', self.formdef.name)) |
|
1040 |
if update_breadcrumbs: |
|
1041 |
get_response().breadcrumb.append((component + '/', self.formdef.name)) |
|
1041 | 1042 |
else: |
1042 | 1043 |
self.formdef = formdef |
1043 | 1044 |
self.view = view |
1044 |
get_response().breadcrumb.append((view.slug + '/', view.title)) |
|
1045 |
if update_breadcrumbs: |
|
1046 |
get_response().breadcrumb.append((view.slug + '/', view.title)) |
|
1045 | 1047 | |
1046 | 1048 |
def check_access(self, api_name=None): |
1047 | 1049 |
session = get_session() |
... | ... | |
1092 | 1094 |
if self.view: |
1093 | 1095 |
active = bool(self.view.get_url_slug() == view.get_url_slug()) |
1094 | 1096 |
r += htmltext('<li class="active">' if active else '<li>') |
1095 |
r += htmltext('<a href="../%s/%s">%s</a></li>') % (view.get_url_slug(), view_type, view.title)
|
|
1097 |
r += htmltext('<a href="../%s/%s">%s</a>') % (view.get_url_slug(), view_type, view.title) |
|
1096 | 1098 |
else: |
1097 |
r += htmltext('<li><a href="%s/%s">%s</a></li>') % (view.get_url_slug(), view_type, view.title) |
|
1099 |
r += htmltext('<li><a href="%s/%s">%s</a>') % (view.get_url_slug(), view_type, view.title) |
|
1100 |
if view.visibility == 'datasource': |
|
1101 |
r += htmltext(' <span class="as-data-source">(%s)</span>') % _('for data sources') |
|
1102 |
r += htmltext('</li>') |
|
1098 | 1103 |
r += htmltext('</ul>') |
1099 | 1104 |
return r.getvalue() |
1100 | 1105 | |
... | ... | |
1464 | 1469 |
value=self.view.title if self.view else None) |
1465 | 1470 |
if get_publisher().get_backoffice_root().is_accessible(self.admin_permission): |
1466 | 1471 |
# admins can create views accessible to everyone |
1472 |
options = [ |
|
1473 |
('owner', _('to me only'), 'owner'), |
|
1474 |
('any', _('to any users'), 'any'), |
|
1475 |
] |
|
1476 | ||
1477 |
if isinstance(self.formdef, CardDef) and self.formdef.digest_template: |
|
1478 |
options.append(('datasource', _('as data source'), 'datasource')) |
|
1479 | ||
1467 | 1480 |
form.add(RadiobuttonsWidget, 'visibility', title=_('Visibility'), |
1468 | 1481 |
value=self.view.visibility if self.view else 'owner', |
1469 |
options=[ |
|
1470 |
('owner', _('to me only'), 'owner'), |
|
1471 |
('any', _('to any users'), 'any') |
|
1472 |
]) |
|
1482 |
options=options) |
|
1473 | 1483 |
if self.view and (self.view.user_id == get_request().user.id or |
1474 | 1484 |
get_publisher().get_backoffice_root().is_accessible(self.admin_permission)): |
1475 | 1485 |
form.add(CheckboxWidget, 'update', title=_('Update existing view settings'), value=True) |
... | ... | |
1611 | 1621 |
return 'all' |
1612 | 1622 | |
1613 | 1623 |
def get_criterias_from_query(self): |
1624 |
query_overrides = get_request().form |
|
1625 |
return self.get_view_criterias(query_overrides, request=get_request()) |
|
1626 | ||
1627 |
def get_view_criterias(self, query_overrides=None, request=None): |
|
1614 | 1628 |
fake_fields = [ |
1615 | 1629 |
FakeField('start', 'period-date', _('Start')), |
1616 | 1630 |
FakeField('end', 'period-date', _('End')), |
... | ... | |
1623 | 1637 | |
1624 | 1638 |
filters_dict = {} |
1625 | 1639 |
if self.view: |
1626 |
filters_dict.update(self.view.get_filters_dict()) |
|
1627 |
filters_dict.update(get_request().form) |
|
1640 |
filters_dict.update(self.view.get_filters_dict() or {}) |
|
1641 |
filters_dict.update(query_overrides or {}) |
|
1642 | ||
1643 |
if request and request.form: |
|
1644 |
request_form = request.form |
|
1645 |
else: |
|
1646 |
request_form = {} |
|
1628 | 1647 | |
1629 | 1648 |
for filter_field in fake_fields + list(self.get_formdef_fields()): |
1630 | 1649 |
if filter_field.type not in self.get_filterable_field_types(): |
... | ... | |
1643 | 1662 |
name_id = filters_dict.get('filter-user-uuid') |
1644 | 1663 |
if name_id: |
1645 | 1664 |
nameid_users = get_publisher().user_class.get_users_with_name_identifier(name_id) |
1646 |
get_request().form['filter-user'] = filters_dict['filter-user'] = 'on'
|
|
1665 |
request_form['filter-user'] = filters_dict['filter-user'] = 'on'
|
|
1647 | 1666 |
if nameid_users: |
1648 | 1667 |
filters_dict['filter-user-value'] = str(nameid_users[0].id) |
1649 |
get_request().form['filter-user-value'] = filters_dict['filter-user-value']
|
|
1668 |
request_form['filter-user-value'] = filters_dict['filter-user-value']
|
|
1650 | 1669 |
else: |
1651 | 1670 |
filters_dict['filter-user-value'] = '-1' |
1652 |
get_request().form['filter-user-value'] = '-1'
|
|
1671 |
request_form['filter-user-value'] = '-1'
|
|
1653 | 1672 | |
1654 | 1673 |
if filter_field.type == 'submission-agent-id': |
1655 | 1674 |
# convert uuid based filter into local id filter |
1656 | 1675 |
name_id = filters_dict.get('filter-submission-agent-uuid') |
1657 | 1676 |
if name_id: |
1658 | 1677 |
nameid_users = get_publisher().user_class.get_users_with_name_identifier(name_id) |
1659 |
get_request().form['filter-submission-agent'] = filters_dict['filter-submission-agent'] = 'on'
|
|
1678 |
request_form['filter-submission-agent'] = filters_dict['filter-submission-agent'] = 'on'
|
|
1660 | 1679 |
if nameid_users: |
1661 | 1680 |
filters_dict['filter-submission-agent-value'] = str(nameid_users[0].id) |
1662 |
get_request().form['filter-submission-agent-value'] = filters_dict['filter-submission-agent-value']
|
|
1681 |
request_form['filter-submission-agent-value'] = filters_dict['filter-submission-agent-value']
|
|
1663 | 1682 |
else: |
1664 | 1683 |
filters_dict['filter-submission-agent-value'] = '-1' |
1665 |
get_request().form['filter-submission-agent-value'] = '-1'
|
|
1684 |
request_form['filter-submission-agent-value'] = '-1'
|
|
1666 | 1685 | |
1667 | 1686 |
if filters_dict.get('filter-%s' % filter_field.id): |
1668 | 1687 |
# if there's a filter-%(id)s, it is used to enable the actual |
wcs/carddef.py | ||
---|---|---|
19 | 19 | |
20 | 20 |
from quixote import get_publisher |
21 | 21 |
from .qommon import _, N_, misc |
22 |
from .qommon.storage import Equal, NotEqual |
|
22 | 23 | |
23 | 24 |
from wcs.carddata import CardData |
24 | 25 |
from wcs.formdef import FormDef |
... | ... | |
137 | 138 | |
138 | 139 |
@classmethod |
139 | 140 |
def get_as_data_source_options(cls): |
141 |
carddefs = {} |
|
140 | 142 |
for carddef in cls.select(lightweight=True, ignore_errors=True, order_by='name'): |
141 | 143 |
if not carddef.digest_template: |
142 | 144 |
continue |
143 | 145 |
data_source_id = 'carddef:%s' % carddef.url_name |
146 |
carddefs[carddef.id] = {'url_name': carddef.url_name, 'name': carddef.name} |
|
144 | 147 |
yield (data_source_id, carddef.name, data_source_id) |
148 |
clauses = [Equal('formdef_type', 'carddef'), Equal('visibility', 'datasource')] |
|
149 |
for custom_view in get_publisher().custom_view_class.select(clauses): |
|
150 |
carddef = carddefs.get(custom_view.formdef_id) |
|
151 |
data_source_id = 'carddef:%s:%s' % (carddef['url_name'], custom_view.slug) |
|
152 |
yield (data_source_id, '%s - %s' % (carddef['name'], custom_view.title), data_source_id) |
|
145 | 153 | |
146 | 154 |
@classmethod |
147 | 155 |
def get_data_source_items(cls, data_source_id): |
148 | 156 |
assert data_source_id.startswith('carddef:') |
157 |
parts = data_source_id.split(':') |
|
149 | 158 |
try: |
150 |
carddef = cls.get_by_urlname(data_source_id[8:])
|
|
159 |
carddef = cls.get_by_urlname(parts[1])
|
|
151 | 160 |
except KeyError: |
152 | 161 |
return [] |
162 |
criterias = [NotEqual('status', 'draft')] |
|
163 |
order_by = None |
|
164 |
if len(parts) > 2: |
|
165 |
lookup_criterias = [ |
|
166 |
Equal('formdef_type', 'carddef'), |
|
167 |
Equal('visibility', 'datasource'), |
|
168 |
Equal('slug', parts[2]), |
|
169 |
] |
|
170 |
try: |
|
171 |
custom_view = get_publisher().custom_view_class.select(lookup_criterias)[0] |
|
172 |
except IndexError: |
|
173 |
return [] |
|
174 |
from wcs.backoffice.management import FormPage |
|
175 |
form_page = FormPage(formdef=carddef, view=custom_view, update_breadcrumbs=False) |
|
176 |
criterias.extend(form_page.get_view_criterias()) |
|
177 |
order_by = custom_view.order_by |
|
178 | ||
153 | 179 |
items = [x.get_data_source_structured_item() |
154 |
for x in carddef.data_class().select() |
|
155 |
if not x.is_draft()] |
|
156 |
items.sort(key=lambda x: misc.simplify(x['text'])) |
|
180 |
for x in carddef.data_class().select( |
|
181 |
clause=criterias, |
|
182 |
order_by=order_by)] |
|
183 |
if order_by is None: |
|
184 |
items.sort(key=lambda x: misc.simplify(x['text'])) |
|
157 | 185 |
return items |
wcs/qommon/static/css/dc2/admin.css | ||
---|---|---|
1937 | 1937 |
#sidebar-custom-views .active { |
1938 | 1938 |
font-weight: bold; |
1939 | 1939 |
} |
1940 | ||
1941 |
#sidebar-custom-views .as-data-source { |
|
1942 |
font-weight: normal; |
|
1943 |
} |
|
1940 |
- |