wcs/tests/admin_pages/test_card.py

523 lines
18 KiB
Python

# -*- coding: utf-8 -*-
import re
import pytest
from utilities import clean_temporary_pub, create_temporary_pub, get_app, login
from wcs import fields
from wcs.admin.settings import UserFieldsFormDef
from wcs.carddef import CardDef
from wcs.categories import CardDefCategory
from wcs.formdef import FormDef
from wcs.qommon.http_request import HTTPRequest
from wcs.wf.form import FormWorkflowStatusItem, WorkflowFormFieldsFormDef
from wcs.workflows import Workflow, WorkflowBackofficeFieldsFormDef, WorkflowVariablesFieldsFormDef
from .test_all import create_superuser
def pytest_generate_tests(metafunc):
if 'pub' in metafunc.fixturenames:
metafunc.parametrize('pub', ['pickle', 'sql', 'pickle-templates'], indirect=True)
@pytest.fixture
def pub(request):
pub = create_temporary_pub(
sql_mode=bool('sql' in request.param), templates_mode=bool('templates' in request.param)
)
req = HTTPRequest(None, {'SCRIPT_NAME': '/', 'SERVER_NAME': 'example.net'})
pub.set_app_dir(req)
pub.cfg['identification'] = {'methods': ['password']}
pub.cfg['language'] = {'language': 'en'}
pub.write_cfg()
return pub
def teardown_module(module):
clean_temporary_pub()
def test_cards_list(pub):
create_superuser(pub)
CardDef.wipe()
carddef = CardDef()
carddef.name = 'card title'
carddef.fields = []
carddef.store()
carddef2 = CardDef()
carddef2.name = 'card title 2'
carddef2.fields = []
carddef2.store()
CardDefCategory.wipe()
cat = CardDefCategory(name='Foo')
cat.store()
cat2 = CardDefCategory(name='Bar')
cat2.store()
app = login(get_app(pub))
resp = app.get('/backoffice/cards/')
assert '<h2>Misc</h2>' not in resp.text
assert '<h2>Foo</h2>' not in resp.text
assert '<h2>Bar</h2>' not in resp.text
carddef.category = cat2
carddef.store()
resp = app.get('/backoffice/cards/')
assert '<h2>Misc</h2>' in resp.text
assert '<h2>Foo</h2>' not in resp.text
assert '<h2>Bar</h2>' in resp.text
carddef2.category = cat
carddef2.store()
resp = app.get('/backoffice/cards/')
assert '<h2>Misc</h2>' not in resp.text
assert '<h2>Foo</h2>' in resp.text
assert '<h2>Bar</h2>' in resp.text
def test_cards_new(pub):
CardDef.wipe()
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/cards/')
resp = resp.click('New Card Model')
resp.form['name'] = 'card title'
resp = resp.form.submit()
assert resp.location == 'http://example.net/backoffice/cards/1/'
resp = resp.follow()
assert '<h2>card title' in resp.text
assert CardDef.get(1).workflow_id is None
assert CardDef.get(1).disabled is False
def test_cards_delete(pub):
CardDef.wipe()
carddef = CardDef()
carddef.name = 'card title'
carddef.fields = []
carddef.store()
create_superuser(pub)
app = login(get_app(pub))
carddata = carddef.data_class()()
carddata.just_created()
carddata.data = {}
carddata.store()
resp = app.get('http://example.net/backoffice/cards/1/')
resp = resp.click('Delete')
if pub.is_using_postgresql():
assert 'Deletion is not possible as there are cards.' in resp
carddef.data_class().wipe()
resp = app.get('http://example.net/backoffice/cards/1/')
resp = resp.click('Delete')
resp = resp.form.submit('submit')
assert CardDef.count() == 0
carddata.remove_self() # don't keep leftovers
def test_cards_duplicate(pub):
CardDef.wipe()
carddef = CardDef()
carddef.name = 'card title'
carddef.fields = []
carddef.store()
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('http://example.net/backoffice/cards/1/')
resp = resp.click('Duplicate')
assert CardDef.get(2).name == 'card title (copy)'
assert CardDef.get(2).disabled is False
def test_card_workflow_change(pub):
Workflow.wipe()
workflow = Workflow(name='Workflow Two')
workflow.add_status('plop')
workflow.store()
CardDef.wipe()
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/cards/')
resp = resp.click('New Card Model')
resp.form['name'] = 'card title'
resp = resp.form.submit()
resp = resp.follow()
resp = resp.click(href='workflow', index=1)
assert resp.form['workflow_id'].options[0][2] == 'Default (cards)'
resp = resp.form.submit('submit').follow()
assert CardDef.select()[0].workflow_id is None
carddata = CardDef.select()[0].data_class()()
carddata.status = 'wf-recorded'
carddata.store()
resp = resp.click(href='workflow', index=1)
resp.form['workflow_id'] = '%s' % workflow.id
resp = resp.form.submit('submit')
assert (
resp.location
== 'http://example.net/backoffice/cards/1/workflow-status-remapping?new=%s' % workflow.id
)
resp = resp.follow()
resp = resp.form.submit('submit').follow()
resp = resp.click(href='workflow', index=1)
resp.form['workflow_id'] = ''
resp = resp.form.submit('submit')
assert (
resp.location
== 'http://example.net/backoffice/cards/1/workflow-status-remapping?new=%s' % '_carddef_default'
)
resp = resp.follow()
resp = resp.form.submit('submit').follow()
def assert_option_display(resp, label, value):
option_line = re.findall('%s.*%s' % (label, value), resp.text, re.DOTALL)
assert option_line
assert '</li>' not in option_line
def test_card_templates(pub):
create_superuser(pub)
CardDef.wipe()
carddef = CardDef()
carddef.name = 'foo'
carddef.fields = [
fields.StringField(id='1', label='Test', type='string', varname='foo'),
]
carddef.store()
carddata = carddef.data_class()()
carddata.data = {'1': 'bar'}
carddata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/cards/1/')
assert_option_display(resp, 'Templates', 'None')
assert resp.pyquery('[href="options/templates"]').attr.rel == '' # no popup
resp = resp.click('Templates')
resp.form['digest_template'] = 'X{{form_var_test}}Y'
resp = resp.form.submit()
assert resp.location == 'http://example.net/backoffice/cards/1/'
resp = resp.follow()
assert_option_display(resp, 'Templates', 'Custom')
carddef = CardDef.get(carddef.id)
assert carddef.digest_template == 'X{{form_var_test}}Y'
assert carddef.lateral_template is None
assert carddef.submission_lateral_template is None
assert 'Existing cards will be updated in the background.' in resp.text
resp = app.get('/backoffice/cards/1/options/templates')
resp.form['lateral_template'] = 'X{{form_var_test}}Y'
resp.form['submission_lateral_template'] = 'X{{form_var_test}}YZ'
resp = resp.form.submit().follow()
assert_option_display(resp, 'Templates', 'Custom')
carddef = CardDef.get(carddef.id)
assert carddef.digest_template == 'X{{form_var_test}}Y'
assert carddef.lateral_template == 'X{{form_var_test}}Y'
assert carddef.submission_lateral_template == 'X{{form_var_test}}YZ'
assert 'Existing cards will be updated in the background.' not in resp.text
def test_card_digest_template(pub):
create_superuser(pub)
CardDef.wipe()
carddef = CardDef()
carddef.name = 'foo'
carddef.fields = [
fields.StringField(id='1', label='Test', type='string', varname='foo'),
]
carddef.digest_template = 'X{{ form_var_foo }}Y'
carddef.store()
carddata = carddef.data_class()()
carddata.data = {'1': 'bar'}
carddata.store()
custom_view = pub.custom_view_class()
custom_view.title = 'card view'
custom_view.formdef = carddef
custom_view.columns = {'list': [{'id': 'id'}]}
custom_view.filters = {'filter-1': True, 'filter-1-value': 'FOO'}
custom_view.visibility = 'datasource'
custom_view.store()
# carddef not used in formdef, it's ok to empty digest_template
FormDef.wipe()
app = login(get_app(pub))
resp = app.get('/backoffice/cards/%s/options/templates' % carddef.id)
resp.form['digest_template'] = ''
resp = resp.form.submit().follow()
carddef = CardDef.get(carddef.id)
assert carddef.digest_template is None
assert 'Existing cards will be updated in the background.' in resp.text
# afterjobs are actually run synchronously during tests; we don't have
# to wait to check the digest has been updated:
assert carddef.data_class().get(carddata.id).digest == 'XbarY'
carddef.digest_template = '{{ form_var_foo }}'
carddef.store()
# a formdef using the carddef as datasource
FormDef.wipe()
formdef = FormDef()
formdef.name = 'test card def on data source'
formdef.fields = [fields.ItemField(id='1', label='item', data_source={'type': 'carddef:foo'})]
formdef.store()
# carddef used in formdef, can not empty digest_template
resp = app.get('/backoffice/cards/%s/options/templates' % carddef.id)
resp.form['digest_template'] = ''
resp = resp.form.submit()
assert 'Can not empty digest template: this card model is used as data source in some forms.' in resp.text
carddef = CardDef.get(carddef.id)
assert carddef.digest_template is not None
# error: not stored, and no after jobs
resp = app.get('/backoffice/cards/%s/' % carddef.id)
assert 'Existing cards will be updated in the background.' not in resp.text
def test_card_category(pub):
create_superuser(pub)
CardDef.wipe()
carddef = CardDef()
carddef.name = 'card title'
carddef.fields = []
carddef.store()
CardDefCategory.wipe()
cat = CardDefCategory(name='Foo')
cat.store()
cat = CardDefCategory(name='Bar')
cat.store()
app = login(get_app(pub))
resp = app.get('/backoffice/cards/1/')
assert '<span class="label">Category</span> <span class="value">None</span>' in resp.text
assert '<span class="label">Category</span> <span class="value">Foo</span>' not in resp.text
assert '<span class="label">Category</span> <span class="value">Bar</span>' not in resp.text
resp = resp.click(href='category')
resp.forms[0].submit('cancel')
assert CardDef.get(carddef.id).category_id is None
resp = app.get('/backoffice/cards/1/')
assert '<span class="label">Category</span> <span class="value">None</span>' in resp.text
assert '<span class="label">Category</span> <span class="value">Foo</span>' not in resp.text
assert '<span class="label">Category</span> <span class="value">Bar</span>' not in resp.text
resp = resp.click(href='category')
resp.forms[0]['category_id'] = cat.id
resp.forms[0].submit('submit')
assert CardDef.get(carddef.id).category_id == cat.id
resp = app.get('/backoffice/cards/1/')
assert '<span class="label">Category</span> <span class="value">None</span>' not in resp.text
assert '<span class="label">Category</span> <span class="value">Foo</span>' not in resp.text
assert '<span class="label">Category</span> <span class="value">Bar</span>' in resp.text
def test_card_user_support(pub):
create_superuser(pub)
CardDef.wipe()
carddef = CardDef()
carddef.name = 'card title'
carddef.fields = []
carddef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/cards/1/')
assert '<span class="label">User support</span> <span class="value">No</span>' in resp.text
resp = resp.click(href='user_support')
resp.forms[0]['user_support'] = 'optional'
resp.forms[0].submit('submit')
assert CardDef.get(carddef.id).user_support == 'optional'
resp = app.get('/backoffice/cards/1/')
assert '<span class="label">User support</span> <span class="value">Optional</span>' in resp.text
def test_card_custom_view_data_source(pub):
user = create_superuser(pub)
pub.role_class.wipe()
role = pub.role_class(name='foobar')
role.store()
user.roles = [role.id]
user.store()
CardDef.wipe()
carddef = CardDef()
carddef.name = 'foo'
carddef.fields = [
fields.StringField(id='1', label='Test', type='string', varname='foo'),
]
carddef.backoffice_submission_roles = user.roles
carddef.workflow_roles = {'_editor': user.roles[0]}
carddef.digest_template = '{{ form_var_foo }}'
carddef.store()
carddef.data_class().wipe()
for i in range(3):
carddata = carddef.data_class()()
carddata.just_created()
if i == 0:
carddata.data = {'1': 'BAR'}
else:
carddata.data = {'1': 'FOO'}
if i == 1:
carddata.jump_status('deleted')
carddata.store()
pub.custom_view_class.wipe()
custom_view = pub.custom_view_class()
custom_view.title = 'card view'
custom_view.formdef = carddef
custom_view.columns = {'list': [{'id': 'id'}]}
custom_view.filters = {'filter-1': True, 'filter-1-value': 'FOO'}
custom_view.visibility = 'datasource'
custom_view.store()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [
fields.ItemField(id='1', label='field', type='item', varname='foo'),
]
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/%s/fields/1/' % formdef.id)
assert 'carddef:foo' in [x[0] for x in resp.form['data_source$type'].options]
assert 'carddef:foo:card-view' in [x[0] for x in resp.form['data_source$type'].options]
assert len(CardDef.get_data_source_items('carddef:foo')) == 3
assert len(CardDef.get_data_source_items('carddef:foo:card-view')) == 2
custom_view.filters = {'filter-1': True, 'filter-1-value': 'FOO', 'filter-status': 'on', 'filter': 'done'}
custom_view.store()
assert len(CardDef.get_data_source_items('carddef:foo:card-view')) == 1
def test_carddef_usage(pub):
user = create_superuser(pub)
pub.role_class.wipe()
role = pub.role_class(name='foobar')
role.store()
user.roles = [role.id]
user.store()
# the one used as data source
CardDef.wipe()
carddef = CardDef()
carddef.name = 'foo'
carddef.fields = [
fields.StringField(id='1', label='Test', type='string', varname='foo'),
]
carddef.workflow_roles = {'_editor': user.roles[0]}
carddef.store()
# another one
carddef2 = CardDef()
carddef2.name = 'foobar' # url_name startswith 'foo'
carddef2.fields = [
fields.StringField(id='1', label='Test', type='string', varname='foo'),
]
carddef2.store()
# custom view
app = login(get_app(pub))
resp = app.get('/backoffice/data/foo/')
resp = resp.forms['listing-settings'].submit()
resp.forms['save-custom-view']['title'] = 'card view'
resp = resp.forms['save-custom-view'].submit()
# a formdef using the carddef as datasource
FormDef.wipe()
formdef = FormDef()
formdef.name = 'test card def on data source'
formdef.fields = [fields.ItemField(id='1', label='item', data_source={'type': 'carddef:foo'})]
formdef.store()
# another using the custom view
formdef2 = FormDef()
formdef2.name = 'test card def on data source2'
formdef2.fields = [fields.ItemField(id='1', label='item', data_source={'type': 'carddef:foo:card-view'})]
formdef2.store()
# another, using the other carddef as datasource
formdef3 = FormDef()
formdef3.name = 'test card def on data source2'
formdef3.fields = [
fields.ItemField(
id='1', label='item', data_source={'type': 'carddef:foobar'}
) # startswith carddef:foo
]
formdef3.store()
# user form
user_formdef = UserFieldsFormDef(pub)
user_formdef.fields.append(
fields.ItemField(id='1', type='item', label='item', data_source={'type': 'carddef:foo'})
)
user_formdef.store()
# workflow
Workflow.wipe()
workflow = Workflow(name='Workflow One')
workflow.variables_formdef = WorkflowVariablesFieldsFormDef(workflow=workflow)
workflow.variables_formdef.fields.append(
fields.ItemField(id='1', type='idem', label='item', data_source={'type': 'carddef:foo'})
)
workflow.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(workflow)
workflow.backoffice_fields_formdef.fields.append(
fields.ItemField(id='1', type='item', label='item', data_source={'type': 'carddef:foo'})
)
baz_status = workflow.add_status(name='baz')
display_form = FormWorkflowStatusItem()
display_form.id = '_x'
display_form.formdef = WorkflowFormFieldsFormDef(item=display_form)
display_form.formdef.fields.append(
fields.ItemField(id='1', type='item', label='item', data_source={'type': 'carddef:foo'})
)
baz_status.items.append(display_form)
display_form.parent = baz_status
workflow.store()
# carddef
carddef3 = CardDef()
carddef3.name = 'Baz'
carddef3.fields = [fields.ItemField(id='1', label='item', data_source={'type': 'carddef:foo'})]
carddef3.store()
resp = app.get('http://example.net/backoffice/cards/1/')
assert 'This card model is used as data source in the following forms' in resp.text
assert '/backoffice/forms/%s/' % formdef.id in resp.text
assert '/backoffice/forms/%s/' % formdef2.id in resp.text
assert '/backoffice/forms/%s/' % formdef3.id not in resp.text # no, not the good one
assert '/backoffice/workflows/%s/backoffice-fields/fields/' % workflow.id in resp.text
assert '/backoffice/workflows/%s/variables/fields/' % workflow.id in resp.text
assert '/backoffice/workflows/%s/status/1/items/_x/fields/' % workflow.id in resp.text
assert '/backoffice/settings/users/fields/' in resp.text
assert '/backoffice/cards/%s/' % carddef3.id in resp.text
# cleanup
user_formdef = UserFieldsFormDef(pub)
user_formdef.fields = []
user_formdef.store()