wcs/tests/backoffice_pages/test_all.py

4645 lines
163 KiB
Python

import datetime
import io
import json
import os
import random
import re
import time
import zipfile
from unittest import mock
import pytest
import wcs.qommon.storage as st
from wcs import fields
from wcs.api_access import ApiAccess
from wcs.blocks import BlockDef
from wcs.carddef import CardDef
from wcs.categories import Category
from wcs.formdef import FormDef
from wcs.qommon.http_request import HTTPRequest
from wcs.qommon.ident.password_accounts import PasswordAccount
from wcs.qommon.upload_storage import PicklableUpload
from wcs.roles import logged_users_role
from wcs.wf.create_formdata import Mapping
from wcs.wf.form import WorkflowFormFieldsFormDef
from wcs.workflows import Workflow, WorkflowBackofficeFieldsFormDef, WorkflowCriticalityLevel
from wcs.wscalls import NamedWsCall
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app, login
@pytest.fixture
def pub(emails):
pub = create_temporary_pub()
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()
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
fd.write(
'''
[api-secrets]
coucou = 1234
'''
)
return pub
def create_user(pub, is_admin=False):
user1 = None
for user in pub.user_class.select():
if user.name == 'admin':
user1 = user
user1.is_admin = is_admin
user1.roles = [x.id for x in pub.role_class.select() if x.name == 'foobar']
user1.store()
elif user.email == 'jean.darmette@triffouilis.fr':
pass # don't remove user created by local_user fixture
else:
user.remove_self()
if user1:
return user1
user1 = pub.user_class(name='admin')
user1.email = 'admin@localhost'
user1.is_admin = is_admin
user1.store()
account1 = PasswordAccount(id='admin')
account1.set_password('admin')
account1.user_id = user1.id
account1.store()
pub.role_class.wipe()
role = pub.role_class(name='foobar')
role.store()
user1.roles = [role.id]
user1.store()
return user1
def create_superuser(pub):
return create_user(pub, is_admin=True)
def create_environment(pub, set_receiver=True):
pub.session_manager.session_class.wipe()
Workflow.wipe()
Category.wipe()
FormDef.wipe()
BlockDef.wipe()
CardDef.wipe()
pub.custom_view_class.wipe()
formdef = FormDef()
formdef.name = 'form title'
if set_receiver:
formdef.workflow_roles = {'_receiver': 1}
datasource = {'type': 'formula', 'value': repr([('A', 'aa'), ('B', 'bb'), ('C', 'cc')])}
formdef.fields = []
formdef.store() # make sure sql columns are removed
formdef.fields = [
fields.StringField(
id='1', label='1st field', type='string', display_locations=['validation', 'summary', 'listings']
),
fields.ItemField(
id='2',
label='2nd field',
type='item',
items=['foo', 'bar', 'baz'],
display_locations=['validation', 'summary', 'listings'],
),
fields.ItemField(id='3', label='3rd field', type='item', data_source=datasource, varname='foo'),
]
formdef.store()
formdef.data_class().wipe()
for i in range(50):
formdata = formdef.data_class()()
formdata.just_created()
formdata.receipt_time = datetime.datetime(2015, 1, 1, 0, i).timetuple()
formdata.data = {'1': 'FOO BAR %d' % i}
if i % 4 == 0:
formdata.data['2'] = 'foo'
formdata.data['2_display'] = 'foo'
formdata.data['3'] = 'A'
formdata.data['3_display'] = 'aa'
elif i % 4 == 1:
formdata.data['2'] = 'bar'
formdata.data['2_display'] = 'bar'
formdata.data['3'] = 'B'
formdata.data['3_display'] = 'bb'
else:
formdata.data['2'] = 'baz'
formdata.data['2_display'] = 'baz'
formdata.data['3'] = 'C'
formdata.data['3_display'] = 'cc'
if i % 3 == 0:
formdata.jump_status('new')
else:
formdata.jump_status('finished')
formdata.store()
formdata = formdef.data_class()()
formdata.data = {'1': 'XXX', '2': 'foo', '2_display': 'foo'}
formdata.status = 'draft'
formdata.store()
formdef = FormDef()
if set_receiver:
formdef.workflow_roles = {'_receiver': 1}
formdef.name = 'other form'
formdef.fields = []
formdef.store()
formdef.data_class().wipe()
for i in range(20):
formdata = formdef.data_class()()
formdata.just_created()
formdata.receipt_time = datetime.datetime(2014, 1, 1).timetuple()
formdata.jump_status('new')
formdata.store()
def teardown_module(module):
clean_temporary_pub()
def test_backoffice_unlogged(pub):
create_superuser(pub)
resp = get_app(pub).get('/backoffice/', status=302)
assert resp.location == 'http://example.net/login/?next=http%3A%2F%2Fexample.net%2Fbackoffice%2F'
def test_backoffice_home(pub):
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/')
assert resp.location.endswith('/studio/')
resp.follow()
def test_backoffice_role_user(pub):
create_user(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/')
assert resp.location.endswith('/management/')
pub.cfg['admin-permissions'] = {'forms': [x.id for x in pub.role_class.select()]}
pub.write_cfg()
resp = app.get('/backoffice/')
assert resp.location.endswith('/studio/')
resp = resp.follow()
assert 'Forms' in resp.text
assert 'Workflows' not in resp.text
pub.cfg['admin-permissions'] = {'workflows': [x.id for x in pub.role_class.select()]}
pub.write_cfg()
resp = app.get('/backoffice/')
assert resp.location.endswith('/studio/')
resp = resp.follow()
assert 'Forms' not in resp.text
assert 'Workflows' in resp.text
# check role id int->str migration
pub.cfg['admin-permissions'] = {'workflows': [int(x.id) for x in pub.role_class.select()]}
pub.write_cfg()
resp = app.get('/backoffice/')
assert resp.location.endswith('/studio/')
resp = resp.follow()
assert 'Forms' not in resp.text
assert 'Workflows' in resp.text
def test_backoffice_forms(pub):
create_superuser(pub)
create_environment(pub, set_receiver=False)
# 1st time with user not handling those forms
app = login(get_app(pub))
resp = app.get('/backoffice/management/forms')
assert 'Forms in your care' not in resp.text
assert re.findall('Other Forms.*form-title', resp.text)
# 2nd time with user set as receiver of the forms
create_environment(pub, set_receiver=True)
app = login(get_app(pub))
resp = app.get('/backoffice/management/forms')
assert 'Forms in your care' in resp.text
assert '17 open on 50' in resp.text
# disable form, make sure it's still displayed
formdef = FormDef.get_by_urlname('form-title')
formdef.disabled = True
formdef.store()
resp = app.get('/backoffice/management/forms')
assert 'form-title' in resp.text
assert '17 open on 50' in resp.text
formdef.disabled = False
formdef.store()
# add an extra status to workflow and move a few formdatas to it, they
# should then be marked as open but not waiting for actions.
workflow = Workflow.get_default_workflow()
workflow.id = '2'
st1 = workflow.add_status('Status1')
jump = st1.add_action('jump', id='_jump')
jump.timeout = 86400
jump.status = 'finished'
workflow.store()
formdef = FormDef.get_by_urlname('form-title')
formdef.workflow = workflow
formdef.store()
for i, formdata in enumerate(formdef.data_class().select(order_by='id')):
if formdata.status == 'wf-new' and i % 2:
formdata.status = 'wf-%s' % st1.id
formdata.store()
resp = app.get('/backoffice/management/forms')
assert 'Forms in your care' in resp.text
assert '9 open on 50' in resp.text
# anonymise some formdata, they should no longer be included
formdef = FormDef.get_by_urlname('form-title')
for i, formdata in enumerate(
formdef.data_class().select([st.Equal('status', 'wf-finished')], order_by='id')
):
if i >= 20:
break
formdata.anonymise()
for i, formdata in enumerate(formdef.data_class().select([st.Equal('status', 'wf-new')], order_by='id')):
if i >= 5:
break
formdata.anonymise()
resp = app.get('/backoffice/management/forms')
assert 'Forms in your care' in resp.text
assert '4 open on 25' in resp.text
def test_backoffice_management_css_class(pub):
create_superuser(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/')
assert resp.pyquery.find('body.section-management')
def test_backoffice_form_access_forbidden(pub):
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
user = create_user(pub)
formdata = formdef.data_class()()
formdata.just_created()
formdata.store()
resp = login(get_app(pub)).get(formdata.get_backoffice_url(), status=403)
assert 'Access Forbidden' in resp.text
assert 'data-gadjo="true"' in resp.text # backoffice style
role = pub.role_class.get(user.roles[0])
role.allows_backoffice_access = False
role.store()
resp = login(get_app(pub)).get(formdata.get_backoffice_url(), status=403)
assert 'data-gadjo="true"' not in resp.text # no style
role.allows_backoffice_access = True
role.store()
def test_admin_form_page(pub):
create_superuser(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/')
assert 'backoffice/forms/1/' in resp
assert 'backoffice/workflows/_default/' in resp
def test_backoffice_listing(pub):
create_superuser(pub)
create_environment(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/')
assert resp.text.count('data-link') == 17
# check status filter <select>
resp = app.get('/backoffice/management/form-title/')
resp.forms['listing-settings']['filter'] = 'all'
resp = resp.forms['listing-settings'].submit()
assert resp.text.count('data-link') == 20
# check status filter <select>
resp = app.get('/backoffice/management/form-title/')
resp.forms['listing-settings']['filter'] = 'done'
resp = resp.forms['listing-settings'].submit()
assert resp.text.count('data-link') == 20
resp = resp.click('Next Page')
assert resp.text.count('data-link') == 13
# add an extra status to workflow and move a few formdatas to it, they
# should then be marked as open but not waiting for actions.
workflow = Workflow.get_default_workflow()
workflow.id = '2'
st1 = workflow.add_status('Status1')
st1.id = 'plop'
jump = st1.add_action('jump', id='_jump')
jump.timeout = 86400
jump.status = 'finished'
workflow.store()
formdef = FormDef.get_by_urlname('form-title')
formdef.workflow = workflow
formdef.store()
for i, formdata in enumerate(formdef.data_class().select(order_by='id')):
if formdata.status == 'wf-new' and i % 2:
formdata.status = 'wf-%s' % st1.id
formdata.store()
resp = app.get('/backoffice/management/form-title/')
assert resp.text.count('data-link') == 9
resp.forms['listing-settings']['filter'] = 'pending'
resp = resp.forms['listing-settings'].submit()
assert resp.text.count('data-link') == 17
# check status forced as endpoints are not part of the "actionable" list.
workflow = Workflow.get_default_workflow()
workflow.id = '3'
st1 = workflow.add_status('Status1')
st1.id = 'plop'
st1.forced_endpoint = False
again = st1.add_action('choice', id='_again')
again.label = 'Again'
again.by = ['_receiver']
again.status = st1.id
workflow.store()
formdef = FormDef.get_by_urlname('form-title')
formdef.workflow = workflow
formdef.store()
formdef.data_class().rebuild_security()
for i, formdata in enumerate(formdef.data_class().select(order_by='id')):
if formdata.status == 'wf-new' and i % 2:
formdata.status = 'wf-%s' % st1.id
formdata.store()
resp = app.get('/backoffice/management/form-title/')
assert resp.text.count('data-link') == 17
resp.forms['listing-settings']['filter'] = 'pending'
resp = resp.forms['listing-settings'].submit()
assert resp.text.count('data-link') == 17
# mark status as an endpoint
st1.forced_endpoint = True
workflow.store()
formdef.data_class().rebuild_security()
resp = app.get('/backoffice/management/form-title/')
assert resp.text.count('data-link') == 9
resp.forms['listing-settings']['filter'] = 'pending'
resp = resp.forms['listing-settings'].submit()
assert resp.text.count('data-link') == 9
def test_backoffice_listing_pagination(pub):
create_superuser(pub)
create_environment(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/')
assert resp.text.count('data-link') == 17
resp = app.get('/backoffice/management/form-title/?limit=5')
assert resp.text.count('data-link') == 5
assert '<div id="page-links">' in resp.text
resp = resp.click(re.compile('^2$')) # second page
assert resp.text.count('data-link') == 5
assert resp.forms['listing-settings']['offset'].value == '5'
resp = resp.click(re.compile('^3$')) # third page
assert resp.text.count('data-link') == 5
assert resp.forms['listing-settings']['offset'].value == '10'
resp = resp.click(re.compile('^4$')) # fourth page
assert resp.text.count('data-link') == 2
assert resp.forms['listing-settings']['offset'].value == '15'
with pytest.raises(IndexError): # no fifth page
resp = resp.click(re.compile('^5$'))
resp = resp.click(re.compile('^10$')) # per page: 10
assert resp.text.count('data-link') == 10
resp = resp.click(re.compile('^20$')) # per page: 20
assert resp.text.count('data-link') == 17
# try an overbound offset
resp = app.get('/backoffice/management/form-title/?limit=5&offset=30')
resp = resp.follow()
assert resp.forms['listing-settings']['offset'].value == '0'
# try invalid values
resp = app.get('/backoffice/management/form-title/?limit=toto&offset=30', status=400)
resp = app.get('/backoffice/management/form-title/?limit=5&offset=toto', status=400)
def test_backoffice_listing_anonymised(pub):
create_superuser(pub)
create_environment(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/?limit=500')
assert resp.text.count('data-link') == 17
formdef = FormDef.get_by_urlname('form-title')
for i, formdata in enumerate(formdef.data_class().select(order_by='id')):
if i % 2:
formdata.anonymise()
resp = app.get('/backoffice/management/form-title/?limit=500')
assert resp.text.count('data-link') == 9
def test_backoffice_listing_fts(pub):
create_superuser(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/')
assert resp.text.count('data-link') == 17
resp = app.get('/backoffice/management/form-title/')
resp.forms['listing-settings']['filter'] = 'all'
resp.forms['listing-settings']['q'] = 'foo'
resp.forms['listing-settings']['limit'] = '100'
resp = resp.forms['listing-settings'].submit()
assert resp.pyquery('tbody tr').length == 50
assert [x.text for x in resp.pyquery('tbody tr .cell-id a')] == [
'%s-%s' % (formdef.id, i) for i in range(50, 0, -1)
]
resp.forms['listing-settings']['q'] = 'baz'
resp = resp.forms['listing-settings'].submit()
assert resp.pyquery('tbody tr').length == 24
def test_backoffice_legacy_urls(pub):
create_superuser(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/form-title/')
assert resp.location == 'http://example.net/backoffice/management/form-title/'
resp = app.get('/backoffice/form-title/%s/' % formdata.id)
assert resp.location == 'http://example.net/backoffice/management/form-title/%s/' % formdata.id
resp = app.get('/backoffice/form-title/listing/?bla')
assert resp.location == 'http://example.net/backoffice/management/form-title/listing/?bla'
resp = app.get('/backoffice/form-title/listing/foo?bla')
assert resp.location == 'http://example.net/backoffice/management/form-title/listing/foo?bla'
resp = app.get('/backoffice/not-form-title/', status=404)
def test_backoffice_form_category_permissions(pub):
user = create_user(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.workflow_roles = {'_receiver': 1}
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/')
assert 'Export a Spreadsheet' in resp.text
assert 'Statistics' in resp.text
cat1 = Category(name='cat1')
cat1.store()
formdef.category_id = cat1.id
formdef.store()
resp = app.get('/backoffice/management/form-title/')
assert 'Export a Spreadsheet' in resp.text
assert 'Statistics' in resp.text
role = pub.role_class(name='limited perms')
role.store()
cat1.export_roles = [role]
cat1.store()
resp = app.get('/backoffice/management/form-title/')
assert 'Export a Spreadsheet' not in resp.text
assert 'Statistics' in resp.text
cat1.statistics_roles = [role]
cat1.store()
resp = app.get('/backoffice/management/form-title/')
assert 'Export a Spreadsheet' not in resp.text
assert 'Statistics' not in resp.text
app.get('/backoffice/management/form-title/stats', status=403)
app.get('/backoffice/management/form-title/export-spreadsheet', status=403)
app.get('/backoffice/management/form-title/csv', status=403)
app.get('/backoffice/management/form-title/ods', status=403)
# check it's ok for admins
user.is_admin = True
user.store()
resp = app.get('/backoffice/management/form-title/')
assert 'Export a Spreadsheet' in resp.text
assert 'Statistics' in resp.text
app.get('/backoffice/management/form-title/stats', status=200)
app.get('/backoffice/management/form-title/export-spreadsheet', status=200)
app.get('/backoffice/management/form-title/csv', status=200)
app.get('/backoffice/management/form-title/ods', status=200)
# check it's ok for agents with roles
user.is_admin = False
user.roles.append(role.id)
user.store()
resp = app.get('/backoffice/management/form-title/')
assert 'Export a Spreadsheet' in resp.text
assert 'Statistics' in resp.text
app.get('/backoffice/management/form-title/stats', status=200)
app.get('/backoffice/management/form-title/export-spreadsheet', status=200)
app.get('/backoffice/management/form-title/csv', status=200)
app.get('/backoffice/management/form-title/ods', status=200)
def test_backoffice_multi_actions(pub):
create_superuser(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/')
assert 'id="multi-actions"' in resp.text # always there
workflow = Workflow.get_default_workflow()
workflow.id = '2'
action = workflow.add_global_action('FOOBAR')
jump = action.add_action('jump')
jump.status = 'finished'
trigger = action.triggers[0]
trigger.roles = ['whatever']
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
resp = app.get('/backoffice/management/form-title/')
assert 'id="multi-actions"' in resp.text
trigger.roles = [x.id for x in pub.role_class.select() if x.name == 'foobar']
workflow.store()
resp = app.get('/backoffice/management/form-title/?limit=20')
assert 'id="multi-actions"' in resp.text
ids = []
for checkbox in resp.forms[0].fields['select[]'][1:6]:
ids.append(checkbox._value)
checkbox.checked = True
resp = resp.forms[0].submit('button-action-1')
assert '?job=' in resp.location
resp = resp.follow()
assert 'Executing task &quot;FOOBAR&quot; on forms' in resp.text
assert '>completed<' in resp.text
assert (
resp.pyquery.find('[data-redirect-auto]').attr['href']
== '/backoffice/management/form-title/?limit=20'
)
for id in ids:
assert formdef.data_class().get(id).status == 'wf-finished'
draft_ids = [x.id for x in formdef.data_class().select() if x.status == 'draft']
resp = app.get('/backoffice/management/form-title/')
assert resp.forms[0].fields['select[]'][0]._value == '_all'
resp.forms[0].fields['select[]'][0].checked = True
resp = resp.forms[0].submit('button-action-1')
for formdata in formdef.data_class().select():
if formdata.id in draft_ids:
assert formdata.status == 'draft'
else:
assert formdata.status == 'wf-finished'
for formdata in formdef.data_class().select():
if formdata.status != 'draft':
formdata.jump_status('new')
formdata.store()
# action for other role
action2 = workflow.add_global_action('OTHER ACTION')
jump = action2.add_action('jump')
jump.status = 'accepted'
trigger = action2.triggers[0]
trigger.roles = ['whatever']
workflow.store()
resp = app.get('/backoffice/management/form-title/')
assert 'id="multi-actions"' in resp.text
assert 'OTHER ACTION' not in resp.text
# action for function
trigger.roles = ['_foobar']
workflow.store()
resp = app.get('/backoffice/management/form-title/')
assert 'id="multi-actions"' in resp.text
assert 'OTHER ACTION' not in resp.text
workflow.roles['_foobar'] = 'Foobar'
workflow.store()
resp = app.get('/backoffice/management/form-title/')
assert 'id="multi-actions"' in resp.text
assert 'OTHER ACTION' in resp.text
# alter some formdata to simulate dispatch action
stable_ids = []
for checkbox in resp.forms[0].fields['select[]'][1:6]:
formdata = formdef.data_class().get(checkbox._value)
formdata.workflow_roles = {'_foobar': [formdef.workflow_roles['_receiver']]}
formdata.store()
stable_ids.append(formdata.id)
resp = app.get('/backoffice/management/form-title/')
assert resp.pyquery('[data-link="%s/"] input' % stable_ids[0]).attr['data-is__foobar'] == 'true'
assert 'OTHER ACTION' in resp.text
resp.forms[0].fields['select[]'][0].checked = True # _all
resp = resp.forms[0].submit('button-action-2')
assert '?job=' in resp.location
resp = resp.follow()
assert 'Executing task &quot;OTHER ACTION&quot; on forms' in resp.text
# check only dispatched formdata have been moved by global action executed
# on all formdatas
for formdata in formdef.data_class().select():
if formdata.id in draft_ids:
assert formdata.status == 'draft'
elif formdata.id in stable_ids:
assert formdata.status == 'wf-accepted'
else:
assert formdata.status != 'wf-accepted'
def test_backoffice_multi_actions_jump(pub):
create_superuser(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/')
workflow = Workflow.get_default_workflow()
workflow.id = '2'
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
resp = app.get('/backoffice/management/form-title/')
assert 'select[]' not in resp.forms['multi-actions'].fields
resp.forms['listing-settings']['filter'] = 'new'
resp = resp.forms['listing-settings'].submit()
assert 'select[]' not in resp.forms['multi-actions'].fields
# add identifier to jumps
workflow.get_status('new').items[1].identifier = 'accept'
workflow.get_status('new').items[2].identifier = 'reject'
workflow.get_status('new').items[2].require_confirmation = True
workflow.store()
resp.forms['listing-settings']['filter-operator'] = 'ne'
resp = resp.forms['listing-settings'].submit()
assert 'select[]' not in resp.forms['multi-actions'].fields
resp.forms['listing-settings']['filter-operator'] = 'eq'
resp = resp.forms['listing-settings'].submit()
assert 'select[]' in resp.forms['multi-actions'].fields
assert len(resp.pyquery.find('#multi-actions div.buttons button')) == 2
assert len(resp.pyquery.find('#multi-actions div.buttons button[data-ask-for-confirmation]')) == 1
ids = []
for checkbox in resp.forms[0].fields['select[]'][1:6]:
ids.append(checkbox._value)
checkbox.checked = True
resp = resp.forms['multi-actions'].submit('button-action-st-accept')
assert '?job=' in resp.location
resp = resp.follow()
assert 'Executing task &quot;Accept&quot; on forms' in resp.text
assert '>completed<' in resp.text
for id in ids:
assert formdef.data_class().get(id).status == 'wf-accepted'
def test_backoffice_multi_actions_oldest_form(pub):
create_superuser(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/')
assert 'id="multi-actions"' in resp.text # always there
workflow = Workflow.get_default_workflow()
workflow.id = '2'
action = workflow.add_global_action('Mark as duplicates')
jump = action.add_action('jump')
jump.condition = {'type': 'django', 'value': "mass_action_index != 0"}
jump.status = 'rejected'
jump2 = action.add_action('jump')
jump2.condition = {'type': 'django', 'value': "mass_action_index == 0"}
jump2.status = 'accepted'
register_comment = workflow.possible_status[2].add_action('register-comment', id='_comment')
register_comment.comment = '<p>Original form: {{ oldest_form_number }}.</p>'
assert workflow.possible_status[2].id == 'rejected'
trigger = action.triggers[0]
trigger.roles = [x.id for x in pub.role_class.select() if x.name == 'foobar']
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
resp = app.get('/backoffice/management/form-title/')
assert 'id="multi-actions"' in resp.text
ids = []
for checkbox in resp.forms[0].fields['select[]'][1:6]:
ids.append(checkbox._value)
checkbox.checked = True
resp = resp.forms[0].submit('button-action-1')
assert '?job=' in resp.location
resp = resp.follow()
assert 'Executing task &quot;Mark as duplicates&quot; on forms' in resp.text
assert '>completed<' in resp.text
oldest_formdata = None
for i, id in enumerate(sorted(ids, key=int)):
if i == 0:
oldest_formdata = formdef.data_class().get(id)
assert formdef.data_class().get(id).status == 'wf-accepted'
else:
assert formdef.data_class().get(id).status == 'wf-rejected'
assert (
formdef.data_class().get(id).evolution[-1].parts[0].content
== '<p>Original form: %s.</p>' % oldest_formdata.get_display_id()
)
def test_backoffice_multi_actions_using_session_user(pub):
create_superuser(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/')
assert 'id="multi-actions"' in resp.text # always there
workflow = Workflow.get_default_workflow()
workflow.id = '2'
action = workflow.add_global_action('Show user')
register_comment = action.add_action('register-comment')
register_comment.comment = 'session_user={{session_user}}'
trigger = action.triggers[0]
trigger.roles = [x.id for x in pub.role_class.select() if x.name == 'foobar']
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
resp = app.get('/backoffice/management/form-title/')
assert 'id="multi-actions"' in resp.text
ids = []
for checkbox in resp.forms[0].fields['select[]'][1:6]:
ids.append(checkbox._value)
checkbox.checked = True
resp = resp.forms[0].submit('button-action-1')
assert '?job=' in resp.location
resp = resp.follow()
assert 'Executing task &quot;Show user&quot; on forms' in resp.text
assert '>completed<' in resp.text
for id in sorted(ids, key=int):
content = formdef.data_class().get(id).evolution[-1].parts[0].content
assert 'session_user=admin' in content
def test_backoffice_map(pub):
create_user(pub)
create_environment(pub)
form_class = FormDef.get_by_urlname('form-title').data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/')
assert re.findall(r'<tbody.*\/tbody>', resp.text, re.DOTALL)[0].count('<tr') == 17
# check there's no link to map the sidebar
assert 'Plot on a Map' not in resp.text
formdef = FormDef.get_by_urlname('form-title')
formdef.geolocations = {'base': 'Geolocafoobar'}
formdef.store()
number31.geolocations = {'base': {'lat': 48.83, 'lon': 2.32}}
number31.store()
resp = app.get('/backoffice/management/form-title/')
assert 'Plot on a Map' in resp.text
resp = resp.click('Plot on a Map')
assert 'data-geojson-url' in resp.text
assert 'tiles.entrouvert.org/' in resp.text
if not pub.site_options.has_section('options'):
pub.site_options.add_section('options')
pub.site_options.set('options', 'map-tile-urltemplate', 'https://{s}.tile.example.net/{z}/{x}/{y}.png')
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
pub.site_options.write(fd)
resp = app.get('/backoffice/management/form-title/')
resp = resp.click('Plot on a Map')
assert 'tile.example.net/' in resp.text
def test_backoffice_geojson(pub):
create_user(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
formdef.fields.append(fields.MapField(id='4', label='4th field', type='map'))
formdef.fields.append(fields.MapField(id='5', label='5th field', type='string'))
formdef.store()
form_class = formdef.data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/geojson', status=404)
formdef = FormDef.get_by_urlname('form-title')
formdef.geolocations = {'base': 'Geolocafoobar'}
formdef.store()
number31 = formdef.data_class().get(number31.id)
number31.geolocations = {'base': {'lat': 48.83, 'lon': 2.32}}
number31.store()
resp = app.get('/backoffice/management/form-title/geojson?1=on&4=on&5=on')
assert len(resp.json['features']) == 1
assert resp.json['features'][0]['geometry']['coordinates'] == [2.32, 48.83]
assert 'status_colour' in resp.json['features'][0]['properties']
assert resp.json['features'][0]['properties']['status_name'] == 'New'
assert resp.json['features'][0]['properties']['status_colour'] == '#66FF00'
assert resp.json['features'][0]['properties']['view_label'] == 'View'
assert 'display_fields' in resp.json['features'][0]['properties']
assert len(resp.json['features'][0]['properties']['display_fields']) == 1
resp = app.get('/backoffice/management/form-title/geojson?filter=pending&filter-status=on')
assert len(resp.json['features']) == 1
resp = app.get('/backoffice/management/form-title/geojson?filter=done&filter-status=on')
assert len(resp.json['features']) == 0
def test_backoffice_handling(pub):
create_user(pub)
create_environment(pub)
form_class = FormDef.get_by_urlname('form-title').data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/')
assert re.findall(r'<tbody.*\/tbody>', resp.text, re.DOTALL)[0].count('<tr') == 17
# check sidebar links are ok
assert 'Statistics' in resp.text
assert 'Export' in resp.text
app.get('/backoffice/management/form-title/stats', status=200)
app.get('/backoffice/management/form-title/csv', status=200)
app.get('/backoffice/management/form-title/ods', status=200)
app.get('/backoffice/management/form-title/json', status=200)
# click on a formdata
resp = resp.click(href='%s/' % number31.id)
assert (' with the number %s.' % number31.get_display_id()) in resp.text
resp.forms[0]['comment'] = 'HELLO WORLD'
resp = resp.forms[0].submit('button_accept')
resp = resp.follow()
assert FormDef.get_by_urlname('form-title').data_class().get(number31.id).status == 'wf-accepted'
assert 'HELLO WORLD' in resp.text
def test_backoffice_handling_global_action(pub):
create_user(pub)
formdef = FormDef()
formdef.name = 'test global action'
formdef.fields = []
workflow = Workflow.get_default_workflow()
workflow.id = '2'
action = workflow.add_global_action('FOOBAR')
register_comment = action.add_action('register-comment')
register_comment.comment = 'HELLO WORLD GLOBAL ACTION'
jump = action.add_action('jump')
jump.status = 'finished'
trigger = action.triggers[0]
trigger.roles = [x.id for x in pub.role_class.select() if x.name == 'foobar']
workflow.store()
formdef.workflow_id = workflow.id
formdef.workflow_roles = {'_receiver': 1}
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/%s/%s/' % (formdef.url_name, formdata.id))
assert 'button-action-1' in resp.form.fields
resp = resp.form.submit('button-action-1')
resp = app.get('/backoffice/management/%s/%s/' % (formdef.url_name, formdata.id))
assert 'HELLO WORLD GLOBAL ACTION' in resp.text
assert formdef.data_class().get(formdata.id).status == 'wf-finished'
def test_backoffice_global_remove_action(pub):
create_user(pub)
formdef = FormDef()
formdef.name = 'test global remove'
formdef.fields = []
workflow = Workflow.get_default_workflow()
workflow.id = '2'
action = workflow.add_global_action('FOOBAR')
action.add_action('remove')
trigger = action.triggers[0]
trigger.roles = [x.id for x in pub.role_class.select() if x.name == 'foobar']
workflow.store()
formdef.workflow_id = workflow.id
formdef.workflow_roles = {'_receiver': 1}
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/%s/%s/' % (formdef.url_name, formdata.id))
assert 'remove' in resp.text
assert 'button-action-1' in resp.form.fields
resp = resp.form.submit('button-action-1')
resp = resp.follow()
assert resp.request.url == 'http://example.net/backoffice/management/test-global-remove/'
assert 'The form has been deleted.' in resp.text
def test_backoffice_global_action_jump_to_current_status(pub):
create_user(pub)
formdef = FormDef()
formdef.name = 'test jump to current status'
formdef.fields = []
workflow = Workflow()
st1 = workflow.add_status('Status1')
register_comment = st1.add_action('register-comment', id='_comment')
register_comment.comment = '<p>WORKFLOW COMMENT</p>'
action = workflow.add_global_action('FOOBAR')
action.add_action('jump')
action.items[0].status = st1.id
trigger = action.triggers[0]
trigger.roles = [x.id for x in pub.role_class.select() if x.name == 'foobar']
workflow.store()
formdef.workflow_id = workflow.id
formdef.workflow_roles = {'_receiver': 1}
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.perform_workflow()
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/%s/%s/' % (formdef.url_name, formdata.id))
assert resp.text.count('WORKFLOW COMMENT') == 1
assert 'button-action-1' in resp.form.fields
resp = resp.form.submit('button-action-1')
resp = resp.follow()
assert resp.text.count('WORKFLOW COMMENT') == 2
def test_backoffice_submission_context(pub):
user = create_user(pub)
create_environment(pub)
form_class = FormDef.get_by_urlname('form-title').data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/')
assert re.findall(r'<tbody.*\/tbody>', resp.text, re.DOTALL)[0].count('<tr') == 17
# click on a formdata
resp = resp.click(href='%s/' % number31.id)
assert (' with the number %s.' % number31.get_display_id()) in resp.text
# check there's nothing in the sidebar
assert 'Channel' not in resp.text
number31.submission_channel = 'mail'
number31.user_id = user.id
number31.submission_context = {
'mail_url': 'http://www.example.com/test.pdf',
'thumbnail_url': 'http://www.example.com/thumbnail.png',
'comments': 'test_backoffice_submission_context',
'summary_url': 'http://www.example.com/summary',
}
number31.submission_agent_id = str(user.id)
number31.store()
resp = app.get('/backoffice/management/form-title/')
resp = resp.click(href='%s/' % number31.id)
assert 'Channel' in resp.text
assert 'http://www.example.com/thumbnail.png' in resp.text
assert 'http://www.example.com/test.pdf' in resp.text
assert 'Associated User' in resp.text
assert 'test_backoffice_submission_context' in resp.text
assert 'http://www.example.com/summary' in resp.text
assert 'by %s' % user.get_display_name() in resp.text
def test_backoffice_download_as_zip(pub):
create_user(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
formdef.fields.append(fields.FileField(id='4', label='file1 field', type='file'))
formdef.fields.append(fields.FileField(id='5', label='file2 field', type='file2'))
formdef.store()
number31 = [x for x in formdef.data_class().select() if x.data['1'] == 'FOO BAR 30'][0]
number31.data['4'] = PicklableUpload('/foo/bar', content_type='text/plain')
number31.data['4'].receive([b'hello world'])
number31.data['5'] = PicklableUpload('/foo/bar', content_type='text/plain')
number31.data['5'].receive([b'hello world2'])
number31.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert 'Download all files as .zip' not in resp
formdef.include_download_all_button = True
formdef.store()
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
resp = resp.click('Download all files as .zip')
zip_content = io.BytesIO(resp.body)
with zipfile.ZipFile(zip_content, 'a') as zipf:
filelist = zipf.namelist()
assert set(filelist) == {'1_bar', '2_bar'}
for zipinfo in zipf.infolist():
content = zipf.read(zipinfo)
if zipinfo.filename == '1_bar':
assert content == b'hello world'
elif zipinfo.filename == '2_bar':
assert content == b'hello world2'
else:
assert False # unknown zip part
def test_backoffice_sidebar_user_template(pub):
user = create_user(pub)
create_environment(pub)
form_class = FormDef.get_by_urlname('form-title').data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
number31.user_id = user.id
number31.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/')
resp = resp.click(href='%s/' % number31.id)
assert 'Associated User' in resp.text
assert '<p>admin</p>' in resp.text
pub.cfg['users'] = {'sidebar_template': 'XXX{{ form_user_display_name }}YYY'}
pub.write_cfg()
resp = app.get(resp.request.url)
assert '<p>XXXadminYYY</p>' in resp.text
pub.cfg['users'] = {'sidebar_template': 'XXX<b>{{ form_user_display_name }}</b>YYY'}
pub.write_cfg()
resp = app.get(resp.request.url)
assert '<p>XXX<b>admin</b>YYY</p>' in resp.text
user.name = 'adm<i>n'
user.store()
resp = app.get(resp.request.url)
assert '<p>XXX<b>adm&lt;i&gt;n</b>YYY</p>' in resp.text
def test_backoffice_geolocation_info(pub):
create_user(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
formdef.geolocations = {'base': 'Geolocafoobar'}
formdef.store()
form_class = FormDef.get_by_urlname('form-title').data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/')
assert re.findall(r'<tbody.*\/tbody>', resp.text, re.DOTALL)[0].count('<tr') == 17
# click on a formdata
resp = resp.click(href='%s/' % number31.id)
assert (' with the number %s.' % number31.get_display_id()) in resp.text
# check there's nothing in the sidebar
assert 'Geolocation' not in resp.text
number31.geolocations = {'base': {'lat': 48.83, 'lon': 2.32}}
number31.store()
resp = app.get('/backoffice/management/form-title/')
resp = resp.click(href='%s/' % number31.id)
assert 'Geolocafoobar' in resp.text
assert 'class="qommon-map"' in resp.text
assert 'data-init-lng="2.32"' in resp.text
assert 'data-init-lat="48.83' in resp.text
def test_backoffice_info_text(pub):
create_user(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
form_class = formdef.data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
# attach a custom workflow
workflow = Workflow(name='info texts')
st1 = workflow.add_status('Status1', number31.status.split('-')[1])
commentable = st1.add_action('commentable', id='_commentable')
commentable.by = ['_submitter', '_receiver']
commentable.button_label = 'CLICK ME!'
commentable2 = st1.add_action('commentable', id='_commentable2')
commentable2.by = ['_submitter']
commentable2.button_label = 'CLICK ME2!'
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert (' with the number %s.' % number31.get_display_id()) in resp.text
assert 'CLICK ME!' in resp.text
assert 'CLICK ME2!' not in resp.text
assert 'backoffice-description' not in resp.text
# add an info text to the status
st1.backoffice_info_text = '<p>Foo</p>'
workflow.store()
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert 'backoffice-description' in resp.text
assert '<p>Foo</p>' in resp.text
# add an info text to the button
commentable.backoffice_info_text = '<p>Bar</p>'
workflow.store()
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert 'backoffice-description' in resp.text
assert '<p>Foo</p>' in resp.text
assert '<p>Bar</p>' in resp.text
# info text is not visible if form is locked
second_user = pub.user_class(name='foobar')
second_user.roles = pub.role_class.keys()
second_user.store()
account = PasswordAccount(id='foobar')
account.set_password('foobar')
account.user_id = second_user.id
account.store()
app2 = login(get_app(pub), username='foobar', password='foobar')
resp = app2.get('/backoffice/management/form-title/%s/' % number31.id)
assert 'Be warned forms of this user are also being looked' in resp.text
assert 'backoffice-description' not in resp.text
assert 'CLICK ME!' not in resp.text
assert 'CLICK ME2!' not in resp.text
# remove info text from the status
st1.backoffice_info_text = None
workflow.store()
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert 'backoffice-description' in resp.text
assert '<p>Foo</p>' not in resp.text
assert '<p>Bar</p>' in resp.text
# add info text to second button
commentable2.backoffice_info_text = '<p>Baz</p>'
workflow.store()
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert 'backoffice-description' in resp.text
assert '<p>Foo</p>' not in resp.text
assert '<p>Bar</p>' in resp.text
assert '<p>Baz</p>' not in resp.text
# remove info text from first button
commentable.backoffice_info_text = None
workflow.store()
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert 'backoffice-description' not in resp.text
def test_backoffice_handling_post_dispatch(pub):
# check a formdata that has been dispatched to another role is accessible
# by an user with that role.
user1 = create_user(pub)
role = pub.role_class(name='foobaz')
role.store()
user1.roles = [role.id]
user1.store()
create_environment(pub)
form_class = FormDef.get_by_urlname('form-title').data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
app = login(get_app(pub))
# check there's no access at the moment
resp = app.get('/backoffice/management/').follow()
assert 'form-title/' not in resp.text
resp = app.get('/backoffice/management/form-title/', status=403)
resp = app.get('/backoffice/management/form-title/%s/' % number31.id, status=403)
# emulate a dispatch (setting formdata.workflow_roles), receiver of that
# formdata is now the local role we gave to the user.
formdata31 = form_class.get(number31.id)
formdata31.workflow_roles = {'_receiver': [role.id]}
formdata31.store()
# check listing is accessible, with a single item
resp = app.get('/backoffice/management/').follow()
assert 'form-title/' in resp.text
resp = app.get('/backoffice/management/form-title/', status=200)
assert re.findall(r'<tbody.*\/tbody>', resp.text, re.DOTALL)[0].count('<tr') == 1
# check statistics and exports are also available
assert 'Statistics' in resp.text
assert 'Export' in resp.text
app.get('/backoffice/management/form-title/stats', status=200)
app.get('/backoffice/management/form-title/csv', status=200)
app.get('/backoffice/management/form-title/ods', status=200)
app.get('/backoffice/management/form-title/json', status=200)
# check formdata is accessible, and that it's possible to perform an action
# on it.
resp = resp.click(href='%s/' % number31.id)
assert (' with the number %s.' % number31.get_display_id()) in resp.text
resp.forms[0]['comment'] = 'HELLO WORLD'
resp = resp.forms[0].submit('button_accept')
resp = resp.follow()
assert FormDef.get_by_urlname('form-title').data_class().get(number31.id).status == 'wf-accepted'
assert 'HELLO WORLD' in resp.text
def test_backoffice_wscall_failure_display(http_requests, pub):
user = create_user(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
form_class = formdef.data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
# attach a custom workflow
workflow = Workflow(name='wscall')
st1 = workflow.add_status('Status1', number31.status.split('-')[1])
wscall = st1.add_action('webservice_call', id='_wscall')
wscall.varname = 'xxx'
wscall.url = 'http://remote.example.net/xml'
wscall.action_on_bad_data = ':stop'
wscall.record_errors = True
again = st1.add_action('choice', id='_again')
again.label = 'Again'
again.by = ['_receiver']
again.status = st1.id
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert (' with the number %s.' % number31.get_display_id()) in resp.text
assert 'Again' in resp.text
resp = resp.forms[0].submit('button_again')
resp = resp.follow()
assert 'Error during webservice call' in resp.text
number31.user_id = user.id # change ownership to stay in frontoffice
number31.store()
# the failure message shouldn't be displayed in the frontoffice
resp = app.get('/form-title/%s/' % number31.id)
assert (' with the number %s.' % number31.get_display_id()) in resp.text
assert 'Error during webservice call' not in resp.text
@pytest.mark.parametrize('notify_on_errors', [True, False])
@pytest.mark.parametrize('record_on_errors', [True, False])
def test_backoffice_wscall_on_error(http_requests, pub, emails, notify_on_errors, record_on_errors):
pub.cfg['debug'] = {'error_email': 'errors@localhost.invalid'}
pub.cfg['emails'] = {'from': 'from@localhost.invalid'}
pub.write_cfg()
create_user(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
form_class = formdef.data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
# attach a custom workflow
workflow = Workflow(name='wscall')
st1 = workflow.add_status('Status1', number31.status.split('-')[1])
wscall = st1.add_action('webservice_call', id='_wscall')
wscall.varname = 'xxx'
wscall.url = 'http://remote.example.net/xml'
wscall.action_on_bad_data = ':stop'
wscall.notify_on_errors = notify_on_errors
wscall.record_on_errors = record_on_errors
wscall.record_errors = True
again = st1.add_action('choice', id='_again')
again.label = 'Again'
again.by = ['_receiver']
again.status = st1.id
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert (' with the number %s.' % number31.get_display_id()) in resp.text
assert 'Again' in resp.text
resp = resp.forms[0].submit('button_again')
resp = resp.follow()
assert 'Error during webservice call' in resp.text
# check email box
if notify_on_errors:
assert emails.count() == 1
error_email = emails.get(
'[ERROR] [WSCALL] json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)'
)
assert '/form-title/%s/' % number31.id in error_email['payload']
assert error_email['from'] == 'from@localhost.invalid'
assert error_email['email_rcpt'] == ['errors@localhost.invalid']
if record_on_errors:
assert error_email['msg']['References']
else:
assert emails.count() == 0
# check pub.loggederror_class
if record_on_errors:
assert pub.loggederror_class.count() == 1
else:
assert pub.loggederror_class.count() == 0
def test_backoffice_wscall_attachment(http_requests, pub):
create_user(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
form_class = formdef.data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
# attach a custom workflow
workflow = Workflow(name='wscall')
workflow.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(workflow)
workflow.backoffice_fields_formdef.fields = [
fields.FileField(id='bo1', label='bo field 1', type='file'),
]
st1 = workflow.add_status('Status1', number31.status.split('-')[1])
wscall = st1.add_action('webservice_call', id='_wscall')
wscall.varname = 'xxx'
wscall.response_type = 'attachment'
wscall.backoffice_filefield_id = 'bo1'
wscall.url = 'http://remote.example.net/xml'
wscall.action_on_bad_data = ':stop'
wscall.record_errors = True
again = st1.add_action('choice', id='_again')
again.label = 'Again'
again.by = ['_receiver']
again.status = st1.id
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert (' with the number %s.' % number31.get_display_id()) in resp.text
assert 'Again' in resp.text
resp = resp.forms[0].submit('button_again')
resp = resp.follow()
# get the two generated files from backoffice: in backoffice fields
# (wscall.backoffice_filefield_id), and in history
for index in (0, 1):
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
resp = resp.click('xxx.xml', index=index)
assert resp.location.endswith('/xxx.xml')
resp = resp.follow()
assert resp.content_type == 'text/xml'
assert resp.text == '<?xml version="1.0"><foo/>'
formdata = formdef.data_class().get(number31.id)
assert formdata.evolution[-1].parts[0].orig_filename == 'xxx.xml'
assert formdata.evolution[-1].parts[0].content_type == 'text/xml'
assert formdata.get_substitution_variables()['attachments'].xxx.filename == 'xxx.xml'
resp = app.get(formdata.get_substitution_variables()['attachments'].xxx.url)
resp = resp.follow()
assert resp.text == '<?xml version="1.0"><foo/>'
def test_backoffice_wfedit(pub):
user = create_user(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
form_class = formdef.data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
number31.submission_channel = 'mail'
number31.submission_context = {
'mail_url': 'http://www.example.com/test.pdf',
}
number31.store()
# attach a custom workflow
workflow = Workflow(name='wfedit')
st1 = workflow.add_status('Status1', number31.status.split('-')[1])
wfedit = st1.add_action('editable', id='_wfedit')
wfedit.by = [user.roles[0]]
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert (' with the number %s.' % number31.get_display_id()) in resp.text
assert len(form_class().get(number31.id).evolution) == 2 # (just submitted, new)
resp = resp.form.submit('button_wfedit')
resp = resp.follow()
assert 'http://www.example.com/test.pdf' in resp.text # make sure sidebar has details
assert 'Tracking Code' not in resp.text # make sure it doesn't display a tracking code
assert resp.form['f1'].value == number31.data['1']
assert resp.form['f2'].value == number31.data['2']
assert resp.form['f3'].value == number31.data['3']
assert 'value="Save Changes"' in resp.text
resp.form['f2'].value = 'bar'
resp = resp.form.submit('submit')
resp = resp.follow()
assert form_class().get(number31.id).data['2'] == 'bar'
assert len(form_class().get(number31.id).evolution) == 3
assert form_class().get(number31.id).evolution[-1].who == str(user.id)
number31.store()
def test_backoffice_wfedit_disabled(pub):
user = create_user(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
form_class = formdef.data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
number31.submission_context = {
'mail_url': 'http://www.example.com/test.pdf',
}
number31.store()
# attach a custom workflow
workflow = Workflow(name='wfedit')
st1 = workflow.add_status('Status1', number31.status.split('-')[1])
wfedit = st1.add_action('editable', id='_wfedit')
wfedit.by = [user.roles[0]]
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
app = login(get_app(pub))
formdef.disabled = True
formdef.store()
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
resp = resp.form.submit('button_wfedit')
resp = resp.follow()
resp.form['f2'].value = 'bar'
resp = resp.form.submit('submit')
resp = resp.follow()
assert form_class().get(number31.id).data['2'] == 'bar'
def test_backoffice_wfedit_submission(pub):
user = create_user(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
formdef.backoffice_submission_roles = user.roles[:]
formdef.enable_tracking_codes = True
formdef.fields.insert(0, fields.PageField(id='0', label='1st page', type='page'))
formdef.fields.append(fields.PageField(id='4', label='2nd page', type='page'))
formdef.store()
form_class = formdef.data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
number31.backoffice_submission = True
number31.store()
formdata_count = form_class.count()
# attach a custom workflow
workflow = Workflow(name='wfedit')
st1 = workflow.add_status('Status1', number31.status.split('-')[1])
wfedit = st1.add_action('editable', id='_wfedit')
wfedit.by = [user.roles[0]]
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert (' with the number %s.' % number31.get_display_id()) in resp.text
resp = resp.form.submit('button_wfedit')
resp = resp.follow()
assert resp.form['f1'].value == number31.data['1']
assert resp.form['f2'].value == number31.data['2']
assert resp.form['f3'].value == number31.data['3']
resp.form['f2'].value = 'bar'
resp = resp.form.submit('submit')
assert 'value="Save Changes"' in resp.text
resp = resp.form.submit('submit')
resp = resp.follow()
assert form_class().get(number31.id).data['2'] == 'bar'
number31.store()
assert formdata_count == form_class.count()
def test_backoffice_wfedit_and_required_comment(pub):
user = create_user(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
form_class = formdef.data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
# attach a custom workflow
workflow = Workflow(name='wfedit')
st1 = workflow.add_status('Status1', number31.status.split('-')[1])
commentable = st1.add_action('commentable', id='_commentable')
commentable.by = [user.roles[0]]
commentable.button_label = 'CLICK ME!'
commentable.required = True
wfedit = st1.add_action('editable', id='_wfedit')
wfedit.by = [user.roles[0]]
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
app = login(get_app(pub))
# check a click goes to edition, not blocked by required comment field.
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
resp = resp.form.submit('button_wfedit')
resp = resp.follow()
resp.form['f2'].value = 'bar'
def test_backoffice_wfedit_and_backoffice_fields(pub):
user = create_user(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
form_class = formdef.data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
# attach a custom workflow
workflow = Workflow(name='wfedit')
workflow.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(workflow)
workflow.backoffice_fields_formdef.fields = [
fields.StringField(
id='bo1', label='1st backoffice field', type='string', varname='backoffice_blah', required=False
),
]
st1 = workflow.add_status('Status1', number31.status.split('-')[1])
wfedit = st1.add_action('editable', id='_wfedit')
wfedit.by = [user.roles[0]]
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
number31 = form_class().get(number31.id)
number31.data['bo1'] = 'plop'
number31.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
resp = resp.form.submit('button_wfedit')
resp = resp.follow()
resp.form['f2'].value = 'bar'
resp = resp.form.submit('submit')
resp = resp.follow()
assert form_class().get(number31.id).data['bo1'] == 'plop'
def test_backoffice_wfedit_and_data_source_with_user_info(pub):
user = create_user(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
formdef.fields[2].data_source = {
'type': 'json',
'value': 'https://www.example.invalid/?name_id={% firstof form_user_display_name "XXX" %}',
}
formdef.store()
form_class = formdef.data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
# attach a custom workflow
workflow = Workflow(name='wfedit')
st1 = workflow.add_status('Status1', number31.status.split('-')[1])
wfedit = st1.add_action('editable', id='_wfedit')
wfedit.by = [user.roles[0]]
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
number31 = form_class().get(number31.id)
number31.user_id = user.id
number31.store()
app = login(get_app(pub))
with mock.patch('wcs.qommon.misc.urlopen') as urlopen:
data = {'data': [{'id': 'A', 'text': 'hello'}, {'id': 'B', 'text': 'world'}]}
def side_effect(url, *args):
assert '?name_id=admin' in url
return io.StringIO(json.dumps(data))
urlopen.side_effect = side_effect
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
resp = resp.form.submit('button_wfedit')
resp = resp.follow()
assert urlopen.call_count == 1
resp.form['f3'].value = 'A'
resp = resp.form.submit('submit')
assert urlopen.call_count == 2
resp = resp.follow()
def test_backoffice_wfedit_and_workflow_data(pub):
user = create_user(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
formdef.fields[2].data_source = {
'type': 'json',
'value': 'https://www.example.invalid/?test={% firstof some_workflow_data "XXX" %}',
}
formdef.store()
form_class = formdef.data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
# attach a custom workflow
workflow = Workflow(name='wfedit')
st1 = workflow.add_status('Status1', number31.status.split('-')[1])
wfedit = st1.add_action('editable', id='_wfedit')
wfedit.by = [user.roles[0]]
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
number31 = form_class().get(number31.id)
number31.workflow_data = {'some_workflow_data': 'foobar'}
number31.store()
app = login(get_app(pub))
with mock.patch('wcs.qommon.misc.urlopen') as urlopen:
data = {'data': [{'id': 'A', 'text': 'hello'}, {'id': 'B', 'text': 'world'}]}
def side_effect(url, *args):
assert '?test=foobar' in url
return io.StringIO(json.dumps(data))
urlopen.side_effect = side_effect
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
resp = resp.form.submit('button_wfedit')
resp = resp.follow()
assert urlopen.call_count == 1
resp.form['f3'].value = 'A'
resp = resp.form.submit('submit')
assert urlopen.call_count == 2
resp = resp.follow()
def test_backoffice_wfedit_and_data_source_with_field_info(pub):
user = create_user(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
formdef.fields[0].varname = 'bar'
formdef.fields[2].data_source = {
'type': 'json',
'value': 'https://www.example.invalid/?xxx={{ form_var_bar }}',
}
formdef.store()
form_class = formdef.data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
# attach a custom workflow
workflow = Workflow(name='wfedit')
st1 = workflow.add_status('Status1', number31.status.split('-')[1])
wfedit = st1.add_action('editable', id='_wfedit')
wfedit.by = [user.roles[0]]
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
number31 = form_class().get(number31.id)
number31.data['3'] = 'EE'
number31.data['3_display'] = 'EE'
number31.store()
app = login(get_app(pub))
with mock.patch('wcs.qommon.misc.urlopen') as urlopen:
data = {'data': [{'id': 'DD', 'text': 'DD'}, {'id': 'EE', 'text': 'EE'}]}
def side_effect(url, *args):
assert '?xxx=FOO BAR 30' in url
return io.StringIO(json.dumps(data))
urlopen.side_effect = side_effect
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
resp = resp.form.submit('button_wfedit')
resp = resp.follow()
assert urlopen.call_count == 1
assert 'invalid value' not in resp
assert resp.form['f3'].value == 'EE'
resp.form['f3'].value = 'DD'
resp = resp.form.submit('submit')
assert urlopen.call_count == 2
resp = resp.follow()
def test_backoffice_wfedit_and_user_selection(pub):
user = create_user(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
form_class = formdef.data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
number31.store()
# attach a custom workflow
workflow = Workflow(name='wfedit')
st1 = workflow.add_status('Status1', number31.status.split('-')[1])
wfedit = st1.add_action('editable', id='_wfedit')
wfedit.by = [user.roles[0]]
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert (' with the number %s.' % number31.get_display_id()) in resp.text
assert 'Associated User' not in resp
resp = resp.form.submit('button_wfedit')
resp = resp.follow()
assert resp.pyquery('.submit-user-selection')
resp.form['user_id'] = str(user.id) # happens via javascript
resp = resp.form.submit('submit')
resp = resp.follow()
assert 'Associated User' in resp
assert formdef.data_class().get(number31.id).user_id == str(user.id)
def test_backoffice_wfedit_and_user_selection_multi_page(pub):
user = create_user(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
formdef.fields.insert(0, fields.PageField(id='0', label='1st page', type='page'))
formdef.fields.append(fields.PageField(id='4', label='2nd page', type='page'))
form_class = formdef.data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
number31.store()
# attach a custom workflow
workflow = Workflow(name='wfedit')
st1 = workflow.add_status('Status1', number31.status.split('-')[1])
wfedit = st1.add_action('editable', id='_wfedit')
wfedit.by = [user.roles[0]]
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert (' with the number %s.' % number31.get_display_id()) in resp.text
assert 'Associated User' not in resp
resp = resp.form.submit('button_wfedit')
resp = resp.follow()
assert resp.pyquery('.submit-user-selection')
resp.form['user_id'] = str(user.id) # happens via javascript
resp = resp.form.submit('submit') # -> 2nd page
assert resp.pyquery('.submit-user-selection')
resp = resp.form.submit('submit') # -> save changes
resp = resp.follow()
assert 'Associated User' in resp
assert formdef.data_class().get(number31.id).user_id == str(user.id)
number31.store() # save and lose associated user id
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert (' with the number %s.' % number31.get_display_id()) in resp.text
assert 'Associated User' not in resp
resp = resp.form.submit('button_wfedit')
resp = resp.follow()
assert resp.pyquery('.submit-user-selection')
resp = resp.form.submit('submit') # -> 2nd page
assert resp.pyquery('.submit-user-selection')
resp.form['user_id'] = str(user.id) # happens via javascript
resp = resp.form.submit('submit') # -> save changes
resp = resp.follow()
assert 'Associated User' in resp
assert formdef.data_class().get(number31.id).user_id == str(user.id)
def test_backoffice_wfedit_and_live_condition(pub):
user = create_user(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
formdef.fields[0].varname = 'foo'
formdef.fields[1].condition = {'type': 'django', 'value': 'form_var_foo == "test"'}
form_class = formdef.data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
# attach a custom workflow
workflow = Workflow(name='wfedit')
st1 = workflow.add_status('Status1', number31.status.split('-')[1])
wfedit = st1.add_action('editable', id='_wfedit')
wfedit.by = [user.roles[0]]
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
resp = resp.form.submit('button_wfedit').follow()
live_url = resp.html.find('form').attrs['data-live-url']
live_resp = app.post(live_url, params=resp.form.submit_fields())
assert live_resp.json['result']['1']['visible']
assert not live_resp.json['result']['2']['visible']
resp.form['f1'].value = 'test'
live_resp = app.post(live_url, params=resp.form.submit_fields())
assert live_resp.json['result']['1']['visible']
assert live_resp.json['result']['2']['visible']
def test_global_listing(pub):
create_user(pub)
create_environment(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/management/').follow()
assert 'Global View' in resp.text
resp = resp.click('Global View')
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 20
assert 'Map View' not in resp.text
resp = app.get('/backoffice/management/listing?limit=500')
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 37 # 17 formdef1 + 20 formdef2
resp = app.get('/backoffice/management/listing?offset=20&limit=20')
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 17
# try an overbound offset
resp = app.get('/backoffice/management/listing?offset=40&limit=20')
resp = resp.follow()
assert resp.forms['listing-settings']['offset'].value == '0'
resp = app.get('/backoffice/management/listing')
resp.forms['listing-settings']['end'] = '2014-02-01'
resp = resp.forms['listing-settings'].submit()
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 20
assert 'http://example.net/backoffice/management/other-form/' in resp.text
assert 'http://example.net/backoffice/management/form-title/' not in resp.text
formdef = FormDef.get_by_urlname('form-title')
last_update_time = formdef.data_class().select(lambda x: not x.is_draft())[0].last_update_time
# check created and last modified columns
assert '>2014-01-01 00:00<' in resp.text
assert time.strftime('>%Y-%m-%d', last_update_time) in resp.text
# check digest is included
formdata = formdef.data_class().get(
re.findall(r'data-link="(.*?)"', app.get('/backoffice/management/listing').text)[0].split('/')[-2]
)
formdata.formdef.digest_templates = {'default': 'digest of number <{{form_number}}>'}
formdata.store()
assert formdata.get(formdata.id).digests['default']
resp = app.get('/backoffice/management/listing')
assert formdata.get_url(backoffice=True) in resp.text
assert 'digest of number &lt;%s&gt;' % formdata.id_display in resp.text
# check a Channel column is added when welco is available
assert 'Channel' not in resp.text
if not pub.site_options.has_section('variables'):
pub.site_options.add_section('variables')
pub.site_options.set('variables', 'welco_url', 'xxx')
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
pub.site_options.write(fd)
resp = app.get('/backoffice/management/listing?limit=500')
formdata = formdef.data_class().select(lambda x: x.status == 'wf-new')[0]
formdata.submission_channel = 'mail'
formdata.store()
assert 'Channel' in resp.text
assert '>Web<' in resp.text
resp.forms['listing-settings']['submission_channel'] = 'web'
resp = resp.forms['listing-settings'].submit()
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 36
resp.forms['listing-settings']['submission_channel'] = 'mail'
resp = resp.forms['listing-settings'].submit()
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 1
resp = app.get('/backoffice/management/listing?limit=500')
resp.forms['listing-settings']['q'] = 'foo'
resp = resp.forms['listing-settings'].submit()
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 17
resp = app.get('/backoffice/management/listing?limit=500')
resp.forms['listing-settings']['status'] = 'waiting'
resp = resp.forms['listing-settings'].submit()
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 37
resp.forms['listing-settings']['status'] = 'open'
resp = resp.forms['listing-settings'].submit()
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 37
resp.forms['listing-settings']['status'] = 'all'
resp = resp.forms['listing-settings'].submit()
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 70
resp.forms['listing-settings']['status'] = 'done'
resp = resp.forms['listing-settings'].submit()
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 33
# change role handling a formdef, make sure they do not appear anylonger in
# the all/done views.
role = pub.role_class(name='whatever')
role.store()
formdef = FormDef.get_by_urlname('form-title')
formdef.workflow_roles = {'_receiver': role.id}
formdef.store()
formdef.data_class().rebuild_security()
resp = app.get('/backoffice/management/listing?limit=500')
resp.forms['listing-settings']['status'] = 'waiting'
resp = resp.forms['listing-settings'].submit()
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 20
assert 'form-title' not in resp.text
resp.forms['listing-settings']['status'] = 'open'
resp = resp.forms['listing-settings'].submit()
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 20
assert 'form-title' not in resp.text
resp.forms['listing-settings']['status'] = 'all'
resp = resp.forms['listing-settings'].submit()
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 20
assert 'form-title' not in resp.text
resp.forms['listing-settings']['status'] = 'done'
resp = resp.forms['listing-settings'].submit()
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 0
assert 'form-title' not in resp.text
def test_global_listing_parameters_from_query_string(pub):
create_user(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.workflow_roles = {'_receiver': 1}
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/listing')
assert resp.forms['listing-settings']['status'].value == 'waiting'
assert resp.forms['listing-settings']['limit'].value == '20'
resp = app.get('/backoffice/management/listing?status=done')
assert resp.forms['listing-settings']['status'].value == 'done'
assert resp.forms['listing-settings']['limit'].value == '20'
resp = app.get('/backoffice/management/listing?status=done&limit=50')
assert resp.forms['listing-settings']['status'].value == 'done'
assert resp.forms['listing-settings']['limit'].value == '50'
resp = app.get('/backoffice/management/listing?status=done&limit=50&q=test')
assert resp.forms['listing-settings']['status'].value == 'done'
assert resp.forms['listing-settings']['limit'].value == '50'
assert resp.forms['listing-settings']['q'].value == 'test'
def test_global_listing_user_label(pub):
create_user(pub)
FormDef.wipe()
from wcs.admin.settings import UserFieldsFormDef
user_formdef = UserFieldsFormDef(pub)
user_formdef.fields.append(fields.StringField(id='3', label='first_name', type='string'))
user_formdef.fields.append(fields.StringField(id='4', label='last_name', type='string'))
user_formdef.store()
pub.cfg['users']['field_name'] = ['3', '4']
pub.write_cfg()
formdef = FormDef()
formdef.name = 'foobar'
formdef.url_name = 'foobar'
formdef.workflow_roles = {'_receiver': 1}
formdef.fields = [
fields.StringField(id='1', label='first_name', prefill={'type': 'user', 'value': '3'}),
fields.StringField(id='2', label='last_name', prefill={'type': 'user', 'value': '4'}),
]
formdef.store()
formdata = formdef.data_class()()
formdata.data = {'1': 'blah', '2': 'xxx'}
formdata.just_created()
formdata.store()
formdata.jump_status('new')
app = login(get_app(pub))
resp = app.get('/backoffice/management/').follow()
resp = resp.click('Global View')
assert '<td class="cell-user">blah xxx</td>' in resp.text
def test_management_views_with_no_formdefs(pub):
create_user(pub)
FormDef.wipe()
from wcs.sql import drop_global_views, get_connection_and_cursor
conn, cur = get_connection_and_cursor()
drop_global_views(conn, cur)
conn.commit()
cur.close()
app = login(get_app(pub))
resp = app.get('/backoffice/management/forms')
assert 'This site is currently empty.' in resp.text
resp = app.get('/backoffice/management/listing')
assert 'This site is currently empty.' in resp.text
def test_category_in_global_listing(pub):
FormDef.wipe()
Category.wipe()
create_user(pub)
formdef = FormDef()
formdef.name = 'form-3'
formdef.workflow_roles = {'_receiver': 1}
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.jump_status('new')
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/listing?limit=500')
assert 'category_ids$element0' not in resp.forms['listing-settings'].fields
cat1 = Category(name='cat1')
cat1.position = 1
cat1.store()
formdef = FormDef()
formdef.name = 'form-1'
formdef.category_id = cat1.id
formdef.workflow_roles = {'_receiver': 1}
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.jump_status('new')
formdata.store()
cat2 = Category(name='cat2')
cat1.position = 2
cat2.store()
formdef = FormDef()
formdef.name = 'form-2'
formdef.category_id = cat2.id
formdef.workflow_roles = {'_receiver': 1}
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.jump_status('new')
formdata.store()
resp = app.get('/backoffice/management/listing')
assert 'category_ids$element0' in resp.forms['listing-settings'].fields
assert 'management/form-1/' in resp.text
assert 'management/form-2/' in resp.text
assert 'management/form-3/' in resp.text
resp.forms['listing-settings']['category_ids$element0'] = cat1.id
resp = resp.forms['listing-settings'].submit()
assert 'management/form-1/' in resp.text
assert 'management/form-2/' not in resp.text
assert 'management/form-3/' not in resp.text
resp.forms['listing-settings']['category_ids$element0'] = cat2.id
resp = resp.forms['listing-settings'].submit()
assert 'management/form-1/' not in resp.text
assert 'management/form-2/' in resp.text
assert 'management/form-3/' not in resp.text
resp = resp.forms['listing-settings'].submit('category_ids$add_element')
resp.forms['listing-settings']['category_ids$element0'] = cat1.id
resp.forms['listing-settings']['category_ids$element1'] = cat2.id
resp = resp.forms['listing-settings'].submit()
assert 'management/form-1/' in resp.text
assert 'management/form-2/' in resp.text
assert 'management/form-3/' not in resp.text
resp = app.get('/backoffice/management/listing?category_slugs=cat1')
assert resp.forms['listing-settings']['category_ids$element0'].value == cat1.id
assert 'category_ids$element1' not in resp.forms['listing-settings'].fields
assert 'management/form-1/' in resp.text
assert 'management/form-2/' not in resp.text
assert 'management/form-3/' not in resp.text
resp = app.get('/backoffice/management/listing?category_slugs=cat1,cat2')
assert resp.forms['listing-settings']['category_ids$element0'].value == cat1.id
assert resp.forms['listing-settings']['category_ids$element1'].value == cat2.id
assert 'management/form-1/' in resp.text
assert 'management/form-2/' in resp.text
assert 'management/form-3/' not in resp.text
def test_datetime_in_global_listing(pub):
create_user(pub)
create_environment(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/management/listing?limit=500')
resp.forms['listing-settings']['end'] = '01/01/2010'
resp = resp.forms['listing-settings'].submit()
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 0
resp = app.get('/backoffice/management/listing?limit=500')
resp.forms['listing-settings']['start'] = '01/01/2010'
resp = resp.forms['listing-settings'].submit()
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 37
resp.forms['listing-settings']['start'] = '01/01/2016'
resp = resp.forms['listing-settings'].submit()
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 0
resp.forms['listing-settings']['start'] = '01/01/16'
resp = resp.forms['listing-settings'].submit()
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 0
resp.forms['listing-settings']['start'] = '01/01/10'
resp = resp.forms['listing-settings'].submit()
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 37
resp.forms['listing-settings']['end'] = '01/01/10'
resp = resp.forms['listing-settings'].submit()
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 0
# check invalid values are simply ignored
resp.forms['listing-settings']['end'] = 'whatever'
resp = resp.forms['listing-settings'].submit()
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 37
def test_global_listing_anonymised(pub):
create_user(pub)
create_environment(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/management/listing?limit=500&status=all')
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 70
formdef = FormDef.get_by_urlname('other-form')
for formdata in formdef.data_class().select():
formdata.anonymise()
resp = app.get('/backoffice/management/listing?limit=500&status=all')
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 50
resp = app.get('/backoffice/management/listing?limit=500&status=open')
assert resp.text[resp.text.index('<tbody') :].count('<tr') == 17
def test_global_listing_geojson(pub):
create_user(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
formdef.geolocations = {'base': 'Geolocafoobar'}
formdef.store()
for formdata in formdef.data_class().select():
formdata.geolocations = {'base': {'lat': 48.83, 'lon': 2.32}}
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/geojson')
assert len(resp.json['features']) == 17
assert resp.json['features'][0]['geometry']['coordinates'] == [2.32, 48.83]
for feature in resp.json['features']:
assert feature['properties']['status_colour'] == '#66FF00'
assert feature['properties']['view_label'] == 'View'
assert feature['properties']['status_name'] == 'New'
assert feature['properties']['display_fields']
assert feature['properties']['display_fields'][0]['label'] == 'Name'
assert feature['properties']['display_fields'][0]['value'].startswith('form title #')
resp = app.get('/backoffice/management/geojson?q=aa')
assert len(resp.json['features']) == 5
resp = app.get('/backoffice/management/geojson?q=bb')
assert len(resp.json['features']) == 4
resp = app.get('/backoffice/management/geojson?q=cc')
assert len(resp.json['features']) == 8
def test_global_map(pub):
create_user(pub)
create_environment(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.geolocations = {'base': 'Geolocafoobar'}
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.geolocations = {'base': {'lat': 48.83, 'lon': 2.32}}
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/listing')
assert 'Map View' in resp.text
resp = app.get('/backoffice/management/forms')
assert 'Map View' in resp.text
resp = resp.click('Map View')
assert re.findall(r'data-geojson-url="(.*?)"', resp.text) == [
'http://example.net/backoffice/management/geojson?'
]
resp = app.get('/backoffice/management/map?q=test')
assert re.findall(r'data-geojson-url="(.*?)"', resp.text) == [
'http://example.net/backoffice/management/geojson?q=test'
]
def test_formdata_lookup(pub):
create_user(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.enable_tracking_codes = True
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.store()
formdata2 = formdef.data_class()()
formdata2.just_created()
formdata2.store()
code = pub.tracking_code_class()
code.formdata = formdata
app = login(get_app(pub))
resp = app.get('/backoffice/management/').follow()
assert 'id="lookup-box"' in resp.text
resp.forms[0]['query'] = formdata.tracking_code
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/management/form-title/%s/' % formdata.id
resp = resp.follow()
assert 'The form has been recorded' in resp.text
assert 'This form has been accessed via its tracking code' in resp.text
# check there's no access to other formdata
app.get('http://example.net/backoffice/management/form-title/%s/' % formdata2.id, status=403)
resp = app.get('/backoffice/management/').follow()
resp.forms[0]['query'] = 'AAAAAAAA'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/management/'
resp = resp.follow().follow()
assert 'No such tracking code or identifier.' in resp.text
# check looking up a formdata id
resp.form['query'] = formdata.get_display_id()
resp = resp.form.submit()
assert resp.location == 'http://example.net/backoffice/management/form-title/%s/' % formdata.id
# check looking up on a custom display_id
formdata.id_display = '999999'
formdata.store()
assert formdata.get_display_id() == '999999'
resp = app.get('/backoffice/management/').follow()
resp.form['query'] = formdata.get_display_id()
resp = resp.form.submit()
assert resp.location == 'http://example.net/backoffice/management/form-title/%s/' % formdata.id
# try it from the global listing
resp = app.get('/backoffice/management/listing')
assert 'id="lookup-box"' in resp.text
resp.forms[0]['query'] = formdata.tracking_code
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/management/form-title/%s/' % formdata.id
resp = resp.follow()
assert 'The form has been recorded' in resp.text
resp = app.get('/backoffice/management/listing')
resp.forms[0]['query'] = 'AAAAAAAA'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/management/listing'
resp = resp.follow()
assert 'No such tracking code or identifier.' in resp.text
def test_backoffice_sidebar_user_context(pub):
user = create_user(pub)
create_environment(pub)
form_class = FormDef.get_by_urlname('form-title').data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/')
assert re.findall(r'<tbody.*\/tbody>', resp.text, re.DOTALL)[0].count('<tr') == 17
# click on a formdata
resp = resp.click(href='%s/' % number31.id)
assert (' with the number %s.' % number31.get_display_id()) in resp.text
# check there's nothing in the sidebar
assert '/user-pending-forms' not in resp.text
number31.formdef.digest_templates = {'default': 'digest of number {{form_number}}'}
number31.user_id = user.id
number31.store()
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert '/user-pending-forms' in resp.text
user_pending_form_url = re.findall('data-async-url="(.*/user-pending-forms)"', resp.text)[0]
partial_resp = app.get(user_pending_form_url)
assert number31.get_url(backoffice=True) not in partial_resp.text
assert number31.digests['default'] in partial_resp.text
assert '<span class="formname">%s</span>' % number31.formdef.name in partial_resp.text
# another item with status = new
number34 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 33'][0]
number34.user_id = user.id
number34.store()
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert '/user-pending-forms' in resp.text
user_pending_form_url = re.findall('data-async-url="(.*/user-pending-forms)"', resp.text)[0]
partial_resp = app.get(user_pending_form_url)
assert number31.get_url(backoffice=True) not in partial_resp.text
assert number34.get_url(backoffice=True) in partial_resp.text
cat1 = Category(name='cat1')
cat1.store()
formdef = FormDef.get_by_urlname('other-form')
formdef.category_id = cat1.id
formdef.store()
other_formdata = formdef.data_class().select()[0]
other_formdata.user_id = user.id
other_formdata.store()
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert '/user-pending-forms' in resp.text
user_pending_form_url = re.findall('data-async-url="(.*/user-pending-forms)"', resp.text)[0]
partial_resp = app.get(user_pending_form_url)
assert number34.get_url(backoffice=True) in partial_resp.text
assert other_formdata.get_url(backoffice=True) in partial_resp.text
# categories are displayed, and current formdata category is on top
assert '>cat1<' in partial_resp.text
assert '>Misc<' in partial_resp.text
assert partial_resp.text.index('>Misc<') < partial_resp.text.index('>cat1<')
def test_backoffice_sidebar_lateral_block(pub):
create_user(pub)
FormDef.wipe()
Workflow.wipe()
wf = Workflow(name='WF')
wf.add_status('Status1')
wf.store()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [
fields.StringField(id='0', label='string', varname='string'),
]
formdef.workflow_roles = {'_receiver': 1}
formdef.workflow = wf
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.data = {'0': 'bouh'}
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/%s/' % formdata.id)
assert '/lateral-block' not in resp.text
formdef.lateral_template = 'XX{{ form_var_string }}XX'
formdef.store()
resp = app.get('/backoffice/management/form-title/%s/' % formdata.id)
assert '/lateral-block' in resp.text
lateral_block_url = re.findall('data-async-url="(.*/lateral-block)"', resp.text)[0]
partial_resp = app.get(lateral_block_url)
assert partial_resp.text == '<div class="lateral-block">XXbouhXX</div>'
def test_count_open(pub):
create_user(pub)
FormDef.wipe()
resp = login(get_app(pub)).get('/backoffice/management/count')
assert resp.json['count'] == 0
create_environment(pub)
resp = login(get_app(pub)).get('/backoffice/management/count')
assert resp.json['count'] == 37
formdef = FormDef.get_by_urlname('form-title')
formdef.workflow_roles = {'_receiver': 2} # role the user doesn't have
formdef.store()
formdef.data_class().rebuild_security()
resp = login(get_app(pub)).get('/backoffice/management/count')
assert resp.json['count'] == 20
formdef = FormDef.get_by_urlname('form-title')
formdef.workflow_roles = {'_receiver': 2, '_foobar': 1}
formdef.store()
formdef.data_class().rebuild_security()
resp = login(get_app(pub)).get('/backoffice/management/count')
assert resp.json['count'] == 20
resp = login(get_app(pub)).get('/backoffice/management/count?waiting=yes')
assert resp.json['count'] == 20
formdef = FormDef.get_by_urlname('form-title')
workflow = Workflow.get_default_workflow()
workflow.roles['_foobar'] = 'Foobar'
workflow.id = '2'
workflow.store()
formdef.workflow_id = workflow.id
formdef.workflow_roles = {'_receiver': 2, '_foobar': '1'}
formdef.store()
formdef.data_class().rebuild_security()
resp = login(get_app(pub)).get('/backoffice/management/count?waiting=no')
assert resp.json['count'] == 37
resp = login(get_app(pub)).get('/backoffice/management/count?waiting=yes')
assert resp.json['count'] == 20
resp = login(get_app(pub)).get('/backoffice/management/count')
assert resp.json['count'] == 20
# check the callback parameter is ignored, that we still get the default
# criterias when it's set.
resp = login(get_app(pub)).get('/backoffice/management/count?callback=toto')
assert "20" in resp.text
def test_count_backoffice_drafts(pub):
user = create_user(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [
fields.StringField(
id='1', label='1st field', type='string', display_locations=['validation', 'summary', 'listings']
),
]
formdef.backoffice_submission_roles = user.roles[:]
formdef.store()
for i in range(3):
formdata = formdef.data_class()()
formdata.data = {'1': 'foo'}
formdata.just_created()
formdata.store()
resp = login(get_app(pub)).get('/backoffice/submission/count')
assert resp.json['count'] == 0
formdata1, formdata2, formdata3 = formdef.data_class().select()
for formdata in (formdata1, formdata2, formdata3):
formdata.status = 'draft'
formdata.store()
resp = login(get_app(pub)).get('/backoffice/submission/count')
assert resp.json['count'] == 0
for formdata in (formdata1, formdata2, formdata3):
formdata.backoffice_submission = True
formdata.store()
resp = login(get_app(pub)).get('/backoffice/submission/count')
assert resp.json['count'] == 3
formdata1.data = {}
formdata1.store()
resp = login(get_app(pub)).get('/backoffice/submission/count?mode=empty')
assert resp.json['count'] == 1
resp = login(get_app(pub)).get('/backoffice/submission/count?mode=existing')
assert resp.json['count'] == 2
def test_menu_json(pub):
FormDef.wipe()
create_user(pub)
resp = login(get_app(pub)).get('/backoffice/menu.json')
menu_json_str = resp.text
assert len(resp.json) == 1
assert resp.json[0]['slug'] == 'management'
assert resp.headers['content-type'] == 'application/json'
resp = login(get_app(pub)).get('/backoffice/menu.json?jsonpCallback=foo')
assert resp.text == 'foo(%s);' % menu_json_str
assert resp.headers['content-type'] == 'application/javascript'
def test_backoffice_resume_folded(pub):
create_user(pub)
create_environment(pub)
form_class = FormDef.get_by_urlname('form-title').data_class()
number31 = [x for x in form_class.select() if x.data['1'] == 'FOO BAR 30'][0]
app = login(get_app(pub))
# first access: summary is not folded
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert '<div class="section foldable" id="summary">' in resp.text
# do something: summary is folded
resp = resp.form.submit('button_commentable')
resp = resp.follow()
assert '<div class="section foldable folded" id="summary">' in resp.text
def test_backoffice_backoffice_submission_in_listings(pub):
create_superuser(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.workflow_roles = {'_receiver': 1}
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.jump_status('new')
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/')
first_link = re.findall(r'data-link="(\d+)/?"', resp.text)[0]
assert 'backoffice-submission' not in resp.text
formdata = FormDef.get_by_urlname('form-title').data_class().get(first_link)
formdata.backoffice_submission = True
formdata.store()
resp = app.get('/backoffice/management/form-title/')
assert 'backoffice-submission' in resp.text
def test_backoffice_backoffice_submission_in_global_listing(pub):
create_superuser(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.workflow_roles = {'_receiver': 1}
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.jump_status('new')
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/listing?limit=100')
assert 'backoffice-submission' not in resp.text
formdef = FormDef.get_by_urlname('form-title')
formdata = formdef.data_class().get(
re.findall(r'data-link="(.*?)"', app.get('/backoffice/management/listing').text)[0].split('/')[-2]
)
formdata.backoffice_submission = True
formdata.store()
resp = app.get('/backoffice/management/listing?limit=100')
assert 'backoffice-submission' in resp.text
def test_backoffice_advisory_lock(pub):
create_superuser(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.workflow_roles = {'_receiver': 1}
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.jump_status('new')
formdata.store()
second_user = pub.user_class(name='foobar')
second_user.roles = pub.role_class.keys()
second_user.store()
account = PasswordAccount(id='foobar')
account.set_password('foobar')
account.user_id = second_user.id
account.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/')
first_link = re.findall(r'data-link="(\d+/)?"', resp.text)[0]
assert 'advisory-lock' not in resp.text
app2 = login(get_app(pub), username='foobar', password='foobar')
resp = app2.get('/backoffice/management/form-title/')
assert 'advisory-lock' not in resp.text
resp = app.get('/backoffice/management/form-title/' + first_link)
resp = app2.get('/backoffice/management/form-title/')
assert 'advisory-lock' in resp.text
resp = app.get('/backoffice/management/form-title/')
assert 'advisory-lock' not in resp.text
# check global view
resp = app2.get('/backoffice/management/listing?limit=100')
assert 'advisory-lock' in resp.text
resp = app.get('/backoffice/management/listing?limit=100')
assert 'advisory-lock' not in resp.text
resp = app.get('/backoffice/management/form-title/' + first_link)
assert 'Be warned forms of this user are also being looked' not in resp.text
assert 'button_commentable' in resp.text
assert len(resp.forms)
resp = app2.get('/backoffice/management/form-title/' + first_link)
assert 'Be warned forms of this user are also being looked' in resp.text
assert 'button_commentable' not in resp.text
assert len(resp.forms) == 0
# revisit with first user, no change
resp = app.get('/backoffice/management/form-title/' + first_link)
assert 'Be warned forms of this user are also being looked' not in resp.text
assert 'button_commentable' in resp.text
# back to second
resp = app2.get('/backoffice/management/form-title/' + first_link)
assert 'Be warned forms of this user are also being looked' in resp.text
assert 'button_commentable' not in resp.text
resp = resp.click('(unlock actions)')
resp = resp.follow()
assert 'Be warned forms of this user are also being looked' in resp.text
assert 'button_commentable' in resp.text
assert '(unlock actions)' not in resp.text
assert len(resp.forms)
# submit action form
resp.form['comment'] = 'HELLO'
resp = resp.form.submit('button_commentable')
# locks are reset after an action
assert 'advisory-lock' not in app2.get('/backoffice/management/form-title/')
assert 'advisory-lock' not in app.get('/backoffice/management/form-title/')
# but as the current user is redirected to the form, a lock will be
# acquired (unless the user didn't have actions anymore, but it's not the
# case here)
resp = resp.follow()
assert 'advisory-lock' not in app2.get('/backoffice/management/form-title/')
assert 'advisory-lock' in app.get('/backoffice/management/form-title/')
# don't lock a form on removed users
second_user.remove_self()
assert 'advisory-lock' in app.get('/backoffice/management/form-title/') # still marked in listing
resp = app.get('/backoffice/management/form-title/' + first_link)
assert 'Be warned forms of this user are also being looked' not in resp.text # but not on view
assert resp.forms['wf-actions'] # and the action form is available
def test_backoffice_advisory_lock_related_formdatas(pub):
pub.session_manager.session_class.wipe()
user = create_superuser(pub)
create_environment(pub)
formdef = FormDef.get_by_urlname('form-title')
formdatas = formdef.data_class().select(lambda x: x.status == 'wf-new')
second_user = pub.user_class(name='foobar')
second_user.roles = pub.role_class.keys()
second_user.store()
account = PasswordAccount(id='foobar')
account.set_password('foobar')
account.user_id = second_user.id
account.store()
third_user = pub.user_class(name='user')
third_user.store()
for formdata in formdatas[:2]:
formdata.user_id = third_user.id
formdata.store()
second_formdef = FormDef.get_by_urlname('other-form')
second_formdef.workflow_roles = {}
second_formdef.store()
other_formdatas = second_formdef.data_class().select(lambda x: x.status == 'wf-new')
other_formdatas[0].user_id = third_user.id
other_formdatas[0].store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/%s/' % formdatas[0].id)
assert 'Be warned forms of this user are also being looked' not in resp.text
app.get(re.findall('data-async-url="(.*/user-pending-forms)"', resp.text)[0])
app2 = login(get_app(pub), username='foobar', password='foobar')
resp2 = app2.get('/backoffice/management/form-title/%s/' % formdatas[0].id)
assert 'Be warned forms of this user are also being looked' in resp2.text
app2.get(re.findall('data-async-url="(.*/user-pending-forms)"', resp.text)[0])
# another by the same user
resp2 = app2.get('/backoffice/management/form-title/%s/' % formdatas[1].id)
assert 'Be warned forms of this user are also being looked' in resp2.text
app2.get(re.findall('data-async-url="(.*/user-pending-forms)"', resp.text)[0])
# another by another user
resp2 = app2.get('/backoffice/management/form-title/%s/' % formdatas[3].id)
assert 'Be warned forms of this user are also being looked' not in resp2.text
app2.get(re.findall('data-async-url="(.*/user-pending-forms)"', resp.text)[0])
# check another formdef is only marked as visited if the user has potential
# actions on it.
session = pub.session_manager.session_class.select(lambda x: x.user == user.id)[0]
second_formdef.workflow_roles = {'_receiver': 1}
second_formdef.store()
other_formdata = second_formdef.data_class().get(other_formdatas[0].id)
other_formdata.store() # update concerned_roles
assert 'formdata-other-form-%d' % other_formdata.id not in session.visiting_objects.keys()
session.visiting_objects = {}
session.store()
resp = app.get('/backoffice/management/form-title/%s/' % formdatas[0].id)
app.get(re.findall('data-async-url="(.*/user-pending-forms)"', resp.text)[0])
session = pub.session_manager.session_class.select(lambda x: x.user == user.id)[0]
assert 'formdef-other-form-%d' % other_formdata.id in session.visiting_objects.keys()
def test_backoffice_resubmit(pub):
user = create_user(pub)
wf = Workflow(name='resubmit')
st1 = wf.add_status('Status1')
st2 = wf.add_status('Status2')
resubmit = st1.add_action('resubmit', id='_resubmit')
resubmit.by = [user.roles[0]]
jump = st1.add_action('jumponsubmit', id='_jump')
jump.status = st2.id
register_comment = st2.add_action('register-comment', id='_register')
register_comment.comment = '<p><a href="[resubmit_formdata_backoffice_url]">resubmitted</a></p>'
wf.store()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [
fields.StringField(id='1', label='1st field', type='string', varname='foo'),
]
formdef.workflow_roles = {'_receiver': 1}
formdef.workflow_id = wf.id
formdef.store()
formdef2 = FormDef()
formdef2.name = 'form title bis'
formdef2.backoffice_submission_roles = user.roles[:]
formdef2.fields = [fields.StringField(id='2', label='1st field', type='string', varname='foo')]
formdef2.store()
formdef2.data_class().wipe()
formdata = formdef.data_class()()
formdata.just_created()
formdata.data = {'1': 'XXX'}
formdata.store()
app = login(get_app(pub))
resp = app.get(formdata.get_url(backoffice=True))
resp.form['resubmit'].value = formdef2.id
resp = resp.form.submit('button_resubmit')
resp = resp.follow()
assert 'resubmitted' in resp.text
assert formdef2.data_class().select()[0].status == 'draft'
assert formdef2.data_class().select()[0].data == {'2': 'XXX'}
resp = resp.click('resubmitted')
resp = resp.follow()
resp = resp.follow()
assert resp.form['f2'].value == 'XXX'
assert 'Original form' in resp.text
assert formdata.get_url(backoffice=True) in resp.text
def test_backoffice_workflow_display_form(pub):
user = create_user(pub)
create_environment(pub)
wf = Workflow.get_default_workflow()
wf.id = '2'
wf.store()
wf = Workflow.get(wf.id)
status = wf.get_status('new')
status.items = []
display_form = status.add_action('form', id='_display_form')
display_form.by = [user.roles[0]]
display_form.varname = 'blah'
display_form.formdef = WorkflowFormFieldsFormDef(item=display_form)
display_form.formdef.fields.append(
fields.StringField(id='1', label='Test', varname='str', type='string', required=True)
)
display_form.formdef.fields.append(
# mimick special case: https://dev.entrouvert.org/issues/14691
# item field displayed as radio buttons, with prefill of a value
# that doesn't exist.
fields.ItemField(
id='2',
label='Test2',
type='item',
prefill={'type': 'string', 'value': ''},
display_mode='radio',
varname='radio',
items=['a', 'b', 'c'],
required=True,
)
)
jump = status.add_action('jumponsubmit', id='_jump')
jump.status = 'accepted'
wf.store()
formdef = FormDef.get_by_urlname('form-title')
formdef.workflow_id = wf.id
formdef.store()
for formdata in formdef.data_class().select():
if formdata.status == 'wf-new':
break
app = login(get_app(pub))
resp = app.get(formdata.get_url(backoffice=True))
assert 'fblah_1' in resp.form.fields
resp.form['fblah_1'] = 'blah'
# don't fill required radio button
resp = resp.form.submit('submit')
assert formdef.data_class().get(formdata.id).status == 'wf-new'
assert 'There were errors processing your form.' in resp.text
resp.form['fblah_2'] = 'c'
resp = resp.form.submit('submit')
assert formdef.data_class().get(formdata.id).status == 'wf-accepted'
assert formdef.data_class().get(formdata.id).workflow_data == {
'blah_var_str': 'blah',
'blah_var_radio': 'c',
'blah_var_radio_raw': 'c',
'blah_var_radio_structured': None,
'blah_var_radio_structured_raw': None,
}
def test_backoffice_workflow_form_with_conditions(pub):
user = create_user(pub)
create_environment(pub)
wf = Workflow.get_default_workflow()
wf.id = '2'
wf.store()
wf = Workflow.get(wf.id)
status = wf.get_status('new')
display_form = status.add_action('form', id='_display_form')
display_form.by = [user.roles[0]]
display_form.varname = 'blah'
display_form.formdef = WorkflowFormFieldsFormDef(item=display_form)
display_form.formdef.fields = [
fields.StringField(id='1', label='Test', varname='str', type='string', required=True),
fields.StringField(id='2', label='Test2', varname='str2', type='string', required=True),
]
wf.store()
formdef = FormDef.get_by_urlname('form-title')
formdef.workflow_id = wf.id
formdef.fields[0].varname = 'plop'
formdef.store()
for formdata in formdef.data_class().select():
if formdata.status == 'wf-new':
break
app = login(get_app(pub))
resp = app.get(formdata.get_url(backoffice=True))
assert 'fblah_1' in resp.form.fields
assert 'fblah_2' in resp.form.fields
# check with static condition
display_form.formdef.fields = [
fields.StringField(id='1', label='Test', varname='str', type='string', required=True),
fields.StringField(
id='2',
label='Test2',
varname='str2',
type='string',
required=True,
condition={'type': 'django', 'value': '0'},
),
]
wf.store()
resp = login(get_app(pub)).get(formdata.get_url(backoffice=True))
assert 'fblah_1' in resp.form.fields
assert 'fblah_2' not in resp.form.fields
# check condition based on formdata
display_form.formdef.fields = [
fields.StringField(id='1', label='Test', varname='str', type='string', required=True),
fields.StringField(
id='2',
label='Test2',
varname='str2',
type='string',
required=True,
condition={'type': 'django', 'value': 'form_var_plop'},
),
]
wf.store()
resp = login(get_app(pub)).get(formdata.get_url(backoffice=True))
assert 'fblah_1' in resp.form.fields
assert 'fblah_2' in resp.form.fields
display_form.formdef.fields = [
fields.StringField(id='1', label='Test', varname='str', type='string', required=True),
fields.StringField(
id='2',
label='Test2',
varname='str2',
type='string',
required=True,
condition={'type': 'django', 'value': 'form_var_plop != "xxx"'},
),
]
wf.store()
resp = login(get_app(pub)).get(formdata.get_url(backoffice=True))
assert 'fblah_1' in resp.form.fields
assert 'fblah_2' in resp.form.fields
for variable_name in (
'blah_var_str',
'form_workflow_data_blah_var_str',
'form_workflow_form_blah_var_str',
):
# check with live conditions
display_form.formdef.fields = [
fields.StringField(id='1', label='Test', varname='str', type='string', required=True),
fields.StringField(
id='2',
label='Test2',
varname='str2',
type='string',
required=True,
condition={'type': 'django', 'value': '%s == "xxx"' % variable_name},
),
]
wf.store()
resp = login(get_app(pub)).get(formdata.get_url(backoffice=True))
assert 'fblah_1' in resp.form.fields
assert 'fblah_2' in resp.form.fields
assert resp.html.find('div', {'data-field-id': 'blah_1'}).attrs['data-live-source'] == 'true'
assert resp.html.find('div', {'data-field-id': 'blah_2'}).attrs.get('style') == 'display: none'
live_url = resp.html.find('form').attrs['data-live-url']
assert '/backoffice/' in live_url
resp.form['fblah_1'] = ''
live_resp = app.post(live_url, params=resp.form.submit_fields())
assert live_resp.json['result']['blah_1']['visible']
assert not live_resp.json['result']['blah_2']['visible']
resp.form['fblah_1'] = 'xxx'
live_resp = app.post(live_url, params=resp.form.submit_fields())
assert live_resp.json['result']['blah_1']['visible']
assert live_resp.json['result']['blah_2']['visible']
# check submit doesn't work
resp = resp.form.submit('submit')
assert 'There were errors processing your form.' in resp.text
resp.form['fblah_1'] = 'xxx2'
live_resp = app.post(live_url, params=resp.form.submit_fields())
assert live_resp.json['result']['blah_1']['visible']
assert not live_resp.json['result']['blah_2']['visible']
# check submit does work when second field is hidden
resp = resp.form.submit('submit').follow()
assert formdef.data_class().get(formdata.id).workflow_data == {
'blah_var_str': 'xxx2',
'blah_var_str2': None,
}
def test_backoffice_workflow_form_with_live_data_source(pub):
user = create_user(pub)
create_environment(pub)
wf = Workflow.get_default_workflow()
wf.id = '2'
wf.store()
wf = Workflow.get(wf.id)
status = wf.get_status('new')
display_form = status.add_action('form', id='_display_form')
display_form.by = [user.roles[0]]
display_form.varname = 'blah'
display_form.formdef = WorkflowFormFieldsFormDef(item=display_form)
display_form.formdef.fields = [
fields.StringField(id='1', label='Test', varname='str', type='string', required=True),
fields.ItemField(
id='2',
label='Test2',
varname='str2',
type='item',
required=True,
data_source={'type': 'json', 'value': 'https://www.example.invalid/{{ blah_var_str }}'},
),
]
wf.store()
formdef = FormDef.get_by_urlname('form-title')
formdef.workflow_id = wf.id
formdef.fields[0].varname = 'plop'
formdef.store()
for formdata in formdef.data_class().select():
if formdata.status == 'wf-new':
break
app = get_app(pub)
with mock.patch('wcs.qommon.misc.urlopen') as urlopen:
data1 = {'data': [{'id': 'A', 'text': 'hello'}, {'id': 'B', 'text': 'world'}]}
data2 = {'data': [{'id': 'C', 'text': 'hello'}, {'id': 'D', 'text': 'world'}]}
def side_effect(url, *args):
if 'toto' not in url:
return io.StringIO(json.dumps(data1))
else:
return io.StringIO(json.dumps(data2))
urlopen.side_effect = side_effect
resp = login(app).get(formdata.get_url(backoffice=True))
assert 'fblah_1' in resp.form.fields
assert 'fblah_2' in resp.form.fields
assert resp.form.fields['fblah_2'][0].options == [('A', False, 'hello'), ('B', False, 'world')]
live_url = resp.html.find('form').attrs['data-live-url']
resp.form['fblah_1'] = 'toto'
live_resp = app.post(live_url + '?modified_field_id=blah_1', params=resp.form.submit_fields())
assert live_resp.json['result']['blah_2']['items'] == [
{'text': 'hello', 'id': 'C'},
{'text': 'world', 'id': 'D'},
]
def test_backoffice_workflow_display_form_with_block_add(pub):
user = create_user(pub)
create_environment(pub)
block = BlockDef()
block.name = 'foobar'
block.fields = [
fields.StringField(id='123', required=True, label='Test', type='string'),
]
block.store()
wf = Workflow.get_default_workflow()
wf.id = '2'
wf.store()
wf = Workflow.get(wf.id)
status = wf.get_status('new')
display_form = status.add_action('form', id='_display_form')
display_form.by = [user.roles[0]]
display_form.varname = 'blah'
display_form.formdef = WorkflowFormFieldsFormDef(item=display_form)
display_form.formdef.fields = [
fields.StringField(id='1', label='Test', varname='str', type='string', required=True),
fields.BlockField(id='2', label='Blocks', type='block:foobar', varname='data', max_items=3),
]
jump = status.add_action('jumponsubmit', id='_jump')
jump.status = 'accepted'
wf.store()
formdef = FormDef.get_by_urlname('form-title')
formdef.workflow_id = wf.id
formdef.store()
for formdata in formdef.data_class().select():
if formdata.status == 'wf-new':
break
app = login(get_app(pub))
resp = app.get(formdata.get_url(backoffice=True))
resp.form['fblah_1'] = 'blah'
resp.form['fblah_2$element0$f123'] = 'foo'
resp = resp.form.submit('fblah_2$add_element')
resp.form['fblah_2$element1$f123'] = 'bar'
resp = resp.form.submit('submit')
assert formdef.data_class().get(formdata.id).workflow_data == {
'blah_var_data': 'foobar, foobar',
'blah_var_data_raw': {'data': [{'123': 'foo'}, {'123': 'bar'}], 'schema': {'123': 'string'}},
'blah_var_str': 'blah',
}
def test_backoffice_workflow_form_with_other_buttons(pub):
user = create_user(pub)
create_environment(pub)
wf = Workflow.get_default_workflow()
wf.id = '2'
wf.store()
wf = Workflow.get(wf.id)
status = wf.get_status('new')
status.items = []
display_form = status.add_action('form', id='_display_form')
display_form.by = [user.roles[0]]
display_form.varname = 'blah'
display_form.formdef = WorkflowFormFieldsFormDef(item=display_form)
display_form.formdef.fields.append(
fields.StringField(id='1', label='Test', varname='str', type='string', required=True)
)
choice_ok = status.add_action('choice', id='_ok')
choice_ok.label = 'OK'
choice_ok.status = 'accepted'
choice_ok.by = [user.roles[0]]
choice_ko = status.add_action('choice', id='_ko')
choice_ko.label = 'KO'
choice_ko.status = 'accepted'
choice_ko.ignore_form_errors = True
choice_ko.by = [user.roles[0]]
jump = status.add_action('jumponsubmit', id='_jump')
jump.status = 'accepted'
wf.store()
formdef = FormDef.get_by_urlname('form-title')
formdef.workflow_id = wf.id
formdef.store()
for button_name in ('submit', 'button_ok', 'button_ko'):
formdata = formdef.data_class()()
formdata.data = {}
formdata.just_created()
formdata.jump_status('new')
formdata.store()
app = login(get_app(pub))
resp = app.get(formdata.get_url(backoffice=True))
resp.form['fblah_1'] = 'blah'
resp = resp.form.submit(button_name)
formdata.refresh_from_storage()
pub.substitutions.reset()
pub.substitutions.feed(formdata)
context = pub.substitutions.get_context_variables(mode='lazy')
assert formdata.status == 'wf-accepted'
if button_name == 'button_ko':
assert context['form_workflow_data_blah_var_str'] == 'blah' # leak
with pytest.raises(KeyError):
assert context['form_workflow_form_blah_var_str'] == 'blah'
else:
assert context['form_workflow_form_blah_var_str'] == 'blah'
assert context['form_workflow_data_blah_var_str'] == 'blah'
def test_backoffice_criticality_formdata_view(pub):
create_user(pub)
create_environment(pub)
wf = Workflow.get_default_workflow()
wf.id = '2'
wf.criticality_levels = [
WorkflowCriticalityLevel(name='green'),
WorkflowCriticalityLevel(name='yellow'),
WorkflowCriticalityLevel(name='red'),
]
wf.store()
formdef = FormDef.get_by_urlname('form-title')
formdef.workflow_id = wf.id
formdef.store()
formdef = FormDef.get_by_urlname('form-title')
formdata = [x for x in formdef.data_class().select() if x.status == 'wf-new'][0]
formdata.set_criticality_level(1)
formdata.store()
app = login(get_app(pub))
resp = app.get(formdata.get_url(backoffice=True))
assert 'Criticality Level: yellow' in resp.text
formdata.set_criticality_level(2)
formdata.store()
resp = app.get(formdata.get_url(backoffice=True))
assert 'Criticality Level: red' in resp.text
def test_workflow_jump_previous(pub):
user = create_user(pub)
create_environment(pub)
wf = Workflow(name='jump around')
# North
# / \
# West <----> East
# | |
# | autojump
# | |
# \ /
# South
st1 = wf.add_status('North')
st1.id = 'north'
st2 = wf.add_status('West')
st2.id = 'west'
st3 = wf.add_status('East')
st3.id = 'east'
st4 = wf.add_status('Autojump')
st4.id = 'autojump'
st5 = wf.add_status('South')
st5.id = 'south'
button_by_id = {}
def add_jump(label, src, dst_id):
jump = src.add_action('choice', id=str(random.random()))
jump.label = label
jump.by = ['logged-users']
jump.status = dst_id
if dst_id != '_previous':
jump.set_marker_on_status = True
button_by_id[label] = 'button%s' % jump.id
return jump
add_jump('Go West', st1, st2.id)
add_jump('Go East', st1, st3.id)
add_jump('Go South', st2, st5.id)
add_jump('Go Autojump', st3, st4.id)
add_jump('Go Back', st5, '_previous')
add_jump('Jump West', st3, st2.id)
add_jump('Jump East', st2, st3.id)
jump = st4.add_action('jump', id='_auto-jump')
jump.status = st5.id
wf.store()
formdef = FormDef.get_by_urlname('form-title')
formdef.data_class().wipe()
formdef.workflow = wf
formdef.store()
formdata = formdef.data_class()()
formdata.data = {}
formdata.just_created()
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/%s/' % formdata.id)
# jump around using buttons
resp = resp.form.submit(button_by_id['Go West']).follow() # push (north)
assert formdef.data_class().get(formdata.id).status == 'wf-%s' % st2.id
resp = resp.form.submit(button_by_id['Go South']).follow() # push (north, west)
assert formdef.data_class().get(formdata.id).status == 'wf-%s' % st5.id
resp = resp.form.submit(button_by_id['Go Back']).follow() # pop (north)
assert formdef.data_class().get(formdata.id).status == 'wf-%s' % st2.id
resp = resp.form.submit(button_by_id['Go South']).follow() # push (north, west)
assert formdef.data_class().get(formdata.id).status == 'wf-%s' % st5.id
resp = resp.form.submit(button_by_id['Go Back']).follow() # pop (north)
assert formdef.data_class().get(formdata.id).status == 'wf-%s' % st2.id
resp = resp.form.submit(button_by_id['Jump East']).follow() # push (north, west)
assert formdef.data_class().get(formdata.id).status == 'wf-%s' % st3.id
resp = resp.form.submit(button_by_id['Go Autojump']).follow() # push (north, west, east)
assert formdef.data_class().get(formdata.id).status == 'wf-%s' % st5.id
# check markers are displayed in /inspect page
user.is_admin = True
user.store()
resp2 = app.get('/backoffice/management/form-title/%s/inspect' % formdata.id)
assert 'Markers Stack' in resp2.text
assert '<span class="status">East</span>' in resp2.text
assert '<span class="status">West</span>' in resp2.text
assert '<span class="status">North</span>' in resp2.text
assert resp2.text.find('<span class="status">East</span>') < resp2.text.find(
'<span class="status">West</span>'
)
assert resp2.text.find('<span class="status">West</span>') < resp2.text.find(
'<span class="status">North</span>'
)
resp = resp.form.submit(button_by_id['Go Back']).follow() # pop (north, west)
assert formdef.data_class().get(formdata.id).status == 'wf-%s' % st3.id
# and do a last jump using the API
formdata = formdef.data_class().get(formdata.id)
formdata.jump_status('_previous') # pop (north)
assert formdata.status == 'wf-%s' % st2.id
formdata = formdef.data_class().get(formdata.id)
formdata.jump_status('_previous') # pop ()
assert formdata.status == 'wf-%s' % st1.id
def test_workflow_jump_previous_on_submit(pub):
create_user(pub)
create_environment(pub)
wf = Workflow(name='blah')
st1 = wf.add_status('North')
st1.id = 'north'
st2 = wf.add_status('South')
st2.id = 'south'
commentable = st1.add_action('commentable', id='_commentable')
commentable.by = ['_submitter', '_receiver']
commentable.button_label = 'CLICK ME!'
jump = st1.add_action('jumponsubmit', id='_jump')
jump.status = st2.id
jump.set_marker_on_status = True
back = st2.add_action('choice', id='_back')
back.label = 'Back'
back.by = ['_receiver']
back.status = '_previous'
wf.store()
formdef = FormDef.get_by_urlname('form-title')
formdef.data_class().wipe()
formdef.workflow = wf
formdef.store()
formdata = formdef.data_class()()
formdata.data = {}
formdata.just_created()
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/%s/' % formdata.id)
resp.form['comment'] = 'HELLO WORLD'
resp = resp.form.submit('button_commentable')
resp = resp.follow()
assert formdef.data_class().get(formdata.id).status == 'wf-south'
assert formdef.data_class().get(formdata.id).workflow_data['_markers_stack']
resp = resp.form.submit('button_back')
resp = resp.follow()
assert formdef.data_class().get(formdata.id).status == 'wf-north'
assert not formdef.data_class().get(formdata.id).workflow_data['_markers_stack']
def test_workflow_jump_previous_auto(pub):
create_user(pub)
create_environment(pub)
wf = Workflow(name='blah')
st1 = wf.add_status('North')
st1.id = 'north'
st2 = wf.add_status('South')
st2.id = 'south'
jump = st1.add_action('jump', id='_auto-jump')
jump.set_marker_on_status = True
jump.status = st2.id
back = st2.add_action('choice', id='_back')
back.label = 'Back'
back.by = ['_receiver']
back.status = '_previous'
wf.store()
formdef = FormDef.get_by_urlname('form-title')
formdef.data_class().wipe()
formdef.workflow = wf
formdef.store()
formdata = formdef.data_class()()
formdata.data = {}
formdata.just_created()
formdata.store()
formdata.perform_workflow()
assert formdata.status == 'wf-south'
assert formdata.workflow_data['_markers_stack'] == [{'status_id': 'north'}]
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/%s/' % formdata.id)
resp = resp.form.submit('button_back')
resp = resp.follow()
# jumped and got back to north, then re-jump to south again (auto-jump)
formdata = formdef.data_class().get(formdata.id)
statuses = [evo.status for evo in formdata.evolution]
assert statuses == ['wf-north', 'wf-south', 'wf-north', 'wf-south']
# formdata went through north->south auto-jump again, status and marker are still here
assert formdata.status == 'wf-south'
assert formdata.workflow_data['_markers_stack'] == [{'status_id': 'north'}]
# no marker (workflow inconsistency)
formdata.workflow_data['_markers_stack'] = []
formdata.store()
resp = app.get('/backoffice/management/form-title/%s/' % formdata.id)
resp = resp.form.submit('button_back')
resp = resp.follow()
formdata = formdef.data_class().get(formdata.id)
assert formdata.status == 'wf-south'
assert not formdata.workflow_data['_markers_stack']
# unknown marker (workflow inconsistency)
formdata.workflow_data['_markers_stack'] = [{'status_id': 'unknown_status'}]
formdata.store()
resp = app.get('/backoffice/management/form-title/%s/' % formdata.id)
resp = resp.form.submit('button_back')
resp = resp.follow()
formdata = formdef.data_class().get(formdata.id)
assert formdata.status == 'wf-south'
def test_backoffice_fields(pub):
create_user(pub)
wf = Workflow(name='bo fields')
wf.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(wf)
wf.backoffice_fields_formdef.fields = [
fields.StringField(
id='bo1', label='1st backoffice field', type='string', varname='backoffice_blah', required=False
),
]
wf.add_status('Status1')
wf.store()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.workflow_roles = {'_receiver': 1}
formdef.workflow_id = wf.id
formdef.store()
formdata = formdef.data_class()()
formdata.data = {}
formdata.just_created()
formdata.store()
app = login(get_app(pub))
resp = app.get(formdata.get_url(backoffice=True))
assert 'Backoffice Data' not in resp.text
assert '1st backoffice field' not in resp.text
formdata.data = {'bo1': 'HELLO WORLD'}
formdata.store()
resp = app.get(formdata.get_url(backoffice=True))
assert 'Backoffice Data' in resp.text
assert '1st backoffice field' in resp.text
assert 'HELLO WORLD' in resp.text
wf.backoffice_fields_formdef.fields = [
fields.StringField(
id='bo1', label='1st backoffice field', type='string', varname='backoffice_blah', required=True
),
]
wf.store()
formdata = formdef.data_class()()
formdata.data = {}
formdata.just_created()
formdata.store()
app = login(get_app(pub))
resp = app.get(formdata.get_url(backoffice=True))
assert 'Backoffice Data' in resp.text
assert 'Not set' in resp.text
def test_backoffice_logged_errors(pub):
Workflow.wipe()
workflow = Workflow.get_default_workflow()
workflow.id = '12'
st1 = workflow.possible_status[0]
jump = st1.add_action('jump', id='_jump', prepend=True)
jump.status = 'rejected'
jump.condition = {'type': 'python', 'value': '1//0'} # ZeroDivisionError
workflow.store()
FormDef.wipe()
formdef = FormDef()
formdef.id = '34'
formdef.workflow = workflow
formdef.name = 'test'
formdef.confirmation = False
formdef.fields = []
formdef.store()
# create a carddef with the same id
CardDef.wipe()
carddef = CardDef()
carddef.id = '34'
carddef.name = 'test'
carddef.fields = []
carddef.store()
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/forms/%s/' % formdef.id)
assert 'ZeroDivisionError' not in resp.text
resp = app.get('/backoffice/cards/%s/' % carddef.id)
assert 'ZeroDivisionError' not in resp.text
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
assert 'ZeroDivisionError' not in resp.text
app = get_app(pub)
resp = app.get('/test/')
resp = resp.form.submit('submit').follow()
resp = resp.form.submit('submit')
assert pub.loggederror_class.count() == 1
app = login(get_app(pub))
resp = app.get('/backoffice/forms/%s/' % formdef.id)
assert 'Failed to evaluate condition' in resp.text
assert 'ZeroDivisionError' in resp.text
resp = resp.click('1 error')
resp = app.get('/backoffice/cards/%s/' % carddef.id)
assert 'ZeroDivisionError' not in resp.text
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp2 = resp.click('1 error')
assert 'Failed to evaluate condition' in resp2.text
assert 'ZeroDivisionError' in resp2.text
resp = resp2.click('Failed to evaluate condition')
assert 'ZeroDivisionError: integer division or modulo by zero' in resp.text
assert 'Python Expression: <code>1//0</code>' in resp.text
resp = resp.click('Delete').follow()
assert pub.loggederror_class.count() == 0
pub.cfg.update({'debug': {'error_email': None}})
pub.write_cfg()
app = get_app(pub)
resp = app.get('/test/')
resp = resp.form.submit('submit').follow()
resp = resp.form.submit('submit')
assert pub.loggederror_class.count() == 1
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
assert 'Failed to evaluate condition' in resp2.text
assert 'ZeroDivisionError' in resp2.text
resp2 = resp.click('1 error')
resp = resp2.click('Failed to evaluate condition')
assert 'href="http://example.net/backoffice/management/test/' in resp.text
# very long error string (check it creates a viable tech_id)
jump.condition = {'type': 'python', 'value': 'x' * 500} # NameError + very long string
workflow.store()
app = get_app(pub)
resp = app.get('/test/')
resp = resp.form.submit('submit').follow()
resp = resp.form.submit('submit')
assert pub.loggederror_class.count() == 2
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
assert 'Failed to evaluate condition' in resp.text
assert "error NameError (name 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx…" in resp.text
# remove formdef
FormDef.wipe()
resp = resp2.click('Failed to evaluate condition')
assert 'href="http://example.net/backoffice/management/test/' not in resp.text
def test_backoffice_formdata_named_wscall(http_requests, pub):
user = create_user(pub)
FormDef.wipe()
NamedWsCall.wipe()
wscall = NamedWsCall()
wscall.name = 'Hello world'
wscall.request = {'url': 'http://remote.example.net/json'}
wscall.store()
assert wscall.slug == 'hello_world'
formdef = FormDef()
formdef.name = 'test'
formdef.backoffice_submission_roles = user.roles[:]
formdef.fields = [
fields.CommentField(id='7', label='X[webservice.hello_world.foo]Y', type='comment'),
]
formdef.store()
formdef.data_class().wipe()
app = login(get_app(pub))
resp = app.get('/backoffice/submission/test/')
assert resp.html.find('div', {'data-field-id': '7'}).text.strip() == 'XbarY'
# check with publisher variable in named webservice call
if not pub.site_options.has_section('variables'):
pub.site_options.add_section('variables')
pub.site_options.set('variables', 'example_url', 'http://remote.example.net/')
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
pub.site_options.write(fd)
wscall = NamedWsCall()
wscall.name = 'Hello world'
wscall.request = {'url': '[example_url]json'}
wscall.store()
resp = app.get('/backoffice/submission/test/')
assert resp.html.find('div', {'data-field-id': '7'}).text.strip() == 'XbarY'
# django-templated URL
wscall.request = {'url': '{{ example_url }}json'}
wscall.store()
resp = app.get('/backoffice/submission/test/')
assert resp.html.find('div', {'data-field-id': '7'}).text.strip() == 'XbarY'
# webservice call in django template
formdef.fields = [
fields.CommentField(id='7', label='dja-{{ webservice.hello_world.foo}}-ngo', type='comment'),
]
formdef.store()
formdef.data_class().wipe()
resp = app.get('/backoffice/submission/test/')
assert resp.html.find('div', {'data-field-id': '7'}).text.strip() == 'dja-bar-ngo'
def test_backoffice_session_var(pub):
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
fd.write(
'''[options]
query_string_allowed_vars = foo,bar
'''
)
FormDef.wipe()
user = create_user(pub)
formdef = FormDef()
formdef.name = 'test'
formdef.backoffice_submission_roles = user.roles[:]
formdef.fields = [
fields.CommentField(id='7', label='X[session_var_foo]Y', type='comment'),
]
formdef.store()
formdef.data_class().wipe()
app = login(get_app(pub))
resp = app.get('/backoffice/submission/test/?session_var_foo=bar')
assert resp.location.endswith('/backoffice/submission/test/')
resp = resp.follow()
assert resp.html.find('div', {'data-field-id': '7'}).text.strip() == 'XbarY'
# django template
formdef.fields = [
fields.CommentField(id='7', label='d{{ session_var_foo }}o', type='comment'),
]
formdef.store()
formdef.data_class().wipe()
resp = app.get('/backoffice/submission/test/?session_var_foo=jang')
assert resp.location.endswith('/backoffice/submission/test/')
resp = resp.follow()
assert resp.html.find('div', {'data-field-id': '7'}).text.strip() == 'django'
def test_backoffice_display_message(pub):
user = create_user(pub)
workflow = Workflow(name='test')
st1 = workflow.add_status('Status1', 'st1')
display1 = st1.add_action('displaymsg')
display1.message = 'message-to-all'
display1.to = []
display2 = st1.add_action('displaymsg')
display2.message = 'message-to-submitter'
display2.to = ['_submitter']
display3 = st1.add_action('displaymsg')
display3.message = 'message-to-receiver'
display3.to = [user.roles[0]]
workflow.store()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.workflow_roles = {'_receiver': 1}
formdef.workflow = workflow
formdef.store()
formdata = formdef.data_class()()
formdata.data = {}
formdata.just_created()
formdata.jump_status('st1')
formdata.store()
app = login(get_app(pub))
resp = app.get(formdata.get_url(backoffice=True))
assert 'message-to-all' in resp.text
assert 'message-to-submitter' not in resp.text
assert 'message-to-receiver' in resp.text
# display first message at the bottom of the page
display1.position = 'bottom'
workflow.store()
resp = app.get(formdata.get_url(backoffice=True))
assert resp.text.index('message-to-all') > resp.text.index('message-to-receiver')
# display first message on top of actions
display1.position = 'actions'
workflow.store()
resp = app.get(formdata.get_url(backoffice=True))
assert 'message-to-all' not in resp.text # no actions no message
again = st1.add_action('choice', id='_again')
again.label = 'Again'
again.by = ['_receiver']
again.status = st1.id
workflow.store()
resp = app.get(formdata.get_url(backoffice=True))
assert 'message-to-all' in resp.text
assert resp.text.index('message-to-all') > resp.text.index('message-to-receiver')
def test_backoffice_forms_condition_on_button(pub):
create_superuser(pub)
create_environment(pub, set_receiver=True)
workflow = Workflow.get_default_workflow()
workflow.id = '2'
workflow.store()
formdef = FormDef.get_by_urlname('form-title')
formdef.workflow = workflow
formdef.store()
# move some forms from new to accepted
for i, formdata in enumerate(formdef.data_class().select(lambda x: x.status == 'wf-new')):
if i % 2:
formdata.status = 'wf-accepted'
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/forms')
assert '17 open on 50' in resp.text
formdata = [x for x in formdef.data_class().select() if x.status == 'wf-new'][0]
resp = app.get(formdata.get_url(backoffice=True))
assert 'button_commentable' in resp.text
assert 'button_accept' in resp.text
assert 'button_reject' in resp.text
# commentable
workflow.possible_status[1].items[0].condition = {'type': 'python', 'value': 'False'}
# reject
workflow.possible_status[1].items[2].condition = {'type': 'python', 'value': 'False'}
workflow.store()
resp = app.get(formdata.get_url(backoffice=True))
assert 'button_commentable' not in resp.text
assert 'button_accept' in resp.text
assert 'button_reject' not in resp.text
formdef = FormDef.get_by_urlname('form-title')
assert formdef.data_class().get(formdata.id).actions_roles == {'1'}
# accept
workflow.possible_status[1].items[1].condition = {'type': 'python', 'value': 'False'}
workflow.store()
resp = app.get(formdata.get_url(backoffice=True))
assert 'button_commentable' not in resp.text
assert 'button_accept' not in resp.text
assert 'button_reject' not in resp.text
formdef = FormDef.get_by_urlname('form-title')
assert formdef.data_class().get(formdata.id).actions_roles == set()
app = login(get_app(pub))
resp = app.get('/backoffice/management/forms')
assert '8 open on 50' in resp.text # only the accepted ones
def test_workflow_comment_required(pub):
create_user(pub)
wf = Workflow(name='blah')
st1 = wf.add_status('Comment')
st1.id = 'comment'
commentable = st1.add_action('commentable', id='_commentable')
commentable.by = ['_submitter', '_receiver']
wf.store()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.workflow_roles = {'_receiver': 1}
formdef.workflow = wf
formdef.store()
formdata = formdef.data_class()()
formdata.data = {}
formdata.just_created()
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/form-title/%s/' % formdata.id)
assert 'widget-required' not in resp.text
resp.form['comment'] = 'HELLO WORLD 1'
resp = resp.form.submit('button_commentable')
resp = resp.follow()
assert 'HELLO WORLD 1' in resp.text
assert 'widget-required' not in resp.text
resp.form['comment'] = None
resp = resp.form.submit('button_commentable')
resp = resp.follow()
commentable.required = True
wf.store()
resp = app.get('/backoffice/management/form-title/%s/' % formdata.id)
assert 'widget-required' in resp.text
resp.form['comment'] = ' ' # spaces == empty
resp = resp.form.submit('button_commentable')
assert 'widget-with-error' in resp.text
resp.form['comment'] = 'HELLO WORLD 2'
resp = resp.form.submit('button_commentable')
resp = resp.follow()
assert 'widget-with-error' not in resp.text
assert 'HELLO WORLD 2' in resp.text
def test_lazy_eval_with_conditional_workflow_form(pub):
role = pub.role_class(name='foobar')
role.store()
user = create_user(pub)
app = login(get_app(pub))
FormDef.wipe()
wf = Workflow(name='lazy backoffice form')
wf.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(wf)
wf.backoffice_fields_formdef.fields = [
fields.StringField(id='bo1', label='Foo Bar', varname='foo_bar'),
]
st1 = wf.add_status('New', 'new')
st2 = wf.add_status('Choose', 'choice')
st3 = wf.add_status('Done', 'done')
# first status with a workflow form, with a live conditional field.
display_form = st1.add_action('form', id='_display_form')
display_form.by = [user.roles[0]]
display_form.varname = 'local'
display_form.formdef = WorkflowFormFieldsFormDef(item=display_form)
display_form.formdef.fields = [
fields.StringField(id='1', label='Test', varname='str', type='string', required=True),
fields.StringField(
id='2',
label='Test 2',
varname='str2',
type='string',
condition={'type': 'django', 'value': 'local_var_str'},
),
]
submit_choice = st1.add_action('jumponsubmit')
submit_choice.status = st2.id
# jump to a second status, that set's a backoffice field data
setbo = st2.add_action('set-backoffice-fields')
setbo.fields = [{'field_id': 'bo1', 'value': 'go'}]
# and jump to the third status if the evoluation succeeds
jump = st2.add_action('jump')
jump.condition = {'type': 'django', 'value': "form_var_foo_bar == 'go'"}
jump.status = st3.id
wf.store()
formdef = FormDef()
formdef.name = 'test'
formdef.fields = [fields.StringField(id='0', label='Foo', varname='foo')]
formdef.workflow_roles = {'_receiver': role.id}
formdef.workflow_id = wf.id
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.data = {'0': 'test'}
formdata.store()
resp = app.get(formdata.get_url(backoffice=True))
resp.forms[0]['flocal_1'] = 'a'
resp.forms[0]['flocal_2'] = 'b'
resp = resp.forms[0].submit()
assert formdata.select()[0].status == 'wf-done'
context = pub.substitutions.get_context_variables(mode='lazy')
assert context['form_var_foo_bar'] == 'go'
@pytest.fixture(params=[{'attach_to_history': True}, {}])
def create_formdata(request, pub):
admin = create_user(pub, is_admin=True)
FormDef.wipe()
source_formdef = FormDef()
source_formdef.name = 'source form'
source_formdef.workflow_roles = {'_receiver': 1}
source_formdef.fields = [
fields.StringField(id='0', label='string', varname='toto_string'),
fields.FileField(id='1', label='file', type='file', varname='toto_file'),
]
source_formdef.store()
target_formdef = FormDef()
target_formdef.name = 'target form'
target_formdef.workflow_roles = {'_receiver': 1}
target_formdef.backoffice_submission_roles = admin.roles[:]
target_formdef.fields = [
fields.StringField(id='0', label='string', varname='foo_string'),
fields.FileField(id='1', label='file', type='file', varname='foo_file'),
]
target_formdef.store()
wf = Workflow(name='create-formdata')
st1 = wf.add_status('New')
st2 = wf.add_status('Resubmit')
jump = st1.add_action('choice', id='_resubmit')
jump.label = 'Resubmit'
jump.by = ['_receiver']
jump.status = st2.id
create_formdata = st2.add_action('create_formdata', id='_create_formdata')
create_formdata.varname = 'resubmitted'
create_formdata.draft = True
create_formdata.formdef_slug = target_formdef.url_name
create_formdata.user_association_mode = 'keep-user'
create_formdata.backoffice_submission = True
create_formdata.attach_to_history = request.param.get('attach_to_history', False)
create_formdata.mappings = [
Mapping(field_id='0', expression='=form_var_toto_string'),
Mapping(field_id='1', expression='=form_var_toto_file_raw'),
]
redirect = st2.add_action('redirect_to_url', id='_redirect')
redirect.url = '{{ form_links_resubmitted.form_backoffice_url }}'
jump = st2.add_action('jumponsubmit', id='_jump')
jump.status = st1.id
wf.store()
source_formdef.workflow_id = wf.id
source_formdef.store()
source_formdef.data_class().wipe()
target_formdef.data_class().wipe()
return locals()
def test_backoffice_create_formdata_backoffice_submission(pub, create_formdata):
# create submitting user
user = create_formdata['pub'].user_class()
user.name = 'Jean Darmette'
user.email = 'jean.darmette@triffouilis.fr'
user.store()
# create source formdata
formdata = create_formdata['source_formdef'].data_class()()
upload = PicklableUpload('/foo/bar', content_type='text/plain')
upload.receive([b'hello world'])
formdata.data = {
'0': 'coucou',
'1': upload,
}
formdata.user = user
formdata.just_created()
formdata.store()
formdata.perform_workflow()
# agent login and go to backoffice management pages
app = get_app(create_formdata['pub'])
app = login(app)
resp = app.get(create_formdata['source_formdef'].get_url(backoffice=True))
# click on first available formdata
resp = resp.click('%s-%s' % (create_formdata['source_formdef'].id, formdata.id))
target_data_class = create_formdata['target_formdef'].data_class()
assert target_data_class.count() == 0
# resubmit it through backoffice submission
resp = resp.form.submit(name='button_resubmit')
assert pub.loggederror_class.count() == 0
assert target_data_class.count() == 1
target_formdata = target_data_class.select()[0]
assert target_formdata.submission_context == {
'orig_object_type': 'formdef',
'orig_formdata_id': '1',
'orig_formdef_id': '1',
}
assert target_formdata.submission_agent_id == str(create_formdata['admin'].id)
assert target_formdata.user.id == user.id
assert target_formdata.status == 'draft'
assert resp.location == 'http://example.net/backoffice/management/target-form/%s/' % target_formdata.id
resp = resp.follow()
assert resp.location == 'http://example.net/backoffice/submission/target-form/%s/' % target_formdata.id
resp = resp.follow()
# second redirect with magic-token
resp = resp.follow()
resp = resp.form.submit(name='submit') # -> validation
resp = resp.form.submit(name='submit') # -> submission
target_formdata = target_data_class.get(id=target_formdata.id)
assert target_formdata.user.id == user.id
assert target_formdata.status == 'wf-new'
resp = resp.follow()
pq = resp.pyquery.remove_namespaces()
assert pq('.field-type-string .value').text() == 'coucou'
assert pq('.field-type-file .value').text() == 'bar'
def test_linked_forms_variables(pub, create_formdata):
# create source formdata
formdata = create_formdata['source_formdef'].data_class()()
upload = PicklableUpload('/foo/bar', content_type='text/plain')
upload.receive([b'hello world'])
formdata.data = {
'0': 'coucou',
'1': upload,
}
formdata.just_created()
formdata.store()
formdata.perform_workflow()
formdata.store()
formdata.jump_status('2')
formdata.perform_workflow()
formdata.store()
pub.substitutions.reset()
pub.substitutions.feed(formdata)
substvars = pub.substitutions.get_context_variables(mode='lazy')
assert str(substvars['form_links_resubmitted_form_var_foo_string']) == 'coucou'
assert 'form_links_resubmitted_form_var_foo_string' in substvars.get_flat_keys()
source_formdata = create_formdata['source_formdef'].data_class().select()[0]
app = get_app(create_formdata['pub'])
app = login(app)
resp = app.get(source_formdata.get_url(backoffice=True) + 'inspect')
assert 'form_links_resubmitted_form_var_foo_string' in resp
# delete target formdata
create_formdata['target_formdef'].data_class().wipe()
resp = app.get(source_formdata.get_url(backoffice=True) + 'inspect')
assert 'form_links_resubmitted_form_var_foo_string' not in resp
# delete target formdef
create_formdata['target_formdef'].remove_self()
resp = app.get(source_formdata.get_url(backoffice=True) + 'inspect')
def test_backoffice_create_formdata_map_fields_by_varname(pub, create_formdata):
create_formdata['create_formdata'].map_fields_by_varname = True
create_formdata['create_formdata'].mappings = []
create_formdata['wf'].store()
create_formdata['source_formdef'].fields = [
fields.StringField(id='0', label='string', varname='string0'),
fields.FileField(id='1', label='file', type='file', varname='file1'),
fields.StringField(id='2', label='string', varname='string2', required=False),
fields.FileField(id='3', label='file', type='file', varname='file3', required=False),
]
create_formdata['source_formdef'].store()
create_formdata['target_formdef'].fields = [
fields.StringField(id='0', label='string', varname='string0'),
fields.FileField(id='1', label='file', type='file', varname='file1'),
fields.StringField(id='2', label='string', varname='string2', required=False),
fields.FileField(id='3', label='file', type='file', varname='file3', required=False),
]
create_formdata['target_formdef'].store()
# create submitting user
user = create_formdata['pub'].user_class()
user.name = 'Jean Darmette'
user.email = 'jean.darmette@triffouilis.fr'
user.store()
# create source formdata
formdata = create_formdata['source_formdef'].data_class()()
create_formdata['formdata'] = formdata
upload = PicklableUpload('/foo/bar', content_type='text/plain')
upload.receive([b'hello world'])
formdata.data = {
'0': 'coucou',
'1': upload,
}
formdata.user = user
formdata.just_created()
formdata.store()
formdata.perform_workflow()
# agent login and go to backoffice management pages
app = get_app(create_formdata['pub'])
app = login(app)
resp = app.get(create_formdata['source_formdef'].get_url(backoffice=True))
# click on first available formdata
resp = resp.click('%s-%s' % (create_formdata['source_formdef'].id, formdata.id))
target_data_class = create_formdata['target_formdef'].data_class()
assert target_data_class.count() == 0
# resubmit it through backoffice submission
resp = resp.form.submit(name='button_resubmit')
assert pub.loggederror_class.count() == 0
assert target_data_class.count() == 1
target_formdata = target_data_class.select()[0]
assert target_formdata.submission_context == {
'orig_object_type': 'formdef',
'orig_formdata_id': '1',
'orig_formdef_id': '1',
}
assert target_formdata.submission_agent_id == str(create_formdata['admin'].id)
assert target_formdata.user.id == user.id
assert target_formdata.status == 'draft'
assert resp.location == 'http://example.net/backoffice/management/target-form/%s/' % target_formdata.id
resp = resp.follow()
assert resp.location == 'http://example.net/backoffice/submission/target-form/%s/' % target_formdata.id
resp = resp.follow()
# second redirect with magic-token
resp = resp.follow()
resp = resp.form.submit(name='submit') # -> validation
resp = resp.form.submit(name='submit') # -> submission
target_formdata = target_data_class.get(id=target_formdata.id)
assert target_formdata.user.id == user.id
assert target_formdata.status == 'wf-new'
resp = resp.follow()
pq = resp.pyquery.remove_namespaces()
assert pq('.field-type-string .value').text() == 'coucou'
assert pq('.field-type-file .value').text() == 'bar'
resp = app.get(create_formdata['formdata'].get_url(backoffice=True))
pq = resp.pyquery.remove_namespaces()
assert pq('.field-type-string .value').text() == 'coucou'
if create_formdata['create_formdata'].attach_to_history:
assert pq('.wf-links')
else:
assert not pq('.wf-links')
def test_backoffice_create_formdata_map_fields_by_varname_plus_empty(pub, create_formdata):
create_formdata['create_formdata'].map_fields_by_varname = True
create_formdata['create_formdata'].mappings = [
Mapping(field_id='0', expression=None),
]
create_formdata['wf'].store()
create_formdata['source_formdef'].fields = [
fields.StringField(id='0', label='string', varname='string0'),
fields.StringField(id='2', label='string', varname='string2', required=False),
]
create_formdata['source_formdef'].store()
create_formdata['target_formdef'].fields = [
fields.StringField(id='0', label='string', varname='string0'),
fields.StringField(id='2', label='string', varname='string2', required=False),
]
create_formdata['target_formdef'].store()
# create submitting user
user = create_formdata['pub'].user_class()
user.name = 'Jean Darmette'
user.email = 'jean.darmette@triffouilis.fr'
user.store()
# create source formdata
formdata = create_formdata['source_formdef'].data_class()()
create_formdata['formdata'] = formdata
formdata.data = {
'0': 'foo',
'2': 'bar',
}
formdata.user = user
formdata.just_created()
formdata.store()
formdata.perform_workflow()
# agent login and go to backoffice management pages
app = get_app(create_formdata['pub'])
app = login(app)
resp = app.get(create_formdata['source_formdef'].get_url(backoffice=True))
# click on first available formdata
resp = resp.click('%s-%s' % (create_formdata['source_formdef'].id, formdata.id))
target_data_class = create_formdata['target_formdef'].data_class()
assert target_data_class.count() == 0
# resubmit it through backoffice submission
resp = resp.form.submit(name='button_resubmit')
assert target_data_class.count() == 1
target_formdata = target_data_class.select()[0]
assert target_formdata.submission_context == {
'orig_object_type': 'formdef',
'orig_formdata_id': '1',
'orig_formdef_id': '1',
}
assert target_formdata.submission_agent_id == str(create_formdata['admin'].id)
assert target_formdata.user.id == user.id
assert target_formdata.status == 'draft'
assert target_formdata.data == {'0': None, '2': 'bar'}
def test_backoffice_create_carddata_from_formdata(pub):
CardDef.wipe()
FormDef.wipe()
user = create_user(pub, is_admin=True)
user.name = 'Foo Bar'
user.email = 'foo@example.com'
user.store()
carddef = CardDef()
carddef.name = 'My card'
carddef.fields = [
fields.StringField(id='1', label='string'),
fields.ItemField(id='2', label='List', items=['item1', 'item2']),
fields.DateField(id='3', label='Date'),
]
carddef.store()
wf = Workflow(name='create-carddata')
st1 = wf.add_status('New')
st2 = wf.add_status('Create card')
jump = st1.add_action('choice', id='_createcard')
jump.label = 'Create card'
jump.by = ['_receiver']
jump.status = st2.id
create_card = st2.add_action('create_carddata', id='_create')
create_card.label = 'Create Card Data'
create_card.varname = 'mycard'
create_card.formdef_slug = carddef.url_name
create_card.mappings = [
Mapping(field_id='1', expression='Simple String'),
Mapping(field_id='2', expression='{{ form_var_list_raw }}'),
Mapping(field_id='3', expression='{{ form_var_date }}'),
]
display_message = st2.add_action('displaymsg')
display_message.message = 'Card nr. {{ form_links_mycard_form_number }} created'
wf.store()
formdef = FormDef()
formdef.name = 'Source form'
formdef.workflow_roles = {'_receiver': 1}
formdef.fields = [
fields.ItemField(id='1', label='List', items=['item1', 'item2'], varname='list'),
fields.DateField(id='2', label='Date', varname='date'),
]
formdef.workflow_id = wf.id
formdef.store()
formdata = formdef.data_class()()
today = time.strptime('2020-01-01', '%Y-%m-%d')
formdata.data = {'1': 'item2', '2': today}
formdata.user = user
formdata.just_created()
formdata.store()
formdata.perform_workflow()
app = login(get_app(pub))
resp = app.get(formdata.get_url(backoffice=True))
resp = resp.form.submit(name='button_createcard').follow()
assert 'Card nr. 1-1 created' in resp
# visit inspect page
resp = app.get(formdata.get_url(backoffice=True) + 'inspect')
assert "variables from parent's request" in resp
def test_backoffice_after_submit_location(pub):
create_superuser(pub)
workflow = Workflow(name='test')
st1 = workflow.add_status('Status1', 'st1')
commentable = st1.add_action('commentable', id='_commentable')
commentable.by = [logged_users_role().id]
commentable.required = True
workflow.store()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.workflow_roles = {'_receiver': 1}
formdef.workflow_id = workflow.id
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.status = 'wf-%s' % st1.id
formdata.store()
app = login(get_app(pub))
resp = app.get(formdata.get_url(backoffice=True))
resp.form['comment'] = 'plop'
resp = resp.form.submit('submit')
assert (
resp.location == 'http://example.net/backoffice/management/form-title/%s/#action-zone' % formdata.id
)
resp = resp.follow()
display = st1.add_action('displaymsg')
display.message = 'message-to-all'
display.to = []
workflow.store()
resp.form['comment'] = 'plop'
resp = resp.form.submit('submit')
assert resp.location == 'http://example.net/backoffice/management/form-title/%s/#' % formdata.id
def test_backoffice_http_basic_auth(pub):
access = ApiAccess()
access.name = 'test'
access.access_identifier = 'test'
access.access_key = '12345'
access.store()
create_superuser(pub)
app = get_app(pub)
app.set_authorization(('Basic', ('test', '12345')))
app.get('/backoffice/', status=403)
def test_backoffice_dispatch_lose_access(pub):
user = create_user(pub)
role1 = pub.role_class(name='xxx1')
role1.store()
role2 = pub.role_class(name='xxx2')
role2.store()
user.roles.append(role1.id)
user.store()
formdef = FormDef()
formdef.name = 'test dispatch lose access'
formdef.fields = []
wf = Workflow(name='dispatch')
st1 = wf.add_status('Status1')
dispatch = st1.add_action('dispatch', id='_dispatch')
dispatch.role_key = '_receiver'
dispatch.role_id = role2.id
add_function = st1.add_action('choice', id='_change_function')
add_function.label = 'Change function'
add_function.by = ['_receiver']
add_function.status = st1.id
wf.store()
formdef.workflow_id = wf.id
formdef.workflow_roles = {'_receiver': role1.id}
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/%s/%s/' % (formdef.url_name, formdata.id))
resp = resp.form.submit('button_add_function')
assert resp.location == '..' # no access -> to listing
def test_backoffice_dispatch_multi(pub):
user = create_user(pub)
role1 = pub.role_class(name='xxx1')
role1.store()
role2 = pub.role_class(name='xxx2')
role2.store()
user.roles.append(role1.id)
user.store()
formdef = FormDef()
formdef.name = 'test dispatch multi'
formdef.fields = []
wf = Workflow(name='dispatch')
wf.roles['_foobar'] = 'Foobar'
st1 = wf.add_status('Status1')
dispatch = st1.add_action('dispatch', id='_dispatch')
dispatch.role_key = '_receiver'
dispatch.role_id = role2.id
dispatch.operation_mode = 'add'
add_function = st1.add_action('choice', id='_add_function')
add_function.label = 'Add function'
add_function.by = ['_receiver']
add_function.status = st1.id
wf.store()
formdef.workflow_id = wf.id
formdef.workflow_roles = {'_receiver': role1.id}
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/%s/%s/' % (formdef.url_name, formdata.id))
resp = resp.form.submit('button_add_function').follow(status=200) # access to role1 is still ok
formdata.refresh_from_storage()
assert formdata.workflow_roles == {'_receiver': [role1.id, role2.id]}
@pytest.mark.parametrize(
'user_template',
[
'{{ session_user }}',
'{{ session_user_email }}',
'{{ session_user_nameid }}',
'{{ session_user_name }}',
'foobar', # a role, not an user
],
)
def test_backoffice_dispatch_single_user(pub, user_template):
pub.user_class.wipe()
user = create_user(pub)
user.name_identifiers = ['0123456789']
user.store()
formdef = FormDef()
formdef.name = 'test dispatch user'
formdef.fields = []
wf = Workflow(name='dispatch')
wf.roles['_foobar'] = 'Foobar'
st1 = wf.add_status('Status1')
dispatch = st1.add_action('dispatch', id='_dispatch')
dispatch.role_key = '_foobar'
dispatch.role_id = user_template
add_function = st1.add_action('choice', id='_add_function')
add_function.label = 'Add function'
add_function.by = ['_receiver']
add_function.status = st1.id
a_button = st1.add_action('choice', id='_a_button')
a_button.label = 'A button'
a_button.by = ['_foobar']
a_button.status = st1.id
wf.store()
formdef.workflow_id = wf.id
formdef.workflow_roles = {'_receiver': user.roles[0]}
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/management/%s/%s/' % (formdef.url_name, formdata.id))
assert 'button_a_button' not in resp.text
resp = resp.form.submit('button_add_function').follow(status=200)
formdata.refresh_from_storage()
if user_template != 'foobar':
assert formdata.workflow_roles == {'_foobar': ['_user:%s' % user.id]}
else:
# check role are still dispatched by name
assert formdata.workflow_roles == {'_foobar': [user.roles[0]]}
assert 'button_a_button' in resp.text