wcs/tests/test_admin_pages.py

5326 lines
187 KiB
Python

# -*- coding: utf-8 -*-
import datetime
from email.MIMEText import MIMEText
import json
import logging
import os
import re
import shutil
import StringIO
import tarfile
import urlparse
import time
import xml.etree.ElementTree as ET
import zipfile
try:
import lasso
except ImportError:
lasso = None
import pytest
from webtest import Upload
import mock
from quixote import cleanup, get_publisher
from quixote.http_request import Upload as QuixoteUpload
from wcs.qommon import errors, sessions
from wcs.qommon.form import UploadedFile
from wcs.qommon.ident.password_accounts import PasswordAccount
from wcs.qommon.http_request import HTTPRequest
from wcs.qommon.template import get_current_theme
from wcs.qommon.bounces import Bounce
from wcs.admin.settings import UserFieldsFormDef
from wcs.categories import Category
from wcs.data_sources import NamedDataSource
from wcs.wscalls import NamedWsCall
from wcs.roles import Role
from wcs.workflows import (Workflow, DisplayMessageWorkflowStatusItem,
WorkflowCriticalityLevel, WorkflowBackofficeFieldsFormDef,
CommentableWorkflowStatusItem)
from wcs.wf.export_to_model import ExportToModel
from wcs.wf.jump import JumpWorkflowStatusItem
from wcs.wf.register_comment import RegisterCommenterWorkflowStatusItem
from wcs.wf.wscall import WebserviceCallStatusItem
from wcs.formdef import FormDef
from wcs.carddef import CardDef
from wcs import fields
from utilities import get_app, login, create_temporary_pub, clean_temporary_pub, HttpRequestsMocking
def pytest_generate_tests(metafunc):
if 'pub' in metafunc.fixturenames:
metafunc.parametrize('pub', ['pickle', 'sql', 'pickle-templates'], indirect=True)
@pytest.fixture
def pub(request):
pub = create_temporary_pub(
sql_mode=bool('sql' in request.param),
templates_mode=bool('templates' in request.param)
)
req = HTTPRequest(None, {'SCRIPT_NAME': '/', 'SERVER_NAME': 'example.net'})
pub.set_app_dir(req)
pub.cfg['identification'] = {'methods': ['password']}
pub.cfg['language'] = {'language': 'en'}
pub.write_cfg()
return pub
def create_superuser(pub):
if pub.user_class.select(lambda x: x.name == 'admin'):
user1 = pub.user_class.select(lambda x: x.name == 'admin')[0]
user1.is_admin = True
user1.store()
return user1
user1 = pub.user_class(name='admin')
user1.is_admin = True
user1.store()
account1 = PasswordAccount(id='admin')
account1.set_password('admin')
account1.user_id = user1.id
account1.store()
return user1
def create_role():
Role.wipe()
role = Role(name='foobar')
role.store()
return role
def teardown_module(module):
clean_temporary_pub()
def test_empty_site(pub):
resp = get_app(pub).get('/backoffice/')
resp = resp.click('Users', index=0)
resp = resp.click('New User')
resp = get_app(pub).get('/backoffice/')
resp = resp.click('Settings', index=0)
def test_empty_site_but_idp_settings(pub):
pub.cfg['idp'] = {'xxx': {}}
pub.write_cfg()
resp = get_app(pub).get('/backoffice/')
assert resp.location == 'http://example.net/login/?next=http%3A%2F%2Fexample.net%2Fbackoffice%2F'
def test_with_user(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_with_superuser(pub):
create_superuser(pub)
app = login(get_app(pub))
app.get('/backoffice/')
def test_admin_redirect(pub):
create_superuser(pub)
app = login(get_app(pub))
assert app.get('/admin/whatever', status=302).location == 'http://example.net/backoffice/whatever'
def test_admin_for_all(pub):
user = create_superuser(pub)
role = create_role()
try:
open(os.path.join(pub.app_dir, 'ADMIN_FOR_ALL'), 'w').close()
resp = get_app(pub).get('/backoffice/', status=200)
# check there is a CSS class
assert 'class="admin-for-all"' in resp.body
# check there are menu items
resp.click('Management', index=0)
resp.click('Forms Workshop', index=0)
resp.click('Settings', index=0)
# cheeck it's possible to get inside the subdirectories
resp = get_app(pub).get('/backoffice/settings/', status=200)
pub.cfg['admin-permissions'] = {'settings': [role.id]}
pub.write_cfg()
resp = get_app(pub).get('/backoffice/settings/', status=200)
# check it doesn't work with a non-empty ADMIN_FOR_ALL file
fd = open(os.path.join(pub.app_dir, 'ADMIN_FOR_ALL'), 'w')
fd.write('x.x.x.x')
fd.close()
resp = get_app(pub).get('/backoffice/settings/', status=302)
# check it works if the file contains the user IP address
fd = open(os.path.join(pub.app_dir, 'ADMIN_FOR_ALL'), 'w')
fd.write('127.0.0.1')
fd.close()
resp = get_app(pub).get('/backoffice/settings/', status=200)
# check it's also ok if the user is logged in but doesn't have the
# permissions
user.is_admin = False
user.store()
resp = login(get_app(pub)).get('/backoffice/settings/', status=200)
# check there are menu items
resp.click('Management', index=0)
resp.click('Forms Workshop', index=0)
resp.click('Settings', index=0)
finally:
if 'admin-permissions' in pub.cfg:
del pub.cfg['admin-permissions']
pub.write_cfg()
os.unlink(os.path.join(pub.app_dir, 'ADMIN_FOR_ALL'))
role.remove_self()
user.is_admin = True
user.store()
def test_forms(pub):
user = create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/forms/')
assert 'You first have to define roles.' in resp.body
assert not 'New Form' in resp.body
def test_forms_new(pub):
user = create_superuser(pub)
app = login(get_app(pub))
create_role()
# create a new form
resp = app.get('/backoffice/forms/')
assert 'New Form' in resp.body
resp = resp.click('New Form')
resp.forms[0]['name'] = 'form title'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/'
resp = resp.follow()
assert '<h2>form title' in resp.body
# makes sure the data has been correctly saved
formdef = FormDef.get(1)
assert formdef.name == 'form title'
assert formdef.url_name == 'form-title'
assert formdef.fields == []
assert formdef.disabled == True
assert formdef.last_modification_user_id == str(user.id)
def test_forms_new_popup(pub):
FormDef.wipe()
user = create_superuser(pub)
app = login(get_app(pub))
create_role()
# create a new form
resp = app.get('/backoffice/forms/')
assert 'New Form' in resp.body
resp = resp.click('New Form', extra_environ={'HTTP_X_POPUP': 'true'})
assert 'popup-content' in resp.body
resp.forms[0]['name'] = 'form title'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/'
resp = resp.follow()
assert '<h2>form title' in resp.body
# makes sure the data has been correctly saved
formdef = FormDef.get(1)
assert formdef.name == 'form title'
assert formdef.url_name == 'form-title'
assert formdef.fields == []
assert formdef.disabled == True
assert formdef.last_modification_user_id == str(user.id)
def assert_option_display(resp, label, value):
option_line = re.findall('%s.*%s' % (label, value), resp.body, re.DOTALL)
assert option_line
assert not '</li>' in option_line
def test_forms_edit(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
# try changing an option
# confirmation page
assert_option_display(resp, 'Confirmation Page', 'Enabled')
resp = resp.click('Confirmation Page')
assert resp.forms[0]['confirmation'].checked
resp.forms[0]['confirmation'].checked = False
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/'
resp = resp.follow()
assert_option_display(resp, 'Confirmation Page', 'Disabled')
assert FormDef.get(1).confirmation == False
# try cancel button
resp = resp.click('Confirmation Page')
assert resp.forms[0]['confirmation'].checked is False
resp.forms[0]['confirmation'].checked = True
resp = resp.forms[0].submit('cancel')
assert resp.location == 'http://example.net/backoffice/forms/1/'
resp = resp.follow()
assert_option_display(resp, 'Confirmation Page', 'Disabled')
assert FormDef.get(1).confirmation == False
# Limit to one form
assert_option_display(resp, 'Limit to one form', 'Disabled')
resp = resp.click('Limit to one form')
assert resp.forms[0]['only_allow_one'].checked is False
resp.forms[0]['only_allow_one'].checked = True
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/'
resp = resp.follow()
assert_option_display(resp, 'Limit to one form', 'Enabled')
assert FormDef.get(1).only_allow_one is True
# Tracking code
assert_option_display(resp, 'Tracking Code', 'Disabled')
resp = resp.click('Tracking Code')
assert resp.forms[0]['enable_tracking_codes'].checked is False
resp.forms[0]['enable_tracking_codes'].checked = True
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/'
resp = resp.follow()
assert_option_display(resp, 'Tracking Code', 'Enabled')
assert FormDef.get(1).enable_tracking_codes is True
# CAPTCHA
assert_option_display(resp, 'CAPTCHA for anonymous users', 'Disabled')
resp = resp.click('CAPTCHA for anonymous users')
assert resp.forms[0]['has_captcha'].checked is False
resp.forms[0]['has_captcha'].checked = True
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/'
resp = resp.follow()
assert_option_display(resp, 'CAPTCHA for anonymous users', 'Enabled')
assert FormDef.get(1).has_captcha is True
# Appearance
assert_option_display(resp, 'Appearance', 'Standard')
resp = resp.click('Appearance')
assert resp.forms[0]['appearance_keywords'].value == ''
resp.forms[0]['appearance_keywords'] = 'foobar'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/'
resp = resp.follow()
assert_option_display(resp, 'Appearance', 'foobar')
assert FormDef.get(1).appearance_keywords == 'foobar'
# Publication
assert_option_display(resp, 'Online Status', 'Active')
resp = resp.click('Online Status')
assert resp.forms[0]['disabled'].checked is False
resp.forms[0]['disabled'].checked = True
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/'
resp = resp.follow()
assert_option_display(resp, 'Online Status', 'Disabled')
assert FormDef.get(1).disabled is True
resp = resp.click('Online Status')
assert resp.forms[0]['disabled'].checked is True
resp.forms[0]['disabled_redirection'] = 'http://www.example.net'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/'
resp = resp.follow()
assert_option_display(resp, 'Online Status', 'Redirected')
assert FormDef.get(1).disabled is True
assert FormDef.get(1).disabled_redirection == 'http://www.example.net'
resp = resp.click('Online Status')
resp.forms[0]['disabled'].checked = False
resp.forms[0]['expiration_date'] = '2000-01-01' # this is past(tm)
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/'
resp = resp.follow()
assert_option_display(resp, 'Online Status', 'Inactive by date')
# enable geolocation
resp = resp.click('Geolocation')
resp.forms[0]['geoloc_label'] = 'Foobar'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/'
resp = resp.follow()
assert_option_display(resp, 'Geolocation', 'Enabled')
assert FormDef.get(formdef.id).geolocations == {'base': 'Foobar'}
# and disable it
resp = resp.click('Geolocation')
resp.forms[0]['geoloc_label'] = ''
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/'
resp = resp.follow()
assert_option_display(resp, 'Geolocation', 'Disabled')
assert FormDef.get(formdef.id).geolocations is None
def test_form_title_change(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click('change title')
assert resp.form['name'].value == 'form title'
assert 'data-slug-sync' in resp.body
assert not 'change-nevertheless' in resp.body
resp.form['name'] = 'new title'
resp = resp.form.submit()
assert resp.location == 'http://example.net/backoffice/forms/1/'
resp = resp.follow()
formdef = FormDef.get(formdef.id)
assert formdef.name == 'new title'
assert formdef.url_name == 'form-title'
assert formdef.internal_identifier == 'new-title'
resp = app.get('/backoffice/forms/1/')
resp = resp.click('change title')
assert not 'data-slug-sync' in resp.body
assert not 'change-nevertheless' in resp.body
formdef.data_class()().store()
resp = app.get('/backoffice/forms/1/')
resp = resp.click('change title')
assert 'change-nevertheless' in resp.body
formdef2 = FormDef()
formdef2.name = 'other title'
formdef2.fields = []
formdef2.store()
resp = app.get('/backoffice/forms/%s/' % formdef2.id)
resp = resp.click('change title')
assert resp.form['name'].value == 'other title'
resp.form['url_name'] = formdef.url_name
resp = resp.form.submit()
assert 'This identifier is already used.' in resp.body
resp.form['url_name'] = 'foobar'
resp = resp.form.submit().follow()
assert FormDef.get(formdef2.id).url_name == 'foobar'
def test_form_category(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
assert_option_display(resp, 'Category', 'None')
Category.wipe()
cat = Category(name='Foo')
cat.store()
cat = Category(name='Bar')
cat.store()
resp = app.get('/backoffice/forms/1/')
assert 'Category' in resp.body
assert_option_display(resp, 'Category', 'None')
def test_form_category_select(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
Category.wipe()
cat = Category(name='Foo')
cat.store()
cat = Category(name='Bar')
cat.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='category')
resp = resp.forms[0].submit('cancel')
assert FormDef.get(formdef.id).category_id is None
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='category')
resp.forms[0]['category_id'] = cat.id
resp = resp.forms[0].submit('submit')
assert FormDef.get(formdef.id).category_id == cat.id
def test_form_workflow(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
assert_option_display(resp, 'Workflow', 'Default')
Workflow.wipe()
workflow = Workflow(name='Workflow One')
workflow.store()
workflow = Workflow(name='Workflow Two')
workflow.store()
resp = app.get('/backoffice/forms/1/')
assert_option_display(resp, 'Workflow', 'Default')
def test_form_workflow_change(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
Workflow.wipe()
workflow = Workflow(name='Workflow One')
workflow.store()
workflow = Workflow(name='Workflow Two')
workflow.possible_status = Workflow.get_default_workflow().possible_status[:]
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='workflow', index=1)
resp = resp.forms[0].submit('cancel')
assert FormDef.get(formdef.id).workflow_id is None
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='workflow', index=1)
assert 'Workflow One' not in resp.body # this workflow doesn't have any status
resp.forms[0]['workflow_id'] = workflow.id
resp = resp.forms[0].submit('submit')
assert FormDef.get(formdef.id).workflow_id == workflow.id
def test_form_workflow_link(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
Workflow.wipe()
workflow = Workflow(name='Workflow One')
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/%s/' % formdef.id)
assert '../workflows/_default/' in resp.body
formdef.workflow = workflow
formdef.store()
resp = app.get('/backoffice/forms/%s/' % formdef.id)
assert '../workflows/%s/' % workflow.id in resp.body
# check workflow link is not displayed if user has no access right
pub.cfg['admin-permissions'] = {'workflows': ['x']} # block access
pub.write_cfg()
resp = app.get('/backoffice/forms/%s/' % formdef.id)
assert '../workflows/%s/' % workflow.id not in resp.body
def test_form_workflow_remapping(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
data_class = formdef.data_class()
data_class.wipe()
formdata1 = data_class()
formdata1.status = 'wf-new'
formdata1.store()
formdata2 = data_class()
formdata2.status = 'draft'
formdata2.store()
Workflow.wipe()
workflow = Workflow(name='Workflow One')
workflow.store()
workflow = Workflow(name='Workflow Two')
# create it with a single status
workflow.possible_status = [Workflow.get_default_workflow().possible_status[-1]]
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='workflow', index=1)
resp.forms[0]['workflow_id'] = workflow.id
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/forms/1/workflow-status-remapping?new=2'
resp = resp.follow()
for status in Workflow.get_default_workflow().possible_status:
assert resp.forms[0]['mapping-%s' % status.id]
# there's only one possible new status
assert len(resp.forms[0]['mapping-just_submitted'].options) == 1
assert data_class.get(formdata1.id).status == 'wf-new'
assert data_class.get(formdata2.id).status == 'draft'
resp = resp.forms[0].submit()
assert data_class.get(formdata1.id).status == 'wf-finished'
assert data_class.get(formdata2.id).status == 'draft'
def test_form_submitter_roles(pub):
create_superuser(pub)
role = create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href=re.compile('^roles$'))
resp.form['roles$element0'] = 'logged-users'
assert not 'required_authentication_contexts' in resp.body
resp = resp.form.submit()
assert FormDef.get(formdef.id).roles == ['logged-users']
# add auth contexts support
if not pub.site_options.has_section('options'):
pub.site_options.add_section('options')
pub.site_options.set('options', 'auth-contexts', 'fedict')
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
pub.site_options.write(fd)
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href=re.compile('^roles$'))
assert 'required_authentication_contexts' in resp.body
resp.form['required_authentication_contexts$element0'].checked = True
resp = resp.form.submit()
resp = resp.follow()
assert FormDef.get(formdef.id).required_authentication_contexts == ['fedict']
# check internal roles are not advertised
role2 = Role(name='internal')
role2.internal = True
role2.store()
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href=re.compile('^roles$'))
assert len(resp.form['roles$element0'].options) == 3 # None, Logged users, foobar
with pytest.raises(ValueError):
resp.form['roles$element0'] = str(role2.id)
def test_form_workflow_role(pub):
create_superuser(pub)
role = create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='role/_receiver')
resp = resp.forms[0].submit('cancel')
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='role/_receiver')
resp.forms[0]['role_id'] = role.id
resp = resp.forms[0].submit('submit')
assert FormDef.get(1).workflow_roles == {'_receiver': '1'}
# check it doesn't fail if a second role with the same name exists
role = Role(name='foobar')
role.store()
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='role/_receiver')
def test_form_workflow_options(pub):
create_superuser(pub)
create_role()
Workflow.wipe()
workflow = Workflow(name='Workflow One')
workflow.store()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.workflow_id = workflow.id
formdef.workflow_options = {'2*1*body': 'xxx'}
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
assert '"workflow-options"' in resp.body
def test_form_workflow_variables(pub):
create_superuser(pub)
create_role()
Workflow.wipe()
workflow = Workflow(name='Workflow One')
from wcs.workflows import WorkflowVariablesFieldsFormDef
workflow.variables_formdef = WorkflowVariablesFieldsFormDef(workflow=workflow)
workflow.variables_formdef.fields.append(
fields.StringField(id='1', varname='test', label='Test', type='string'))
workflow.store()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.workflow_id = workflow.id
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
assert '"workflow-variables"' in resp.body
# visit the variables page
resp = resp.click(href='workflow-variables')
# and set a value
resp.forms[0]['f1'] = 'foobar'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/'
# check the value has been correctly saved
assert FormDef.get(formdef.id).workflow_options == {'test': 'foobar'}
# go back to the variables page, also check value
resp = resp.follow()
resp = resp.click(href='workflow-variables')
assert resp.forms[0]['f1'].value == 'foobar'
resp.forms[0]['f1'] = 'barbaz'
resp = resp.forms[0].submit('cancel')
assert resp.location == 'http://example.net/backoffice/forms/1/'
# check with a date field
workflow.variables_formdef.fields.append(
fields.DateField(id='2', varname='test2', label='Test2', type='date'))
workflow.store()
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='workflow-variables')
resp.form['f2'] = '2016-06-17'
resp = resp.form.submit()
assert time.strftime('%d %m %y', FormDef.get(formdef.id).workflow_options.get('test2')) == '17 06 16'
def test_form_workflow_table_variables(pub):
create_superuser(pub)
create_role()
Workflow.wipe()
workflow = Workflow(name='Workflow One')
from wcs.workflows import WorkflowVariablesFieldsFormDef
workflow.variables_formdef = WorkflowVariablesFieldsFormDef(workflow=workflow)
workflow.variables_formdef.fields.append(
fields.TableRowsField(id='1', varname='test', label='Test2',
type='tablerows', columns=['a']))
workflow.variables_formdef.fields.append(
fields.StringField(id='2', varname='test2', label='Test', type='string'))
workflow.store()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.workflow_id = workflow.id
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
assert '"workflow-variables"' in resp.body
# visit the variables page
resp = resp.click(href='workflow-variables')
# and set a value
resp.form['f1$element0$col0'] = 'foobar'
resp.form['f2'] = 'foobar'
resp = resp.form.submit('submit')
assert resp.location == 'http://example.net/backoffice/forms/1/'
# check the value has been correctly saved
assert FormDef.get(formdef.id).workflow_options == {
'test': [['foobar']],
'test2': 'foobar'}
# go back to the variables page, also check value
resp = resp.follow()
resp = resp.click(href='workflow-variables')
assert resp.form['f1$element0$col0'].value == 'foobar'
assert resp.form['f2'].value == 'foobar'
def test_form_roles(pub):
create_superuser(pub)
role = create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click('User Roles')
resp = resp.forms[0].submit('cancel')
resp = app.get('/backoffice/forms/1/')
resp = resp.click('User Roles')
resp.forms[0]['roles$element0'].value = role.id
resp = resp.forms[0].submit('submit')
assert FormDef.get(1).roles == [role.id]
def test_form_always_advertise(pub):
create_superuser(pub)
role = create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
# Display to unlogged users
formdef.roles = [role.id]
formdef.store()
resp = app.get('/backoffice/forms/1/')
assert_option_display(resp, 'Display to unlogged users', 'Disabled')
resp = resp.click('Display to unlogged users')
assert resp.forms[0]['always_advertise'].checked is False
resp.forms[0]['always_advertise'].checked = True
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/'
resp = resp.follow()
assert_option_display(resp, 'Display to unlogged users', 'Enabled')
assert FormDef.get(1).always_advertise is True
def test_form_digest_template(pub):
create_superuser(pub)
role = create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [fields.StringField(id='1', varname='test', label='Test', type='string')]
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.data = {'1': 'hello'}
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
# Display to unlogged users
assert_option_display(resp, 'Digest Template', 'None')
resp = resp.click('Digest Template')
resp.form['digest_template'] = 'X{{form_var_test}}Y'
resp = resp.form.submit()
assert resp.location == 'http://example.net/backoffice/forms/1/'
resp = resp.follow()
assert_option_display(resp, 'Digest Template', 'Custom')
formdef = FormDef.get(formdef.id)
assert formdef.digest_template == 'X{{form_var_test}}Y'
assert 'Existing forms will be updated in the background.' in resp.body
# afterjobs are actually run synchronously during tests; we don't have
# to wait to check the digest has been updated:
assert formdef.data_class().get(formdata.id).digest == 'XhelloY'
def test_form_delete(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='delete')
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/'
resp = resp.follow()
assert FormDef.count() == 0
def test_form_duplicate(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='duplicate')
assert resp.location == 'http://example.net/backoffice/forms/2/'
resp = resp.follow()
assert FormDef.count() == 2
assert FormDef.get(2).name == 'form title (copy)'
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='duplicate')
assert resp.location == 'http://example.net/backoffice/forms/3/'
resp = resp.follow()
assert FormDef.count() == 3
assert FormDef.get(3).name == 'form title (copy 2)'
def test_form_export(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='export')
xml_export = resp.body
fd = StringIO.StringIO(xml_export)
formdef2 = FormDef.import_from_xml(fd)
assert formdef2.name == 'form title'
def test_form_import(pub):
user = create_superuser(pub)
role = create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
formdef_xml = ET.tostring(formdef.export_to_xml(include_id=True))
FormDef.wipe()
assert FormDef.count() == 0
app = login(get_app(pub))
resp = app.get('/backoffice/forms/')
resp = resp.click(href='import')
resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml)
resp = resp.forms[0].submit()
assert FormDef.count() == 1
# import the same formdef a second time, make sure url name and internal
# identifier are not reused
resp = app.get('/backoffice/forms/')
resp = resp.click(href='import')
resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml)
resp = resp.forms[0].submit()
assert FormDef.count() == 2
assert FormDef.get(1).url_name == 'form-title'
assert FormDef.get(2).url_name == 'form-title-1'
assert FormDef.get(1).internal_identifier == 'form-title'
assert FormDef.get(2).internal_identifier == 'form-title-1'
# import a formdef with an url name that doesn't match its title,
# it should be kept intact.
formdef.url_name = 'xxx-other-form-title'
formdef_xml = ET.tostring(formdef.export_to_xml(include_id=True))
resp = app.get('/backoffice/forms/')
resp = resp.click(href='import')
resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml)
resp = resp.forms[0].submit()
assert FormDef.get(3).url_name == 'xxx-other-form-title'
assert FormDef.get(3).internal_identifier == 'form-title-2'
# import an invalid file
resp = app.get('/backoffice/forms/')
resp = resp.click(href='import')
resp.form['file'] = Upload('formdef.wcs', 'garbage')
resp = resp.form.submit()
assert 'Invalid File' in resp.body
# xml with duplicate id, fix it
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [
fields.StringField(id='42', label='1st field', type='string'),
fields.StringField(id='42', label='2nd field', type='string'),
]
formdef_xml = ET.tostring(formdef.export_to_xml(include_id=True))
FormDef.wipe()
resp = app.get('/backoffice/forms/')
resp = resp.click(href='import')
resp.form['file'] = Upload('formdef.wcs', formdef_xml)
resp = resp.form.submit()
resp = resp.follow()
assert 'form contained errors and has been automatically fixed' in resp.body
assert FormDef.count() == 1
assert FormDef.get(1).fields[0].id == '1'
assert FormDef.get(1).fields[1].id == '2'
def test_form_qrcode(pub):
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='qrcode')
assert '<div id="qrcode">' in resp.body
def test_form_description(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
assert_option_display(resp, 'Description', 'None')
resp = resp.click('Description')
resp.forms[0]['description'].value = '<p>Hello World</p>'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/'
resp = resp.follow()
assert_option_display(resp, 'Description', 'On')
def test_form_new_field(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='fields/')
assert 'There are not yet any fields for this form' in resp.body
resp.forms[0]['label'] = 'foobar'
resp.forms[0]['type'] = 'Text (line)'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/fields/'
resp = resp.follow()
assert 'foobar' in resp.body
assert 'Use drag and drop' in resp.body
assert len(FormDef.get(1).fields) == 1
assert FormDef.get(1).fields[0].key == 'string'
assert FormDef.get(1).fields[0].label == 'foobar'
# add a title too
resp.forms[0]['label'] = 'baz'
resp.forms[0]['type'] = 'Title'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/fields/'
resp = resp.follow()
# check it's in the preview
resp = app.get('/backoffice/forms/1/')
assert '<h3 data-field-id="1">baz</h3>' in resp.body
def test_form_delete_field(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [fields.StringField(id='1', label='1st field', type='string')]
formdef.store()
formdef.data_class().wipe()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='fields/')
assert '1st field' in resp.body
assert 'Use drag and drop' in resp.body
resp = resp.click(href='1/delete')
assert 'You are about to remove the "1st field" field.' in resp.body
assert 'Warning:' not in resp.body
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/fields/'
resp = resp.follow()
assert len(FormDef.get(1).fields) == 0
def test_form_delete_field_existing_data(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [
fields.StringField(id='1', label='1st field', type='string'),
fields.CommentField(id='2', label='comment field', type='comment'),
]
formdef.store()
formdef.data_class().wipe()
formdata = formdef.data_class()()
formdata.just_created()
formdata.data = {'1': 'hello'}
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='fields/')
resp = resp.click(href='1/delete')
assert 'You are about to remove the "1st field" field.' in resp.body
assert 'Warning:' in resp.body
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/fields/#itemId_2'
resp = resp.follow()
assert len(FormDef.get(1).fields) == 1
# check non-data fields do not show this warning
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='fields/')
resp = resp.click(href='2/delete')
assert 'You are about to remove the "comment field" field.' in resp.body
assert 'Warning:' not in resp.body
resp = resp.forms[0].submit()
resp = resp.follow()
assert len(FormDef.get(1).fields) == 0
def test_form_duplicate_field(pub):
user = create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [fields.StringField(id='1', label='1st field', type='string')]
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='fields/')
assert '1st field' in resp.body
resp = resp.click(href='1/duplicate')
assert resp.location == 'http://example.net/backoffice/forms/1/fields/#itemId_2'
resp = resp.follow()
assert len(FormDef.get(1).fields) == 2
assert FormDef.get(1).fields[0].label == '1st field'
assert FormDef.get(1).fields[1].label == '1st field'
def test_form_duplicate_file_field(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='fields/')
# add a first field
resp.forms[0]['label'] = 'foobar'
resp.forms[0]['type'] = 'File Upload'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/%s/fields/' % formdef.id
resp = resp.follow()
assert 'foobar' in resp.body
resp = resp.click(href='%s/duplicate' % FormDef.get(formdef.id).fields[0].id)
assert resp.location == 'http://example.net/backoffice/forms/1/fields/#itemId_2'
resp = resp.follow()
def test_form_edit_field(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [fields.StringField(id='1', label='1st field', type='string')]
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='fields/')
assert '1st field' in resp.body
resp = resp.click('Edit', href='1/')
assert resp.forms[0]['label'].value == '1st field'
resp.forms[0]['label'] = 'changed field'
resp.forms[0]['required'] = False
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/forms/1/fields/#itemId_1'
assert FormDef.get(1).fields[0].label == 'changed field'
assert FormDef.get(1).fields[0].required == False
def test_form_edit_field_advanced(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [fields.StringField(id='1', label='1st field', type='string')]
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='fields/')
assert '1st field' in resp.body
resp = resp.click('Edit', href='1/')
assert resp.forms[0]['label'].value == '1st field'
assert '<legend>Additional parameters</legend>' in resp.body
assert '<label for="form_prefill">Prefill</label>' in resp.body
# check the "prefill" field is under additional parameters
assert resp.body.index('<legend>Additional parameters</legend>') < \
resp.body.index('<label for="form_prefill">Prefill</label>')
# complete the "prefill" field
resp.forms[0]['prefill$type'] = 'String / Template'
resp.forms[0]['prefill$value_string'] = 'test'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/forms/1/fields/#itemId_1'
resp = resp.follow()
assert FormDef.get(formdef.id).fields[0].prefill == {'type': 'string', 'value': 'test'}
# do the same with 'data sources' field
resp = resp.click('Edit', href='1/')
assert resp.forms[0]['label'].value == '1st field'
assert '<legend>Additional parameters</legend>' in resp.body
assert '<label for="form_data_source">Data Source</label>' in resp.body
# check the "data source" field is under additional parameters
assert resp.body.index('<legend>Additional parameters</legend>') < \
resp.body.index('<label for="form_data_source">Data Source</label>')
# start filling the "data source" field
resp.forms[0]['data_source$type'] = 'json'
resp.forms[0]['data_source$value'] = 'http://example.net'
resp = resp.forms[0].submit('submit')
resp = resp.follow()
# it should now appear before the additional parameters section
resp = resp.click('Edit', href='1/')
assert resp.body.index('<legend>Additional parameters</legend>') > \
resp.body.index('<label for="form_data_source">Data Source</label>')
def test_form_prefill_field(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [fields.StringField(id='1', label='1st field', type='string')]
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/fields/1/')
resp.form['prefill$type'] = 'String / Template'
resp.form['prefill$value_string'] = 'test'
resp = resp.form.submit('submit').follow()
assert FormDef.get(formdef.id).fields[0].prefill == {'type': 'string', 'value': 'test'}
resp = app.get('/backoffice/forms/1/fields/1/')
resp.form['prefill$type'] = 'Python Expression'
resp.form['prefill$value_formula'] = 'True'
resp = resp.form.submit('submit').follow()
assert FormDef.get(formdef.id).fields[0].prefill == {'type': 'formula', 'value': 'True'}
resp = app.get('/backoffice/forms/1/fields/1/')
resp.form['prefill$type'] = 'String / Template'
resp.form['prefill$value_string'] = '{{form_var_toto}}'
resp = resp.form.submit('submit').follow()
assert FormDef.get(formdef.id).fields[0].prefill == {'type': 'string', 'value': '{{form_var_toto}}'}
# check error handling
resp = app.get('/backoffice/forms/1/fields/1/')
resp.form['prefill$type'] = 'Python Expression'
resp.form['prefill$value_formula'] = ':'
resp = resp.form.submit('submit')
assert 'invalid expression: unexpected EOF while parsing' in resp.body
resp = app.get('/backoffice/forms/1/fields/1/')
resp.form['prefill$type'] = 'String / Template'
resp.form['prefill$value_string'] = '{% if %}'
resp = resp.form.submit('submit')
assert 'syntax error in Django template: Unexpected end of expression' in resp.body
def test_form_edit_string_field_validation(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [fields.StringField(id='1', label='1st field', type='string')]
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='fields/')
assert '1st field' in resp.body
resp = resp.click('Edit', href='1/')
resp.form['validation$type'] = 'Regular Expression'
resp.form['validation$value_regex'] = r'\d+'
resp = resp.form.submit('submit').follow()
assert FormDef.get(formdef.id).fields[0].validation == {'type': 'regex', 'value': r'\d+'}
resp = resp.click('Edit', href='1/')
resp.form['validation$type'] = 'None'
resp = resp.form.submit('submit').follow()
assert FormDef.get(formdef.id).fields[0].validation is None
resp = resp.click('Edit', href='1/')
resp.form['validation$type'] = 'Django Condition'
resp.form['validation$value_django'] = 'value|decimal < 20'
resp = resp.form.submit('submit').follow()
assert FormDef.get(formdef.id).fields[0].validation == {'type': 'django', 'value': 'value|decimal < 20'}
resp = resp.click('Edit', href='1/')
resp.form['validation$type'] = 'Django Condition'
resp.form['validation$value_django'] = '{{ value|decimal < 20 }}'
resp = resp.form.submit('submit')
assert 'syntax error' in resp.body
def test_form_edit_item_field(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [fields.ItemField(id='1', label='1st field', type='item')]
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='fields/')
assert '1st field' in resp.body
resp = resp.click('Edit', href='1/')
assert resp.forms[0]['label'].value == '1st field'
resp.forms[0]['label'] = 'changed field'
resp.forms[0]['required'] = False
resp = resp.forms[0].submit('items$add_element')
# this adds a second field
assert 'items$element0' in resp.form.fields
assert 'items$element1' in resp.form.fields
# but don't fill anything
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/forms/1/fields/#itemId_1'
resp = resp.follow()
assert FormDef.get(1).fields[0].label == 'changed field'
assert FormDef.get(1).fields[0].required == False
assert FormDef.get(1).fields[0].items is None
# edit and fill with one item
resp = resp.click('Edit', href='1/')
assert resp.forms[0]['label'].value == 'changed field'
resp.forms[0]['items$element0'] = 'XXX'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/forms/1/fields/#itemId_1'
assert FormDef.get(1).fields[0].items == ['XXX']
def test_form_edit_item_field_data_source(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [fields.ItemField(id='1', label='1st field', type='item')]
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/fields/1/')
assert resp.form['data_source$type'].options == [
(u'None', True, u'None'),
(u'json', False, u'JSON URL'),
(u'jsonp', False, u'JSONP URL'),
(u'python', False, u'Python Expression')
]
resp = resp.form.submit('submit').follow()
data_source = NamedDataSource(name='Foobar')
data_source.data_source = {'type': 'formula', 'value': '[]'}
data_source.store()
resp = app.get('/backoffice/forms/1/fields/1/')
assert resp.form['data_source$type'].options == [
(u'None', True, u'None'),
(u'foobar', False, u'Foobar'),
(u'json', False, u'JSON URL'),
(u'jsonp', False, u'JSONP URL'),
(u'python', False, u'Python Expression')
]
resp.form['data_source$type'].value = 'foobar'
resp = resp.form.submit('submit').follow()
assert FormDef.get(formdef.id).fields[0].data_source == {'type': 'foobar'}
carddef = CardDef()
carddef.name = 'Baz'
carddef.store()
resp = app.get('/backoffice/forms/1/fields/1/')
assert resp.form['data_source$type'].options == [
(u'None', False, u'None'),
(u'foobar', True, u'Foobar'),
(u'json', False, u'JSON URL'),
(u'jsonp', False, u'JSONP URL'),
(u'python', False, u'Python Expression')
]
carddef.digest_template = 'plop'
carddef.store()
resp = app.get('/backoffice/forms/1/fields/1/')
assert resp.form['data_source$type'].options == [
(u'None', False, u'None'),
(u'carddef:%s' % carddef.url_name, False, u'Baz'),
(u'foobar', True, u'Foobar'),
(u'json', False, u'JSON URL'),
(u'jsonp', False, u'JSONP URL'),
(u'python', False, u'Python Expression')
]
resp.form['data_source$type'].value = 'carddef:%s' % carddef.url_name
resp = resp.form.submit('submit').follow()
assert FormDef.get(formdef.id).fields[0].data_source == {'type': 'carddef:%s' % carddef.url_name}
# set json source then back to none
resp = app.get('/backoffice/forms/1/fields/1/')
resp.form['data_source$type'].value = 'json'
resp.form['data_source$value'].value = 'http://whatever'
resp = resp.form.submit('submit').follow()
assert FormDef.get(formdef.id).fields[0].data_source == {'type': 'json', 'value': 'http://whatever'}
resp = app.get('/backoffice/forms/1/fields/1/')
resp.form['data_source$type'].value = 'None'
resp = resp.form.submit('submit').follow()
resp = app.get('/backoffice/forms/1/')
def test_form_edit_items_field(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [fields.ItemsField(id='1', label='1st field', type='items')]
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='fields/')
assert '1st field' in resp.body
resp = resp.click('Edit', href='1/')
assert resp.forms[0]['label'].value == '1st field'
resp.forms[0]['label'] = 'changed field'
resp.forms[0]['required'] = False
resp = resp.forms[0].submit('items$add_element')
# this adds a second field
assert 'items$element0' in resp.form.fields
assert 'items$element1' in resp.form.fields
# but don't fill anything
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/forms/1/fields/#itemId_1'
resp = resp.follow()
assert FormDef.get(1).fields[0].label == 'changed field'
assert FormDef.get(1).fields[0].required == False
assert FormDef.get(1).fields[0].items is None
# edit and fill with one item
resp = resp.click('Edit', href='1/')
assert resp.forms[0]['label'].value == 'changed field'
resp.forms[0]['items$element0'] = 'XXX'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/forms/1/fields/#itemId_1'
assert FormDef.get(1).fields[0].items == ['XXX']
# check prefilling is only possible with Python
resp = resp.follow()
resp = resp.click('Edit', href='1/')
assert resp.forms[0]['prefill$type'].options == [
(u'None', True, u'None'), (u'Python Expression', False, u'Python Expression')]
def test_form_edit_page_field(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='fields/')
assert 'There are not yet any fields for this form' in resp.body
resp.forms[0]['label'] = 'foobar'
resp.forms[0]['type'] = 'Page'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/fields/'
resp = resp.follow()
assert 'Page #1' in resp.body
assert 'foobar' in resp.body
assert 'Use drag and drop' in resp.body
assert len(FormDef.get(1).fields) == 1
assert FormDef.get(1).fields[0].key == 'page'
assert FormDef.get(1).fields[0].label == 'foobar'
resp = resp.click('Edit', href='1/')
resp.form['post_conditions$element0$condition$type'] = 'python'
resp.form['post_conditions$element0$condition$value_python'] = 'foo'
resp.form['post_conditions$element0$error_message'] = 'bar'
resp = resp.form.submit('post_conditions$add_element')
resp.form['post_conditions$element1$condition$type'] = 'python'
resp.form['post_conditions$element1$condition$value_python'] = 'foo2'
resp = resp.form.submit('submit')
assert 'Both condition and error message are required.' in resp.body
resp.form['post_conditions$element1$error_message'] = 'bar2'
resp = resp.form.submit('submit').follow()
assert FormDef.get(1).fields[0].post_conditions == [
{'condition': {'type': 'python', 'value': 'foo'}, 'error_message': 'bar'},
{'condition': {'type': 'python', 'value': 'foo2'}, 'error_message': 'bar2'},
]
resp = resp.click('Edit', href='1/')
resp.form['post_conditions$element1$condition$type'] = 'django'
resp.form['post_conditions$element1$condition$value_django'] = 'foo3'
resp = resp.form.submit('submit').follow()
assert FormDef.get(1).fields[0].post_conditions == [
{'condition': {'type': 'python', 'value': 'foo'}, 'error_message': 'bar'},
{'condition': {'type': 'django', 'value': 'foo3'}, 'error_message': 'bar2'},
]
def test_form_edit_comment_field(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [fields.CommentField(id='1', label='a comment field', type='comment')]
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/fields/1/')
assert 'a comment field' in resp.body
assert 'WysiwygTextWidget' in resp.body
# legacy, double line breaks will be converted to paragraphs
formdef.fields = [fields.CommentField(id='1', type='comment',
label='a comment field\n\na second line')]
formdef.store()
resp = app.get('/backoffice/forms/1/fields/1/')
assert 'WysiwygTextWidget' in resp.body
resp = resp.form.submit('submit')
assert FormDef.get(formdef.id).fields[0].label == '<p>a comment field</p>\n<p>a second line</p>'
# starting with a <
formdef.fields = [fields.CommentField(id='1', type='comment',
label='<strong>a comment field\n\na second line</strong>')]
formdef.store()
resp = app.get('/backoffice/forms/1/fields/1/')
assert 'WysiwygTextWidget' in resp.body
# legacy, ezt syntax in a non-html field will be presented as a textarea
formdef.fields = [fields.CommentField(id='1', type='comment',
label='[if-any toto]hello world[end]')]
formdef.store()
resp = app.get('/backoffice/forms/1/fields/1/')
assert 'WysiwygTextWidget' not in resp.body
# check a new field is created with label as HTML, enclosing label in <p>
resp = app.get('/backoffice/forms/1/fields/')
resp.forms[0]['label'] = 'foobar'
resp.forms[0]['type'] = 'Comment'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/fields/'
assert FormDef.get(formdef.id).fields[-1].label == '<p>foobar</p>'
# unless label is already given as HTML
resp = app.get('/backoffice/forms/1/fields/')
resp.forms[0]['label'] = '<div>blah</div>'
resp.forms[0]['type'] = 'Comment'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/fields/'
assert FormDef.get(formdef.id).fields[-1].label == '<div>blah</div>'
def test_form_edit_map_field(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [fields.MapField(id='1', label='a field', type='map')]
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/fields/1/')
resp = resp.form.submit('submit')
assert resp.location
# min
formdef.store()
resp = app.get('/backoffice/forms/1/fields/1/')
resp.form['min_zoom'] = 'Wide area'
resp = resp.form.submit('submit')
assert FormDef.get(formdef.id).fields[0].min_zoom == '9'
# max
formdef.store()
resp = app.get('/backoffice/forms/1/fields/1/')
resp.form['max_zoom'] = 'Small road'
resp = resp.form.submit('submit')
assert FormDef.get(formdef.id).fields[0].max_zoom == '16'
# both
formdef.store()
resp = app.get('/backoffice/forms/1/fields/1/')
resp.form['min_zoom'] = 'Wide area'
resp.form['max_zoom'] = 'Small road'
resp = resp.form.submit('submit')
assert FormDef.get(formdef.id).fields[0].min_zoom == '9'
assert FormDef.get(formdef.id).fields[0].max_zoom == '16'
# inverted
formdef.store()
resp = app.get('/backoffice/forms/1/fields/1/')
resp.form['min_zoom'] = 'Small road'
resp.form['max_zoom'] = 'Wide area'
resp = resp.form.submit('submit')
assert 'widget-with-error' in resp.body
# initial out of range
formdef.store()
resp = app.get('/backoffice/forms/1/fields/1/')
resp.form['initial_zoom'] = 'Whole world'
resp.form['min_zoom'] = 'Wide area'
resp.form['max_zoom'] = 'Small road'
resp = resp.form.submit('submit')
assert 'widget-with-error' in resp.body
# prefill fields
resp = app.get('/backoffice/forms/1/fields/1/')
resp.form['prefill$type'].value = 'Geolocation'
resp.form['prefill$value_geolocation'].value = 'Position'
resp = resp.form.submit('submit')
assert FormDef.get(formdef.id).fields[0].prefill == {
'type': 'geolocation', 'value': 'position'}
def test_form_edit_field_warnings(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [fields.StringField(id='%d' % i, label='field %d' % i, type='string')
for i in range(1,10)]
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='fields/')
assert 'more than 500 fields' not in resp.body
assert 'first field should be of type "page"' not in resp.body
formdef.fields.append(fields.PageField(id='1000', label='page', type='page'))
formdef.store()
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='fields/')
assert 'more than 500 fields' not in resp.body
assert 'first field should be of type "page"' in resp.body
formdef.fields.extend([fields.StringField(id='%d' % i, label='field %d' % i, type='string')
for i in range(10,510)])
formdef.store()
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='fields/')
assert 'more than 500 fields' in resp.body
assert 'first field should be of type "page"' in resp.body
FormDef.wipe()
def test_form_limit_display_to_page(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [fields.PageField(id='0', label='1st page', type='page'),
fields.StringField(id='1', label='string', type='string', varname='foobar'),
fields.PageField(id='2', label='2nd page', type='page'),
fields.StringField(id='3', label='string 2', type='string', varname='baz')]
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/fields/')
assert '{{form_var_foobar}}' in resp.body
assert '2nd page' in resp.body
resp = resp.click('Limit display to this page', index=0)
hidden_fields = ''.join(re.findall('display:none.*', resp.body))
assert 'Display all pages' in resp.body
assert '{{form_var_foobar}}' not in hidden_fields
assert '{{form_var_baz}}' in hidden_fields
def test_form_legacy_int_id(pub):
create_superuser(pub)
create_role()
Category.wipe()
cat = Category(name='Foo')
cat.store()
Workflow.wipe()
workflow = Workflow(name='Workflow One')
# create it with a single status
workflow.possible_status = [Workflow.get_default_workflow().possible_status[-1]]
workflow.store()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
role = Role(name='ZAB') # Z to get sorted last
role.store()
# set attributes using integers
formdef.category_id = int(cat.id)
formdef.workflow_id = int(workflow.id)
formdef.workflow_roles = {'_receiver': int(role.id)}
formdef.roles = ['logged-users', int(role.id)]
formdef.store()
formdef = FormDef.get(formdef.id) # will run migrate
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='category')
assert resp.forms[0]['category_id'].value
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='workflow', index=1)
assert resp.forms[0]['workflow_id'].value
resp = app.get('/backoffice/forms/1/')
resp = resp.click('User Roles')
assert resp.forms[0]['roles$element0'].value == 'logged-users'
assert resp.forms[0]['roles$element1'].value == role.id
resp = app.get('/backoffice/forms/1/')
resp = resp.click('Recipient')
assert resp.forms[0]['role_id'].value == role.id
def test_form_anonymise(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
data_class = formdef.data_class()
data_class.wipe()
for i in range(10):
formdata = data_class()
formdata.just_created()
if i < 3:
formdata.status = 'wf-new'
else:
formdata.status = 'wf-rejected'
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='anonymise')
resp = resp.form.submit('cancel')
assert len([x for x in formdef.data_class().select() if x.anonymised]) == 0
assert resp.location == 'http://example.net/backoffice/forms/1/'
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='anonymise')
resp = resp.form.submit('submit')
assert resp.location == 'http://example.net/backoffice/forms/1/'
assert len([x for x in formdef.data_class().select() if x.anonymised]) == 0
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='anonymise')
resp.form['before_request_date'].value = (datetime.datetime.today() +
datetime.timedelta(days=1)).strftime('%Y-%m-%d')
resp = resp.form.submit('submit')
assert resp.location == 'http://example.net/backoffice/forms/1/'
assert len([x for x in formdef.data_class().select() if x.anonymised]) == 7
data_class.wipe()
for i in range(110):
formdata = data_class()
formdata.just_created()
if i < 3:
formdata.status = 'wf-rejected'
else:
formdata.status = 'wf-finished'
formdata.store()
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='anonymise')
resp.form['before_request_date'].value = (datetime.datetime.today() +
datetime.timedelta(days=1)).strftime('%Y-%m-%d')
resp.form['endpoints$elementfinished'].checked = False
resp = resp.form.submit('submit')
assert '?job=' in resp.location
resp = resp.follow()
assert 'job-status' in resp.body
assert 'completed' in resp.body
assert len([x for x in formdef.data_class().select() if x.anonymised]) == 3
def test_form_public_url(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click('Display public URL')
assert 'http://example.net/form-title/' in resp.body
def test_form_archive(pub):
create_superuser(pub)
create_role()
if pub.is_using_postgresql():
# this doesn't exist in SQL
pytest.skip('no archive in SQL mode')
return
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
data_class = formdef.data_class()
data_class.wipe()
for i in range(10):
formdata = data_class()
formdata.just_created()
if i < 3:
formdata.status = 'wf-new'
else:
formdata.status = 'wf-rejected'
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='archive')
resp = resp.form.submit('cancel')
assert data_class.count() == 10
assert resp.location == 'http://example.net/backoffice/forms/1/'
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='archive')
resp = resp.form.submit('submit')
assert resp.content_type == 'application/x-wcs-archive'
tf = tarfile.open(fileobj=StringIO.StringIO(resp.body))
assert 'formdef' in [x.name for x in tf.getmembers()]
assert len(tf.getmembers()) == 8 # 7 formdata + 1 formdef
# second archive, it shouldn't get anything (but the formdef)
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='archive')
resp = resp.form.submit('submit')
assert resp.content_type == 'application/x-wcs-archive'
tf = tarfile.open(fileobj=StringIO.StringIO(resp.body))
assert 'formdef' in [x.name for x in tf.getmembers()]
assert len(tf.getmembers()) == 1 # 0 formdata + 1 formdef
def test_form_overwrite(pub):
user = create_superuser(pub)
role = create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form test'
formdef.table_name = 'xxx'
formdef.fields = [fields.StringField(id='1', label='1st field', type='string'),
fields.StringField(id='2', label='2nd field', type='string')]
formdef.store()
formdata = formdef.data_class()()
formdata.data = {'1': 'foo', '2': 'bar'}
formdata.just_created()
formdata.store()
formdef_id = formdef.id
formdef.fields[0].label = '1st modified field'
formdef_xml = ET.tostring(formdef.export_to_xml(include_id=True))
app = login(get_app(pub))
resp = app.get('/backoffice/forms/%s/' % formdef_id)
resp = resp.click(href='overwrite')
resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml)
resp = resp.forms[0].submit()
assert FormDef.get(formdef_id).fields[0].label == '1st modified field'
resp = resp.follow()
assert 'The form has been successfully overwritten.' in resp.body
# check with added/removed field
formdef = FormDef()
formdef.name = 'form test overwrite'
formdef.fields = [
fields.StringField(id='2', label='2nd field', type='string'),
fields.StringField(id='3', label='3rd field', type='string')]
formdef_xml = ET.tostring(formdef.export_to_xml(include_id=True))
app = login(get_app(pub))
resp = app.get('/backoffice/forms/%s/' % formdef_id)
resp = resp.click(href='overwrite')
resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml)
resp = resp.forms[0].submit()
assert 'The form removes and changes fields' in resp.body
assert not 'The form has incompatible fields, it may cause data corruption and bugs' in resp.body
resp = resp.forms[0].submit()
assert FormDef.get(formdef_id).fields[0].id == '2'
assert FormDef.get(formdef_id).fields[0].label == '2nd field'
assert FormDef.get(formdef_id).fields[1].id == '3'
assert FormDef.get(formdef_id).fields[1].label == '3rd field'
# check with a field of different type
formdef = FormDef()
formdef.name = 'form test overwrite'
formdef.fields = [
fields.StringField(id='2', label='2nd field', type='string'),
fields.TextField(id='3', label='3rd field, text', type='text')]
formdef_xml = ET.tostring(formdef.export_to_xml(include_id=True))
app = login(get_app(pub))
resp = app.get('/backoffice/forms/%s/' % formdef_id)
resp = resp.click(href='overwrite', index=0)
resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml)
resp = resp.forms[0].submit()
assert 'The form removes and changes fields' in resp.body
assert 'The form has incompatible fields, it may cause data corruption and bugs' in resp.body
resp.forms[0]['force'] = True
resp = resp.forms[0].submit()
assert FormDef.get(formdef_id).fields[1].id == '3'
assert FormDef.get(formdef_id).fields[1].label == '3rd field, text'
assert FormDef.get(formdef_id).fields[1].type == 'text'
# check we kept stable references
assert FormDef.get(formdef_id).url_name == 'form-test'
assert FormDef.get(formdef_id).table_name == 'xxx'
def test_form_export_import_export_overwrite(pub):
create_superuser(pub)
create_role()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.table_name = 'xxx'
formdef.fields = [ # unordered id
fields.StringField(id='1', label='field 1', type='string'),
fields.DateField(id='12', label='field 2', type='date'),
fields.ItemField(id='4', label='field 3', type='item'),
]
formdef.store()
formdef_xml = ET.tostring(formdef.export_to_xml(include_id=True))
assert FormDef.count() == 1
assert formdef.url_name == 'form-title'
app = login(get_app(pub))
resp = app.get('/backoffice/forms/')
resp = resp.click(href='import')
resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml)
resp = resp.forms[0].submit()
assert FormDef.count() == 2
formdef2 = FormDef.get(2)
assert formdef2.url_name == 'form-title-1'
# fields are imported with original ids
for i, field in enumerate(formdef.fields):
field2 = formdef2.fields[i]
assert (field.id, field.label, field.type) == (field2.id, field2.label, field2.type)
# modify imported formdef, then overwrite original formdef with it
formdef2.fields.insert(2, fields.StringField(id='2', label='field 4', type='string'))
formdef2.fields.insert(3, fields.DateField(id='3', label='field 5', type='date'))
formdef2.fields.append(fields.ItemField(id='5', label='field 6', type='item'))
formdef2.store()
formdef2_xml = ET.tostring(formdef2.export_to_xml(include_id=True))
resp = app.get('/backoffice/forms/%s/' % formdef.id)
resp = resp.click(href='overwrite')
resp.forms[0]['file'] = Upload('formdef.wcs', formdef2_xml)
resp = resp.forms[0].submit()
formdef_overwrited = FormDef.get(formdef.id)
for i, field in enumerate(formdef2.fields):
field_ow = formdef_overwrited.fields[i]
assert (field.id, field.label, field.type) == (field_ow.id, field_ow.label, field_ow.type)
def test_form_comment_with_error_in_wscall(http_requests, pub):
create_superuser(pub)
NamedWsCall.wipe()
wscall = NamedWsCall(name='xxx')
wscall.description = 'description'
wscall.request = {
'url': 'http://remote.example.net/404',
'request_signature_key': 'xxx',
'qs_data': {'a': 'b'},
'method': 'POST',
'post_data': {'c': 'd'},
}
wscall.store()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [fields.CommentField(id='1',
label='x [webservice.xxx.foobar] x', type='comment')]
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/%s/' % formdef.id)
assert 'x [webservice.xxx.foobar] x' in resp.body
def test_workflows(pub):
app = login(get_app(pub))
app.get('/backoffice/workflows/')
def test_workflows_default(pub):
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/')
assert 'Default' in resp.body
resp = resp.click(href='_default')
assert 'Just Submitted' in resp.body
assert 'This is the default workflow' in resp.body
# makes sure it cannot be edited
assert 'Edit' not in resp.body
# and makes sure status are not editable either
resp = resp.click('Just Submitted')
assert '<h2>Just Submitted' in resp.body
assert 'Change Status Name' not in resp.body
assert 'Delete' not in resp.body
def test_workflows_new(pub):
user = create_superuser(pub)
role = create_role()
Workflow.wipe()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/')
# create a new workflow
resp = resp.click('New Workflow')
resp.forms[0]['name'] = 'a new workflow'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/workflows/1/'
resp = resp.follow()
assert 'There are not yet any status defined in this workflow' in resp.body
assert not '<svg ' in resp.body
# create a new status
resp.forms[0]['name'] = 'new status'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/workflows/1/'
resp = resp.follow()
assert '<svg ' in resp.body
assert not '@import ' in resp.body
# create a new action
resp = resp.click('new status')
resp.forms[0]['action-interaction'] = 'Alert'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/workflows/1/status/1/'
resp = resp.follow()
assert 'Use drag and drop' in resp.body
# fill action
resp = resp.click('Alert')
resp.forms[0]['message'] = 'bla bla bla'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/workflows/1/status/1/items/'
resp = resp.follow()
assert resp.location == 'http://example.net/backoffice/workflows/1/status/1/'
wf = Workflow.get(1)
assert wf.name == 'a new workflow'
assert wf.possible_status[0].name == 'new status'
assert wf.possible_status[0].items[0].message == 'bla bla bla'
def test_workflows_svg(pub):
user = create_superuser(pub)
role = create_role()
Workflow.wipe()
workflow = Workflow(name='foo')
st1 = workflow.add_status(name='baz')
commentable = CommentableWorkflowStatusItem()
commentable.id = '_commentable'
commentable.by = [role.id]
commentable.label = 'foobar'
st1.items.append(commentable)
commentable.parent = st1
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/%s/svg' % workflow.id)
assert resp.content_type == 'image/svg+xml'
assert '/static/css/dc2/admin.css' in resp.body
def test_workflows_edit(pub):
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/1/')
resp = resp.click(href='edit')
assert resp.forms[0]['name'].value == 'foo'
resp.forms[0]['name'] = 'baz'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/workflows/1/'
resp = resp.follow()
assert 'baz' in resp.body
def test_workflows_edit_status(pub):
create_superuser(pub)
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.add_status(name='baz')
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/1/')
resp = resp.click('baz')
resp = resp.click('Change Status Name')
resp.forms[0]['name'] = 'bza'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/workflows/1/status/1/'
resp = resp.follow()
assert Workflow.get(1).possible_status[0].name == 'bza'
resp = resp.click('Change Display Settings')
resp.forms[0]['hide_status_from_user'].checked = True
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/workflows/1/status/1/'
resp = resp.follow()
assert Workflow.get(1).possible_status[0].visibility == ['_receiver']
resp = resp.click('Change Terminal Status')
resp.forms[0]['force_terminal_status'].checked = True
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/workflows/1/status/1/'
resp = resp.follow()
assert Workflow.get(1).possible_status[0].forced_endpoint == True
resp = resp.click('Change Display Settings')
assert resp.forms[0]['colour'].value == 'FFFFFF'
assert resp.forms[0]['extra_css_class'].value == ''
resp.forms[0]['colour'] = 'FF0000'
resp.forms[0]['extra_css_class'] = 'plop'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/workflows/1/status/1/'
resp = resp.follow()
assert Workflow.get(1).possible_status[0].colour == 'FF0000'
assert Workflow.get(1).possible_status[0].extra_css_class == 'plop'
resp = resp.click('Change Display Settings')
assert resp.forms[0]['colour'].value == 'FF0000'
assert resp.forms[0]['extra_css_class'].value == 'plop'
resp.forms[0]['extra_css_class'] = 'xxx'
resp = resp.forms[0].submit('cancel')
assert Workflow.get(1).possible_status[0].extra_css_class == 'plop'
assert resp.location == 'http://example.net/backoffice/workflows/1/status/1/'
resp = resp.follow()
resp = resp.click('Change Backoffice Information Text')
assert resp.forms[0]['backoffice_info_text'].value == ''
resp.forms[0]['backoffice_info_text'] = '<p>Hello</p>'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/workflows/1/status/1/'
resp = resp.follow()
assert 'Hello' in Workflow.get(1).possible_status[0].backoffice_info_text
def test_workflows_delete_status(pub):
create_superuser(pub)
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.add_status(name='baz')
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/1/')
resp = resp.click('baz')
resp = resp.click('Delete')
resp = resp.form.submit('cancel')
assert resp.location == 'http://example.net/backoffice/workflows/1/status/1/'
resp = resp.follow()
resp = resp.click('Delete')
resp = resp.form.submit('submit')
assert resp.location == 'http://example.net/backoffice/workflows/1/'
resp = resp.follow()
def test_workflows_delete(pub):
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/1/')
resp = resp.click(href='delete')
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/workflows/'
resp = resp.follow()
assert Workflow.count() == 0
def test_workflows_export_import(pub):
create_superuser(pub)
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.add_status(name='baz')
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/1/')
resp = resp.click('Export')
assert resp.content_type == 'application/x-wcs-form'
wf_export = resp.body
resp = app.get('/backoffice/workflows/')
resp = resp.click('Import')
resp.form['file'] = Upload('xxx.wcs', wf_export)
resp = resp.form.submit('submit')
assert resp.location == 'http://example.net/backoffice/workflows/2/'
resp = resp.follow()
assert 'This workflow has been successfully imported' in resp.body
assert Workflow.get(2).name == 'Copy of foo'
resp = app.get('/backoffice/workflows/')
resp = resp.click('Import')
resp.form['file'] = Upload('xxx.wcs', 'garbage')
resp = resp.form.submit('submit')
assert 'Invalid File' in resp.body
assert Workflow.count() == 2
def test_workflows_export_import_create_role(pub):
create_superuser(pub)
Role.wipe()
role = Role()
role.name = 'PLOP'
role.store()
Workflow.wipe()
workflow = Workflow(name='foo')
st1 = workflow.add_status(name='baz')
commentable = CommentableWorkflowStatusItem()
commentable.id = '_commentable'
commentable.by = [role.id]
st1.items.append(commentable)
commentable.parent = st1
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/1/')
resp = resp.click('Export')
assert resp.content_type == 'application/x-wcs-form'
wf_export = resp.body
resp = app.get('/backoffice/workflows/')
resp = resp.click('Import')
resp.form['file'] = Upload('xxx.wcs', wf_export)
resp = resp.form.submit('submit')
assert resp.location == 'http://example.net/backoffice/workflows/2/'
resp = resp.follow()
assert 'This workflow has been successfully imported' in resp.body
assert Workflow.get(2).name == 'Copy of foo'
assert Workflow.get(2).possible_status[0].items[0].by == [role.id]
role.remove_self()
# automatically create role
resp = app.get('/backoffice/workflows/')
resp = resp.click('Import')
resp.form['file'] = Upload('xxx.wcs', wf_export)
resp = resp.form.submit('submit')
assert resp.location == 'http://example.net/backoffice/workflows/3/'
resp = resp.follow()
assert 'This workflow has been successfully imported' in resp.body
assert Workflow.get(3).name == 'Copy of foo (2)'
assert Role.count() == 1
assert Role.select()[0].name == 'PLOP'
assert Workflow.get(2).possible_status[0].items[0].by == [Role.select()[0].id]
# don't create role if they are managed by the identity provider
Role.wipe()
pub.cfg['sp'] = {'idp-manage-roles': True}
pub.write_cfg()
resp = app.get('/backoffice/workflows/')
resp = resp.click('Import')
resp.form['file'] = Upload('xxx.wcs', wf_export)
resp = resp.form.submit('submit')
assert 'Invalid File (Unknown referenced role (PLOP))' in resp.body
def test_workflows_duplicate(pub):
create_superuser(pub)
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.add_status(name='baz')
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/1/')
resp = resp.click('Duplicate')
assert resp.location == 'http://example.net/backoffice/workflows/2/'
resp = resp.follow()
assert Workflow.get(2).name == 'foo (copy)'
resp = app.get('/backoffice/workflows/1/')
resp = resp.click('Duplicate')
assert resp.location == 'http://example.net/backoffice/workflows/3/'
resp = resp.follow()
assert Workflow.get(3).name == 'foo (copy 2)'
def test_workflows_add_all_actions(pub):
create_superuser(pub)
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.add_status(name='baz')
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/1/')
resp = resp.click('baz')
for category in ('status-change', 'interaction', 'formdata-action', 'user-action'):
for action in [x[0] for x in resp.forms[0]['action-%s' % category].options if x[0]]:
resp.forms[0]['action-%s' % category] = action
resp = resp.forms[0].submit()
resp = resp.follow()
i = 1
for category in ('status-change', 'interaction', 'formdata-action', 'user-action'):
for action in [x[0] for x in resp.forms[0]['action-%s' % category].options if x[0]]:
resp = resp.click('Edit', href='items/%d/' % i, index=0)
resp = resp.forms[0].submit('cancel')
resp = resp.follow() # redirect to items/
resp = resp.follow() # redirect to ./
i += 1
def test_workflows_check_available_actions(pub):
create_superuser(pub)
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.add_status(name='baz')
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/1/')
resp = resp.click('baz')
assert not 'Criticality Levels' in [x[0] for x in resp.forms[0]['action-formdata-action'].options]
assert not 'SMS' in [x[0] for x in resp.forms[0]['action-interaction'].options]
assert not 'User Notification' in [x[0] for x in resp.forms[0]['action-interaction'].options]
if not pub.site_options.has_section('variables'):
pub.site_options.add_section('variables')
pub.site_options.set('variables', 'portal_url', 'https://www.example.net/')
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
pub.site_options.write(fd)
pub.cfg['sms'] = {'mode': 'foobar'}
pub.write_cfg()
workflow.criticality_levels = [WorkflowCriticalityLevel(name='green')]
workflow.store()
resp = app.get('/backoffice/workflows/1/')
resp = resp.click('baz')
assert 'Criticality Levels' in [x[0] for x in resp.forms[0]['action-formdata-action'].options]
assert 'SMS' in [x[0] for x in resp.forms[0]['action-interaction'].options]
assert 'User Notification' in [x[0] for x in resp.forms[0]['action-interaction'].options]
for action in ('Criticality Levels', 'SMS', 'User Notification'):
for category in ('status-change', 'interaction', 'formdata-action', 'user-action'):
if action in [x[0] for x in resp.forms[0]['action-%s' % category].options if x[0]]:
resp.forms[0]['action-%s' % category] = action
resp = resp.forms[0].submit()
resp = resp.follow()
for i in range(3):
resp = resp.click('Edit', href='items/%d/' % (i+1), index=0)
resp = resp.forms[0].submit('cancel')
resp = resp.follow() # redirect to items/
resp = resp.follow() # redirect to ./
def test_workflows_edit_dispatch_action(pub):
create_superuser(pub)
role = create_role()
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.add_status(name='baz')
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/1/')
resp = resp.click('baz')
resp.forms[0]['action-formdata-action'] = 'Function/Role Linking'
resp = resp.forms[0].submit()
resp = resp.follow()
resp = resp.click('Function/Role Linking')
resp.form['rules$element0$value'].value = 'FOOBAR'
resp.form['rules$element0$role_id'].value = str(role.id)
resp = resp.form.submit('submit')
resp = resp.follow()
resp = resp.follow()
resp = resp.click('Function/Role Linking')
assert resp.form['rules$element0$value'].value == 'FOOBAR'
resp.form['rules$element1$value'].value = 'BARFOO'
resp.form['rules$element1$role_id'].value = str(role.id)
resp = resp.form.submit('submit')
workflow = Workflow.get(workflow.id)
assert workflow.possible_status[0].items[0].rules == [
{'value': 'FOOBAR', 'role_id': '1'}, {'value': 'BARFOO', 'role_id': '1'}]
def test_workflows_edit_email_action(pub):
create_superuser(pub)
role = create_role()
Workflow.wipe()
workflow = Workflow(name='foo')
st1 = workflow.add_status(name='baz')
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/1/')
resp = resp.click('baz')
resp.forms[0]['action-interaction'] = 'Email'
resp = resp.forms[0].submit()
resp = resp.follow()
resp = resp.click('Email')
item_url = resp.request.url
ok_strings = [
'Hello world', # ordinary string
'Hello [world]', # unknown reference
'Hello [if-any world][world][end]', # unknown reference, in condition
'Hello world ][', # random brackets
]
for field in ('body', 'subject'):
for ok_string in ok_strings:
resp = app.get(item_url)
resp.form[field] = ok_string
resp = resp.form.submit('submit')
assert resp.location
resp = app.get(item_url)
resp.form[field] = 'Hello {% if world %}{{ world }}{% else %}.'
resp = resp.form.submit('submit')
assert 'syntax error in Django template' in resp.body and 'Unclosed tag' in resp.body
resp = app.get(item_url)
resp.form[field] = 'Hello {% if world %}{{ world }}{% else %}.{% endif %}{% endif %}'
resp = resp.form.submit('submit')
assert 'syntax error in Django template' in resp.body and 'Invalid block tag' in resp.body
resp = app.get(item_url)
resp.form[field] = 'Hello [if-any world][world][else].'
resp = resp.form.submit('submit')
assert 'syntax error in ezt template' in resp.body and 'unclosed block' in resp.body
resp = app.get(item_url)
resp.form[field] = 'Hello [if-any world][world][else].[end] [end]'
resp = resp.form.submit('submit')
assert 'syntax error in ezt template' in resp.body and 'unmatched [end]' in resp.body
# attachments without backoffice fields: python expressions
resp = app.get(item_url)
assert "Attachments (Python expressions)" in resp.body
resp.form['attachments$element0'] = 'form_var_upload_raw'
resp = resp.form.submit('submit')
assert resp.location
resp = app.get(item_url)
assert "Attachments (Python expressions)" in resp.body
assert resp.form['attachments$element0'].value == 'form_var_upload_raw'
sendmail = Workflow.get(workflow.id).get_status(st1.id).items[0]
assert sendmail.attachments == ['form_var_upload_raw']
# attachments with backoffice fields: select-with-other inputs
workflow = Workflow.get(workflow.id)
workflow.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(workflow)
workflow.backoffice_fields_formdef.fields = [
fields.FileField(id='bo1-1x', label='bo field 1', type='file', varname='upload'),
fields.FileField(id='bo2-2x', label='bo field 2', type='file', varname='upload2'),
fields.FileField(id='bo3-3x', label='bo field varnameless', type='file'),
]
workflow.store()
resp = app.get(item_url)
assert "Attachments" in resp.body
assert "Attachments (Python expressions)" not in resp.body
assert resp.form['attachments$element0$choice'].value == 'form_var_upload_raw'
assert len(resp.form['attachments$element0$choice'].options) == 5
resp.form['attachments$element1$choice'] = 'form_var_upload2_raw'
resp = resp.form.submit('submit')
assert resp.location
sendmail = Workflow.get(workflow.id).get_status(st1.id).items[0]
assert sendmail.attachments == ['form_var_upload_raw', 'form_var_upload2_raw']
resp = app.get(item_url)
resp.form['attachments$element2$choice'] = 'form_fbo3_3x'
resp = resp.form.submit('submit')
assert resp.location
sendmail = Workflow.get(workflow.id).get_status(st1.id).items[0]
assert sendmail.attachments == ['form_var_upload_raw', 'form_var_upload2_raw', 'form_fbo3_3x']
resp = app.get(item_url)
resp.form['attachments$element3$choice'] = '__other'
resp.form['attachments$element3$other'] = '{"content":"foo", "filename":"bar.txt"}'
resp = resp.form.submit('submit')
assert resp.location
sendmail = Workflow.get(workflow.id).get_status(st1.id).items[0]
assert sendmail.attachments == ['form_var_upload_raw', 'form_var_upload2_raw', 'form_fbo3_3x',
'{"content":"foo", "filename":"bar.txt"}']
# remove some backoffice fields: varnameless fbo3 disapear
workflow = Workflow.get(workflow.id)
workflow.backoffice_fields_formdef.fields = [
fields.FileField(id='bo2', label='bo field 2', type='file', varname='upload2'),
]
workflow.store()
resp = app.get(item_url)
resp = resp.form.submit('submit')
assert resp.location
sendmail = Workflow.get(workflow.id).get_status(st1.id).items[0]
assert sendmail.attachments == ['form_var_upload_raw', 'form_var_upload2_raw',
'{"content":"foo", "filename":"bar.txt"}']
# remove all backoffice fields
workflow = Workflow.get(workflow.id)
workflow.backoffice_fields_formdef.fields = []
workflow.store()
resp = app.get(item_url)
assert "Attachments (Python expressions)" in resp.body
resp = resp.form.submit('submit')
assert resp.location
sendmail = Workflow.get(workflow.id).get_status(st1.id).items[0]
assert sendmail.attachments == ['form_var_upload_raw', 'form_var_upload2_raw',
'{"content":"foo", "filename":"bar.txt"}']
# check condition has been saved as None, not {}.
assert sendmail.condition is None
resp = app.get(item_url)
resp.form['condition$type'] = 'python'
resp.form['condition$value_python'] = 'True'
resp = resp.form.submit('submit')
sendmail = Workflow.get(workflow.id).get_status(st1.id).items[0]
assert sendmail.condition == {'type': 'python', 'value': 'True'}
def test_workflows_edit_jump_previous(pub):
create_superuser(pub)
role = create_role()
Workflow.wipe()
workflow = Workflow(name='foo')
st1 = workflow.add_status(name='baz')
jump = JumpWorkflowStatusItem()
jump.id = '_jump'
jump.timeout = 86400
st1.items.append(jump)
jump.parent = st1
ac1 = workflow.add_global_action('Action', 'ac1')
jump_global = JumpWorkflowStatusItem()
jump_global.id = '_jump'
jump_global.timeout = 86400
ac1.items.append(jump_global)
jump_global.parent = ac1
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/1/status/1/items/_jump/')
assert not 'Previously Marked Status' in [x[2] for x in resp.form['status'].options]
jump.set_marker_on_status = True
workflow.store()
resp = app.get('/backoffice/workflows/1/status/1/items/_jump/')
assert 'Previously Marked Status' in [x[2] for x in resp.form['status'].options]
jump.set_marker_on_status = False
workflow.store()
resp = app.get('/backoffice/workflows/1/status/1/items/_jump/')
assert not 'Previously Marked Status' in [x[2] for x in resp.form['status'].options]
jump_global.set_marker_on_status = True
workflow.store()
resp = app.get('/backoffice/workflows/1/status/1/items/_jump/')
assert 'Previously Marked Status' in [x[2] for x in resp.form['status'].options]
resp = app.get('/backoffice/workflows/1/global-actions/ac1/items/_jump/')
assert 'Previously Marked Status' in [x[2] for x in resp.form['status'].options]
jump_global.set_marker_on_status = False
workflow.store()
resp = app.get('/backoffice/workflows/1/global-actions/ac1/items/_jump/')
assert not 'Previously Marked Status' in [x[2] for x in resp.form['status'].options]
def test_workflows_edit_jump_timeout(pub):
create_superuser(pub)
role = create_role()
Workflow.wipe()
workflow = Workflow(name='foo')
st1 = workflow.add_status(name='baz')
jump = JumpWorkflowStatusItem()
jump.id = '_jump'
jump.status = '1'
jump.timeout = 86400
st1.items.append(jump)
jump.parent = st1
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/1/status/1/items/_jump/')
resp.form['timeout'] = ''
resp = resp.form.submit('submit').follow().follow()
assert Workflow.get(workflow.id).possible_status[0].items[0].timeout is None
assert 'Automatic Jump (baz)' in resp.body
resp = app.get('/backoffice/workflows/1/status/1/items/_jump/')
resp.form['timeout'] = '90 minutes'
resp = resp.form.submit('submit').follow().follow()
assert Workflow.get(workflow.id).possible_status[0].items[0].timeout == 5400
assert 'Automatic Jump (to baz, timeout)' in resp.body
resp = app.get('/backoffice/workflows/1/status/1/items/_jump/')
resp.form['timeout'] = '=5400'
resp = resp.form.submit('submit').follow().follow()
assert Workflow.get(workflow.id).possible_status[0].items[0].timeout == '=5400'
assert 'Automatic Jump (to baz, timeout)' in resp.body
# check field switched to being a computed expression widget
resp = app.get('/backoffice/workflows/1/status/1/items/_jump/')
assert resp.body.count('ComputedExpressionWidget') == 1
def test_workflows_edit_sms_action(pub):
create_superuser(pub)
role = create_role()
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.add_status(name='baz')
workflow.store()
pub.cfg['sms'] = {'mode': 'foobar'}
pub.write_cfg()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/1/')
resp = resp.click('baz')
resp.form['action-interaction'] = 'SMS'
resp = resp.form.submit().follow()
resp = resp.click('SMS')
resp = resp.form.submit('to$add_element')
resp = resp.form.submit('to$add_element')
resp = resp.form.submit('to$add_element')
resp.form['to$element1$value_text'] = '12345'
resp = resp.form.submit('submit')
assert Workflow.get(workflow.id).possible_status[0].items[0].to == ['12345']
def test_workflows_edit_display_form_action(pub):
create_superuser(pub)
role = create_role()
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.add_status(name='baz')
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/1/')
resp = resp.click('baz')
resp.forms[0]['action-interaction'] = 'Form'
resp = resp.forms[0].submit()
resp = resp.follow()
resp = resp.click(re.compile('^Form$'))
resp = resp.click('Edit Fields')
resp.form['label'] = 'foobar'
resp.form['type'] = 'Text (line)'
resp = resp.form.submit()
resp = resp.follow()
assert 'foobar' in resp.body
resp = resp.click('Edit')
assert not 'display_locations' in resp.form.fields.keys()
assert 'condition$type' in resp.form.fields.keys()
resp = resp.form.submit('cancel')
resp = resp.follow()
resp = resp.click('Remove')
assert 'You are about to remove the "foobar" field.' in resp.body
assert not 'Warning:' in resp.body
def test_workflows_edit_choice_action(pub):
create_superuser(pub)
role = create_role()
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.add_status(name='baz')
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/1/')
resp = resp.click('baz')
resp.forms[0]['action-status-change'] = 'Manual Jump'
resp = resp.forms[0].submit()
resp = resp.follow()
resp = resp.click(href='items/1/', index=0)
assert 'Previously Marked Status' not in [x[2] for x in resp.form['status'].options]
resp.form['status'].value = 'baz'
resp = resp.form.submit('submit')
resp = resp.follow()
resp = resp.follow()
resp = resp.click(href='items/1/', index=0)
resp.form['set_marker_on_status'].value = True
resp = resp.form.submit('submit')
resp = resp.follow()
resp = resp.follow()
resp = resp.click(href='items/1/', index=0)
assert 'Previously Marked Status' in [x[2] for x in resp.form['status'].options]
def test_workflows_edit_choice_action_functions_only(pub):
create_superuser(pub)
role = create_role()
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.add_status(name='baz')
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/1/')
resp = resp.click('baz')
resp.forms[0]['action-status-change'] = 'Manual Jump'
resp = resp.forms[0].submit()
resp = resp.follow()
resp = resp.click(href='items/1/', index=0)
assert 'foobar' in [x[2] for x in resp.form['by$element0'].options]
assert '_receiver' in [x[0] for x in resp.form['by$element0'].options]
pub.site_options.set('options', 'workflow-functions-only', 'true')
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
pub.site_options.write(fd)
resp = app.get('/backoffice/workflows/1/')
resp = resp.click('baz')
resp = resp.click(href='items/1/', index=0)
assert 'foobar' not in [x[2] for x in resp.form['by$element0'].options]
assert '_receiver' in [x[0] for x in resp.form['by$element0'].options]
def test_workflows_action_subpath(pub):
create_superuser(pub)
role = create_role()
Workflow.wipe()
workflow = Workflow(name='foo')
baz_status = workflow.add_status(name='baz')
display_message = DisplayMessageWorkflowStatusItem()
display_message.parent = baz_status
baz_status.items.append(display_message)
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/%s/status/%s/items/1/' % (
workflow.id, baz_status.id))
resp = app.get('/backoffice/workflows/%s/status/%s/items/1/crash' % (
workflow.id, baz_status.id), status=404)
def test_workflows_display_action_ezt_validation(pub):
create_superuser(pub)
role = create_role()
Workflow.wipe()
workflow = Workflow(name='foo')
baz_status = workflow.add_status(name='baz')
display_message = DisplayMessageWorkflowStatusItem()
display_message.parent = baz_status
baz_status.items.append(display_message)
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/%s/status/%s/items/1/' % (
workflow.id, baz_status.id))
resp.form['message'] = 'Hello world'
resp = resp.form.submit('submit')
assert Workflow.get(workflow.id).possible_status[0].items[0].message == 'Hello world'
resp = app.get('/backoffice/workflows/%s/status/%s/items/1/' % (
workflow.id, baz_status.id))
resp.form['message'] = '{% if test %}test{% endif %}' # valid Django
resp = resp.form.submit('submit')
assert Workflow.get(workflow.id).possible_status[0].items[0].message == '{% if test %}test{% endif %}'
resp = app.get('/backoffice/workflows/%s/status/%s/items/1/' % (
workflow.id, baz_status.id))
resp.form['message'] = '{% if test %}test{% end %}' # invalid Django
resp = resp.form.submit('submit')
assert 'syntax error in Django template' in resp.body
resp = app.get('/backoffice/workflows/%s/status/%s/items/1/' % (
workflow.id, baz_status.id))
resp.form['message'] = '[if-any test]test[end]' # valid ezt
resp = resp.form.submit('submit')
assert Workflow.get(workflow.id).possible_status[0].items[0].message == '[if-any test]test[end]'
resp = app.get('/backoffice/workflows/%s/status/%s/items/1/' % (
workflow.id, baz_status.id))
resp.form['message'] = '[is test][end]' # invalid ezt
resp = resp.form.submit('submit')
assert 'syntax error in ezt template' in resp.body
def test_workflows_delete_action(pub):
create_superuser(pub)
role = create_role()
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.add_status(name='baz')
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/1/')
resp = resp.click('baz')
resp.forms[0]['action-interaction'] = 'Email'
resp = resp.forms[0].submit()
resp = resp.follow()
assert 'Email' in resp.body
resp = resp.click(href='items/1/delete')
resp = resp.form.submit('cancel')
assert resp.location == 'http://example.net/backoffice/workflows/1/status/1/'
resp = resp.follow()
resp = resp.click(href='items/1/delete')
resp = resp.form.submit('submit')
assert resp.location == 'http://example.net/backoffice/workflows/1/status/1/'
resp = resp.follow()
assert Workflow.get(workflow.id).possible_status[0].items == []
def test_workflows_variables(pub):
create_superuser(pub)
create_role()
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/1/')
resp = resp.click(href='variables/')
assert resp.location == 'http://example.net/backoffice/workflows/1/variables/fields/'
resp = resp.follow()
# makes sure we can't add page fields
assert 'value="Page"' not in resp.body
# add a simple field
resp.forms[0]['label'] = 'foobar'
resp.forms[0]['type'] = 'Text (line)'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/workflows/1/variables/fields/'
resp = resp.follow()
# check it's been saved correctly
assert 'foobar' in resp.body
assert len(Workflow.get(1).variables_formdef.fields) == 1
assert Workflow.get(1).variables_formdef.fields[0].key == 'string'
assert Workflow.get(1).variables_formdef.fields[0].label == 'foobar'
def test_workflows_variables_edit(pub):
test_workflows_variables(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/1/')
resp = resp.click(href='variables/', index=0)
assert resp.location == 'http://example.net/backoffice/workflows/1/variables/fields/'
resp = resp.follow()
resp = resp.click('Edit', href='1/')
assert resp.forms[0]['varname$name'].value == 'foobar'
assert not 'varname$select' in resp.forms[0].fields
workflow = Workflow.get(1)
baz_status = workflow.add_status(name='baz')
display_message = DisplayMessageWorkflowStatusItem()
display_message.parent = baz_status
baz_status.items.append(display_message)
workflow.store()
resp = app.get('/backoffice/workflows/1/variables/fields/')
resp = resp.click('Edit', href='1/')
assert 'varname$select' in resp.forms[0].fields
resp.forms[0]['varname$select'].value = '1*1*message'
resp = resp.forms[0].submit('submit')
assert Workflow.get(1).variables_formdef.fields[0].key == 'string'
assert Workflow.get(1).variables_formdef.fields[0].varname == '1*1*message'
def test_workflows_variables_with_export_to_model_action(pub):
test_workflows_variables(pub)
workflow = Workflow.get(1)
baz_status = workflow.add_status(name='baz')
export_to = ExportToModel()
export_to.label = 'create doc'
baz_status.items.append(export_to)
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/1/variables/fields/')
resp = resp.click('Edit', href='1/')
def test_workflows_backoffice_fields(pub):
create_superuser(pub)
create_role()
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.add_status(name='baz')
workflow.store()
formdef = FormDef()
formdef.name = 'form title'
formdef.workflow_id = workflow.id
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/1/')
resp = resp.click('baz')
assert not 'Set Backoffice Field' in resp.body
resp = app.get('/backoffice/workflows/1/')
resp = resp.click(href='backoffice-fields/')
assert resp.location == 'http://example.net/backoffice/workflows/1/backoffice-fields/fields/'
resp = resp.follow()
# makes sure we can't add page fields
assert 'value="Page"' not in resp.body
# add a simple field
resp.forms[0]['label'] = 'foobar'
resp.forms[0]['type'] = 'Text (line)'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/workflows/1/backoffice-fields/fields/'
resp = resp.follow()
assert Workflow.get(workflow.id).get_backoffice_fields()[0].required is True
# check it's been saved correctly
assert 'foobar' in resp.body
assert len(Workflow.get(1).backoffice_fields_formdef.fields) == 1
assert Workflow.get(1).backoffice_fields_formdef.fields[0].id.startswith('bo')
assert Workflow.get(1).backoffice_fields_formdef.fields[0].key == 'string'
assert Workflow.get(1).backoffice_fields_formdef.fields[0].label == 'foobar'
backoffice_field_id = Workflow.get(1).backoffice_fields_formdef.fields[0].id
formdef = FormDef.get(formdef.id)
data_class = formdef.data_class()
data_class.wipe()
formdata = data_class()
formdata.data = {backoffice_field_id: 'HELLO'}
formdata.status = 'wf-new'
formdata.store()
assert data_class.get(formdata.id).data[backoffice_field_id] == 'HELLO'
# check the "set backoffice fields" action is now available
resp = app.get('/backoffice/workflows/1/')
resp = resp.click('baz')
resp.forms[0]['action-formdata-action'] = 'Backoffice Data'
resp = resp.forms[0].submit()
resp = resp.follow()
# add a second field
resp = app.get('/backoffice/workflows/1/')
resp = resp.click(href='backoffice-fields/', index=0)
assert resp.location == 'http://example.net/backoffice/workflows/1/backoffice-fields/fields/'
resp = resp.follow()
resp.forms[0]['label'] = 'foobar2'
resp.forms[0]['type'] = 'Text (line)'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/workflows/1/backoffice-fields/fields/'
resp = resp.follow()
workflow = Workflow.get(workflow.id)
assert len(workflow.backoffice_fields_formdef.fields) == 2
first_field_id = workflow.backoffice_fields_formdef.fields[0].id
assert workflow.backoffice_fields_formdef.fields[1].id != first_field_id
# check there's no prefill field
resp = app.get('/backoffice/workflows/1/backoffice-fields/fields/%s/' % workflow.backoffice_fields_formdef.fields[1].id)
assert not 'prefill$type' in resp.form.fields.keys()
# add a title field
resp = app.get('/backoffice/workflows/1/backoffice-fields/fields/')
resp.forms[0]['label'] = 'foobar3'
resp.forms[0]['type'] = 'Title'
resp = resp.form.submit()
workflow = Workflow.get(workflow.id)
assert len(workflow.backoffice_fields_formdef.fields) == 3
# check backoffice fields are available in set backoffice fields action
resp = app.get('/backoffice/workflows/1/')
resp = resp.click('baz') # status
resp = resp.click('Backoffice Data')
options = [x[2] for x in resp.form['fields$element0$field_id'].options]
assert '' in options
assert 'foobar' in options
assert 'foobar2' in options
assert 'foobar3' not in options
resp.form['fields$element0$field_id'] = first_field_id
resp.form['fields$element0$value$value_text'] = 'Hello'
resp = resp.form.submit('submit')
workflow = Workflow.get(workflow.id)
assert workflow.possible_status[0].items[0].fields == [{'field_id': first_field_id, 'value': 'Hello'}]
def test_workflows_functions(pub):
create_superuser(pub)
create_role()
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('add function')
resp = resp.forms[0].submit('cancel')
assert Workflow.get(workflow.id).roles.keys() == ['_receiver']
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('add function')
resp.forms[0]['name'] = 'Other Function'
resp = resp.forms[0].submit('submit')
assert set(Workflow.get(workflow.id).roles.keys()) == set(['_receiver', '_other-function'])
assert Workflow.get(workflow.id).roles['_other-function'] == 'Other Function'
# test rename
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('Other Function')
resp = resp.forms[0].submit('cancel')
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('Other Function')
resp.forms[0]['name'] = 'Other Renamed Function'
resp = resp.forms[0].submit('submit')
assert set(Workflow.get(workflow.id).roles.keys()) == set(['_receiver', '_other-function'])
assert Workflow.get(workflow.id).roles['_other-function'] == 'Other Renamed Function'
# test new function with older name
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('add function')
resp.forms[0]['name'] = 'Other Function'
resp = resp.forms[0].submit('submit')
assert set(Workflow.get(workflow.id).roles.keys()) == set(
['_receiver', '_other-function', '_other-function-2'])
assert Workflow.get(workflow.id).roles['_other-function'] == 'Other Renamed Function'
assert Workflow.get(workflow.id).roles['_other-function-2'] == 'Other Function'
# test removal
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('Other Renamed Function')
resp = resp.forms[0].submit('delete')
assert set(Workflow.get(workflow.id).roles.keys()) == set(['_receiver', '_other-function-2'])
# make sure it's not possible to remove the "_receiver" key
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('Recipient')
assert not 'delete' in resp.forms[0].fields
def test_workflows_functions_vs_visibility(pub):
create_superuser(pub)
create_role()
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.possible_status = Workflow.get_default_workflow().possible_status[:]
workflow.store()
# restrict visibility
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('Just Submitted')
resp = resp.click('Change Display Settings')
resp.forms[0]['hide_status_from_user'].checked = True
resp = resp.forms[0].submit()
assert Workflow.get(workflow.id).possible_status[0].visibility == ['_receiver']
# add function, make sure visibility follows
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('add function')
resp.forms[0]['name'] = 'Other Function'
resp = resp.forms[0].submit('submit')
assert set(Workflow.get(workflow.id).roles.keys()) == set(['_receiver', '_other-function'])
assert Workflow.get(workflow.id).roles['_other-function'] == 'Other Function'
assert set(Workflow.get(workflow.id).possible_status[0].visibility) == set(
['_receiver', '_other-function'])
# restrict visibility in a different status, check it gets all the
# functions
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('Rejected')
resp = resp.click('Change Display Settings')
resp.forms[0]['hide_status_from_user'].checked = True
resp = resp.forms[0].submit()
assert set(Workflow.get(workflow.id).possible_status[2].visibility) == set(
['_receiver', '_other-function'])
def test_workflows_global_actions(pub):
create_superuser(pub)
create_role()
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('add global action')
resp = resp.forms[0].submit('cancel')
assert not Workflow.get(workflow.id).global_actions
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('add global action')
resp.forms[0]['name'] = 'Global Action'
resp = resp.forms[0].submit('submit')
# test adding action with same name
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('add global action')
resp.forms[0]['name'] = 'Global Action'
resp = resp.forms[0].submit('submit')
assert 'There is already an action with that name.' in resp.body
# test rename
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('Global Action')
resp = resp.click('Change Action Name')
resp = resp.form.submit('cancel')
resp = resp.follow()
resp = resp.click('Change Action Name')
resp.forms[0]['name'] = 'Renamed Action'
resp = resp.forms[0].submit('submit')
assert Workflow.get(workflow.id).global_actions[0].name == 'Renamed Action'
# test removal
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('Renamed Action')
resp = resp.click('Delete')
resp = resp.form.submit('cancel')
resp = resp.follow()
resp = resp.click('Delete')
resp = resp.form.submit('delete')
assert not Workflow.get(workflow.id).global_actions
def test_workflows_global_actions_edit(pub):
create_superuser(pub)
create_role()
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('add global action')
resp.forms[0]['name'] = 'Global Action'
resp = resp.forms[0].submit('submit')
resp = resp.follow()
# test adding all actions
for category in ('status-change', 'interaction', 'formdata-action', 'user-action'):
for action in [x[0] for x in resp.forms[0]['action-%s' % category].options if x[0]]:
resp.forms[0]['action-%s' % category] = action
resp = resp.forms[0].submit()
resp = resp.follow()
# test visiting
action_id = Workflow.get(workflow.id).global_actions[0].id
for item in Workflow.get(workflow.id).global_actions[0].items:
resp = app.get('/backoffice/workflows/%s/global-actions/%s/items/%s/' % (
workflow.id, action_id, item.id))
# test modifying a trigger
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('Global Action')
assert len(Workflow.get(workflow.id).global_actions[0].triggers) == 1
resp = resp.click(href='triggers/%s/' % Workflow.get(workflow.id).global_actions[0].triggers[0].id,
index=0)
assert resp.form['roles$element0'].value == 'None'
resp.form['roles$element0'].value = '_receiver'
resp = resp.form.submit('submit')
assert Workflow.get(workflow.id).global_actions[0].triggers[0].roles == ['_receiver']
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('Global Action')
resp = resp.click(href='triggers/%s/' % Workflow.get(workflow.id).global_actions[0].triggers[0].id,
index=0)
assert resp.form['roles$element0'].value == '_receiver'
resp.form['roles$element1'].value = '_submitter'
resp = resp.form.submit('submit')
assert Workflow.get(workflow.id).global_actions[0].triggers[0].roles == [
'_receiver', '_submitter']
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('Global Action')
resp = resp.click(href='triggers/%s/' % Workflow.get(workflow.id).global_actions[0].triggers[0].id,
index=0)
resp.form['roles$element1'].value = 'None'
resp = resp.form.submit('submit')
assert Workflow.get(workflow.id).global_actions[0].triggers[0].roles == ['_receiver']
def test_workflows_global_actions_timeout_triggers(pub):
create_superuser(pub)
create_role()
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('add global action')
resp.forms[0]['name'] = 'Global Action'
resp = resp.forms[0].submit('submit')
resp = resp.follow()
# test removing the existing manual trigger
resp = resp.click(href='triggers/%s/delete' % Workflow.get(workflow.id).global_actions[0].triggers[0].id)
resp = resp.forms[0].submit()
resp = resp.follow()
assert len(Workflow.get(workflow.id).global_actions[0].triggers) == 0
# test adding a timeout trigger
resp.forms[1]['type'] = 'Automatic'
resp = resp.forms[1].submit()
resp = resp.follow()
assert 'Automatic (not configured)' in resp.body
resp = resp.click(href='triggers/%s/' % Workflow.get(workflow.id).global_actions[0].triggers[0].id, index=0)
for invalid_value in ('foobar', '-'):
resp.form['timeout'] = invalid_value
resp = resp.form.submit('submit')
assert 'wrong format' in resp.body
resp.form['timeout'] = ''
resp = resp.form.submit('submit')
assert 'required field' in resp.body
resp.form['timeout'] = '3'
resp = resp.form.submit('submit').follow()
assert Workflow.get(workflow.id).global_actions[0].triggers[0].timeout == '3'
resp = resp.click(href='triggers/%s/' % Workflow.get(workflow.id).global_actions[0].triggers[0].id, index=0)
resp.form['timeout'] = '-2'
resp = resp.form.submit('submit').follow()
assert Workflow.get(workflow.id).global_actions[0].triggers[0].timeout == '-2'
def test_workflows_criticality_levels(pub):
create_superuser(pub)
create_role()
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('add criticality level')
resp = resp.forms[0].submit('cancel')
assert not Workflow.get(workflow.id).criticality_levels
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('add criticality level')
resp.forms[0]['name'] = 'vigilance'
resp = resp.forms[0].submit('submit')
assert len(Workflow.get(workflow.id).criticality_levels) == 1
assert Workflow.get(workflow.id).criticality_levels[0].name == 'vigilance'
# test rename
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('vigilance')
resp = resp.forms[0].submit('cancel')
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('vigilance')
resp.forms[0]['name'] = 'Vigilance'
resp = resp.forms[0].submit('submit')
assert len(Workflow.get(workflow.id).criticality_levels) == 1
assert Workflow.get(workflow.id).criticality_levels[0].name == 'Vigilance'
# add a second level
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('add criticality level')
resp.forms[0]['name'] = 'Alerte attentat'
resp = resp.forms[0].submit('submit')
assert len(Workflow.get(workflow.id).criticality_levels) == 2
assert Workflow.get(workflow.id).criticality_levels[0].name == 'Vigilance'
assert Workflow.get(workflow.id).criticality_levels[1].name == 'Alerte attentat'
# test reorder
level1_id = Workflow.get(workflow.id).criticality_levels[0].id
level2_id = Workflow.get(workflow.id).criticality_levels[1].id
app.get('/backoffice/workflows/%s/update_criticality_levels_order?order=%s;%s;' % (
workflow.id, level1_id, level2_id))
assert Workflow.get(workflow.id).criticality_levels[0].id == level1_id
assert Workflow.get(workflow.id).criticality_levels[1].id == level2_id
app.get('/backoffice/workflows/%s/update_criticality_levels_order?order=%s;%s;' % (
workflow.id, level2_id, level1_id))
assert Workflow.get(workflow.id).criticality_levels[0].id == level2_id
assert Workflow.get(workflow.id).criticality_levels[1].id == level1_id
# test removal
resp = app.get('/backoffice/workflows/%s/' % workflow.id)
resp = resp.click('Vigilance')
resp = resp.forms[0].submit('delete-level')
assert len(Workflow.get(workflow.id).criticality_levels) == 1
def test_workflows_wscall_label(pub):
create_superuser(pub)
create_role()
Workflow.wipe()
workflow = Workflow(name='foo')
baz_status = workflow.add_status(name='baz')
wscall = WebserviceCallStatusItem()
wscall.parent = baz_status
baz_status.items.append(wscall)
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/%s/status/%s/' % (workflow.id, baz_status.id))
assert 'Webservice' in resp.body
assert 'Webservice (' not in resp.body
wscall.label = 'foowscallbar'
workflow.store()
resp = app.get('/backoffice/workflows/%s/status/%s/' % (workflow.id, baz_status.id))
assert 'Webservice (foowscallbar)' in resp.body
def test_workflows_inspect_view(pub):
from wcs.workflows import WorkflowVariablesFieldsFormDef
from wcs.wf.form import FormWorkflowStatusItem, WorkflowFormFieldsFormDef
create_superuser(pub)
role = create_role()
Workflow.wipe()
workflow = Workflow(name='foo')
workflow.criticality_levels = [WorkflowCriticalityLevel(name='green')]
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=True),
]
workflow.variables_formdef = WorkflowVariablesFieldsFormDef(workflow=workflow)
workflow.variables_formdef.fields.append(fields.StringField(label='Test', type='string'))
foo_status = workflow.add_status(name='foo')
baz_status = workflow.add_status(name='baz')
baz_status.backoffice_info_text = 'Info text'
wscall = WebserviceCallStatusItem()
wscall.parent = baz_status
baz_status.items.append(wscall)
baz_status.backoffice_info_text = '<p>Hello</p>'
display_form = FormWorkflowStatusItem()
display_form.id = '_x'
display_form.formdef = WorkflowFormFieldsFormDef(item=display_form)
display_form.formdef.fields.append(fields.StringField(label='Test', type='string'))
display_form.formdef.fields.append(fields.StringField(label='Test2', type='string'))
display_form.backoffice_info_text = '<p>Foo</p>'
baz_status.items.append(display_form)
display_form.parent = baz_status
jump = JumpWorkflowStatusItem()
jump.id = '_jump'
jump.timeout = 86400
jump.status = foo_status.id
baz_status.items.append(jump)
jump.parent = baz_status
invalid_jump = JumpWorkflowStatusItem()
invalid_jump.id = '_invalid_jump'
invalid_jump.status = 'xxx'
baz_status.items.append(invalid_jump)
invalid_jump.parent = baz_status
ac1 = workflow.add_global_action('Action', 'ac1')
ac1.backoffice_info_text = '<p>Foo</p>'
add_to_journal = RegisterCommenterWorkflowStatusItem()
add_to_journal.id = '_add_to_journal'
add_to_journal.comment = 'HELLO WORLD'
ac1.items.append(add_to_journal)
add_to_journal.parent = ac1
trigger = ac1.triggers[0]
assert trigger.key == 'manual'
trigger.roles = [role.id]
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/%s/inspect' % workflow.id)
def test_workflows_unused(pub):
create_superuser(pub)
FormDef.wipe()
Workflow.wipe()
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/')
assert not 'Unused workflows' in resp.body
workflow = Workflow(name='Workflow One')
workflow.store()
resp = app.get('/backoffice/workflows/')
assert 'Unused workflows' in resp.body
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
resp = app.get('/backoffice/workflows/')
assert 'Unused workflows' in resp.body
formdef.workflow = workflow
formdef.store()
resp = app.get('/backoffice/workflows/')
assert not 'Unused workflows' in resp.body
workflow = Workflow(name='Workflow Two')
workflow.store()
resp = app.get('/backoffice/workflows/')
assert 'Unused workflows' in resp.body
def test_users_roles_menu_entries(pub):
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/')
assert 'Users' in resp.body
assert 'Roles' in resp.body
resp = app.get('/backoffice/menu.json')
assert 'Users' in [x['label'] for x in resp.json]
assert 'Roles' in [x['label'] for x in resp.json]
# don't include users/roles in menu if roles are managed by an external
# identity provider.
pub.cfg['sp'] = {'idp-manage-roles': True}
pub.write_cfg()
resp = app.get('/backoffice/')
assert 'Users' not in resp.body
assert 'Roles' not in resp.body
resp = app.get('/backoffice/menu.json')
assert 'Users' not in [x['label'] for x in resp.json]
assert 'Roles' not in [x['label'] for x in resp.json]
def test_users(pub):
create_superuser(pub)
app = login(get_app(pub))
app.get('/backoffice/users/')
def test_users_new(pub):
pub.user_class.wipe()
create_superuser(pub)
user_count = pub.user_class.count()
account_count = PasswordAccount.count()
app = login(get_app(pub))
resp = app.get('/backoffice/users/')
resp = resp.click('New User')
resp.forms[0]['name'] = 'a new user'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/users/'
resp = resp.follow()
assert 'a new user' in resp.body
resp = resp.click('a new user')
assert 'User - a new user' in resp.body
assert pub.user_class.count() == user_count + 1
assert PasswordAccount.count() == account_count
def test_users_new_with_account(pub):
pub.user_class.wipe()
create_superuser(pub)
user_count = pub.user_class.count()
account_count = PasswordAccount.count()
app = login(get_app(pub))
resp = app.get('/backoffice/users/')
resp = resp.click('New User')
resp.forms[0]['name'] = 'a second user'
resp.forms[0]['method_password$username'] = 'second-user'
resp.forms[0]['method_password$password'] = 'foobar'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/users/'
resp = resp.follow()
assert 'a second user' in resp.body
resp = resp.click('a second user')
assert 'User - a second user' in resp.body
assert pub.user_class.count() == user_count + 1
assert PasswordAccount.count() == account_count + 1
def test_users_edit(pub):
pub.user_class.wipe()
create_superuser(pub)
user = pub.user_class(name='foo bar')
user.store()
app = login(get_app(pub))
resp = app.get('/backoffice/users/%s/' % user.id)
resp = resp.click(href='edit')
resp.forms[0]['is_admin'].checked = True
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/users/%s/' % user.id
resp = resp.follow()
def test_users_edit_new_account(pub):
pub.user_class.wipe()
PasswordAccount.wipe()
create_superuser(pub)
user = pub.user_class(name='foo bar')
user.store()
account_count = PasswordAccount.count()
app = login(get_app(pub))
resp = app.get('/backoffice/users/%s/' % user.id)
resp = resp.click(href='edit')
resp.forms[0]['is_admin'].checked = True
resp.forms[0]['method_password$username'] = 'foo'
resp.forms[0]['method_password$password'] = 'bar'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/users/%s/' % user.id
resp = resp.follow()
assert PasswordAccount.count() == account_count + 1
def test_users_edit_edit_account(pub):
pub.user_class.wipe()
PasswordAccount.wipe()
create_superuser(pub)
user = pub.user_class(name='foo bar')
user.store()
account = PasswordAccount(id='test')
account.user_id = user.id
account.store()
assert PasswordAccount.has_key('test')
app = login(get_app(pub))
resp = app.get('/backoffice/users/%s/' % user.id)
resp = resp.click(href='edit')
resp.forms[0]['is_admin'].checked = True
resp.forms[0]['method_password$username'] = 'foo' # change username
resp.forms[0]['method_password$password'] = 'bar'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/users/%s/' % user.id
resp = resp.follow()
# makes sure the old account has been removed
assert not PasswordAccount.has_key('test')
assert PasswordAccount.has_key('foo')
assert PasswordAccount.get('foo').user_id == user.id
def test_users_edit_with_managing_idp(pub):
create_role()
pub.user_class.wipe()
pub.cfg['sp'] = {'idp-manage-user-attributes': True}
pub.write_cfg()
PasswordAccount.wipe()
create_superuser(pub)
user = pub.user_class(name='foo bar')
user.store()
app = login(get_app(pub))
resp = app.get('/backoffice/users/%s/' % user.id)
assert '>Manage Roles<' in resp.body
resp = resp.click(href='edit')
assert not 'email' in resp.form.fields
assert 'roles$added_elements' in resp.form.fields
pub.cfg['sp'] = {'idp-manage-roles': True}
pub.write_cfg()
resp = app.get('/backoffice/users/%s/' % user.id)
assert '>Edit<' in resp.body
resp = resp.click(href='edit')
assert 'email' in resp.form.fields
assert not 'roles$added_elements' in resp.form.fields
pub.cfg['sp'] = {'idp-manage-roles': True, 'idp-manage-user-attributes': True}
pub.write_cfg()
resp = app.get('/backoffice/users/%s/' % user.id)
assert not '/edit' in resp.body
def test_users_delete(pub):
pub.user_class.wipe()
PasswordAccount.wipe()
create_superuser(pub)
user = pub.user_class(name='foo bar')
user.store()
account = PasswordAccount(id='test')
account.user_id = user.id
account.store()
user_count = pub.user_class.count()
account_count = PasswordAccount.count()
app = login(get_app(pub))
resp = app.get('/backoffice/users/%s/' % user.id)
resp = resp.click(href='delete')
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/users/'
resp = resp.follow()
assert pub.user_class.count() == user_count - 1
assert PasswordAccount.count() == account_count - 1
def test_users_pagination(pub):
pub.user_class.wipe()
PasswordAccount.wipe()
create_superuser(pub)
for i in range(50):
user = pub.user_class(name='foo bar %s' % (i+1))
user.store()
app = login(get_app(pub))
resp = app.get('/backoffice/users/')
assert 'foo bar 10' in resp.body
assert 'foo bar 30' not in resp.body
resp = resp.click('Next Page')
assert 'foo bar 10' not in resp.body
assert 'foo bar 30' in resp.body
resp = resp.click('Previous Page')
assert 'foo bar 10' in resp.body
assert 'foo bar 30' not in resp.body
resp = resp.click('Next Page')
resp = resp.click('Next Page')
assert 'foo bar 50' in resp.body
def test_users_filter(pub):
pub.user_class.wipe()
PasswordAccount.wipe()
create_superuser(pub)
role = create_role()
for i in range(50):
user = pub.user_class(name='foo bar %s' % (i+1))
user.store()
for i in range(5):
user = pub.user_class(name='baz bar %s' % (i+1))
user.roles = [role.id]
user.store()
app = login(get_app(pub))
resp = app.get('/backoffice/users/')
assert 'admin' in resp.body # superuser
assert 'foo bar 10' in resp.body # simple user
# uncheck 'None'; unfortunately this doesn't work with webtest 1.3
# resp.forms[0].fields['role'][-1].checked = False
# resp = resp.forms[0].submit()
# therefore we fall back on using the URL
resp = app.get('/backoffice/users/?offset=0&limit=100&q=&filter=true&role=admin')
assert '>Number of filtered users: 1<' in resp.body
assert 'user-is-admin' in resp.body # superuser
assert 'foo bar 1' not in resp.body # simple user
assert 'baz bar 1' not in resp.body # user with role
resp = app.get('/backoffice/users/?offset=0&limit=100&q=&filter=true&role=1')
assert '>Number of filtered users: 5<' in resp.body
assert 'user-is-admin' not in resp.body # superuser
assert 'foo bar 10' not in resp.body # simple user
assert 'baz bar 1' in resp.body # user with role
def test_users_search(pub):
pub.user_class.wipe()
PasswordAccount.wipe()
create_superuser(pub)
for i in range(20):
user = pub.user_class(name='foo %s' % (i+1))
user.store()
for i in range(10):
user = pub.user_class(name='bar %s' % (i+1))
user.store()
app = login(get_app(pub))
resp = app.get('/backoffice/users/')
assert 'foo 10' in resp.body
resp.forms[0]['q'] = 'bar'
resp = resp.forms[0].submit()
assert 'foo 10' not in resp.body
assert 'bar 10' in resp.body
assert 'Number of filtered users: 10' in resp.body
def test_users_new_with_custom_formdef(pub):
pub.user_class.wipe()
formdef = UserFieldsFormDef(pub)
formdef.fields.append(fields.StringField(id='3', label='test', type='string'))
formdef.fields.append(fields.CommentField(id='4', label='test', type='comment'))
formdef.fields.append(fields.FileField(id='5', label='test', type='file', required=False))
formdef.store()
create_superuser(pub)
user_count = pub.user_class.count()
account_count = PasswordAccount.count()
app = login(get_app(pub))
resp = app.get('/backoffice/users/')
resp = resp.click('New User')
resp.form['name'] = 'a new user'
resp.form['f3'] = 'TEST'
resp = resp.form.submit('submit')
assert resp.location == 'http://example.net/backoffice/users/'
resp = resp.follow()
assert 'a new user' in resp.body
resp = resp.click('a new user')
assert 'User - a new user' in resp.body
assert 'TEST' in resp.body
assert pub.user_class.count() == user_count + 1
assert PasswordAccount.count() == account_count
def test_users_display_roles(pub):
pub.user_class.wipe()
user = create_superuser(pub)
role = create_role()
user.roles = [role.id, 'XXX']
user.store()
app = login(get_app(pub))
resp = app.get('/backoffice/users/%s/' % user.id)
assert role.name in resp.body
assert 'Unknown role (XXX)' in resp.body
def test_roles(pub):
app = login(get_app(pub))
app.get('/backoffice/roles/')
def test_roles_new(pub):
Role.wipe()
app = login(get_app(pub))
resp = app.get('/backoffice/roles/')
resp = resp.click('New Role')
resp.forms[0]['name'] = 'a new role'
resp.forms[0]['details'] = 'bla bla bla'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/roles/'
resp = resp.follow()
assert 'a new role' in resp.body
resp = resp.click('a new role')
assert '<h2>a new role' in resp.body
assert Role.get(1).name == 'a new role'
assert Role.get(1).details == 'bla bla bla'
def test_roles_edit(pub):
Role.wipe()
role = Role(name='foobar')
role.store()
app = login(get_app(pub))
resp = app.get('/backoffice/roles/1/')
assert 'Holders of this role are granted access to the backoffice' in resp.body
resp = resp.click(href='edit')
assert resp.forms[0]['name'].value == 'foobar'
resp.forms[0]['name'] = 'baz'
resp.forms[0]['details'] = 'bla bla bla'
resp.forms[0]['emails_to_members'].checked = True
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/roles/1/'
resp = resp.follow()
assert '<h2>baz' in resp.body
assert 'Holders of this role will receive all emails adressed to the role.' in resp.body
assert Role.get(1).details == 'bla bla bla'
assert Role.get(1).emails_to_members == True
def test_roles_matching_formdefs(pub):
Role.wipe()
role = Role(name='foo')
role.store()
FormDef.wipe()
app = login(get_app(pub))
resp = app.get('/backoffice/roles/1/')
assert 'form bar' not in resp.body
formdef = FormDef()
formdef.name = 'form bar'
formdef.roles = [role.id]
formdef.fields = []
formdef.store()
resp = app.get('/backoffice/roles/1/')
assert 'form bar' in resp.body
assert 'form baz' not in resp.body
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form baz'
formdef.fields = []
formdef.workflow_roles = {'_receiver': role.id}
formdef.store()
resp = app.get('/backoffice/roles/1/')
assert 'form baz' in resp.body
assert 'form bar' not in resp.body
def test_roles_delete(pub):
Role.wipe()
role = Role(name='foobar')
role.store()
app = login(get_app(pub))
resp = app.get('/backoffice/roles/1/')
resp = resp.click(href='delete')
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/roles/'
resp = resp.follow()
assert Role.count() == 0
def test_categories(pub):
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/forms/categories/')
def test_categories_legacy_urls(pub):
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/categories/')
assert resp.location.endswith('/backoffice/forms/categories/')
resp = app.get('/backoffice/categories/1')
assert resp.location.endswith('/backoffice/forms/categories/1')
resp = app.get('/backoffice/categories/1/')
assert resp.location.endswith('/backoffice/forms/categories/1/')
def test_categories_new(pub):
create_superuser(pub)
Category.wipe()
app = login(get_app(pub))
# go to the page and cancel
resp = app.get('/backoffice/forms/categories/')
resp = resp.click('New Category')
resp = resp.forms[0].submit('cancel')
assert resp.location == 'http://example.net/backoffice/forms/categories/'
# go to the page and add a category
resp = app.get('/backoffice/forms/categories/')
resp = resp.click('New Category')
resp.forms[0]['name'] = 'a new category'
resp.forms[0]['description'] = 'description of the category'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/forms/categories/'
resp = resp.follow()
assert 'a new category' in resp.body
resp = resp.click('a new category')
assert '<h2>a new category' in resp.body
assert Category.get(1).name == 'a new category'
assert Category.get(1).description == 'description of the category'
def test_categories_edit(pub):
create_superuser(pub)
Category.wipe()
category = Category(name='foobar')
category.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/categories/1/')
assert 'no form associated to this category' in resp.body
resp = resp.click(href='edit')
assert resp.forms[0]['name'].value == 'foobar'
resp.forms[0]['description'] = 'category description'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/forms/categories/'
resp = resp.follow()
resp = resp.click('foobar')
assert '<h2>foobar' in resp.body
assert Category.get(1).description == 'category description'
def test_categories_edit_duplicate_name(pub):
Category.wipe()
category = Category(name='foobar')
category.store()
category = Category(name='foobar2')
category.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/categories/1/')
resp = resp.click(href='edit')
assert resp.forms[0]['name'].value == 'foobar'
resp.forms[0]['name'] = 'foobar2'
resp = resp.forms[0].submit('submit')
assert 'This name is already used' in resp.body
resp = resp.forms[0].submit('cancel')
assert resp.location == 'http://example.net/backoffice/forms/categories/'
def test_categories_with_formdefs(pub):
Category.wipe()
category = Category(name='foobar')
category.store()
FormDef.wipe()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/categories/1/')
assert 'form bar' not in resp.body
formdef = FormDef()
formdef.name = 'form bar'
formdef.fields = []
formdef.category_id = category.id
formdef.store()
resp = app.get('/backoffice/forms/categories/1/')
assert 'form bar' in resp.body
assert 'no form associated to this category' not in resp.body
def test_categories_delete(pub):
Category.wipe()
category = Category(name='foobar')
category.store()
FormDef.wipe()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/categories/1/')
resp = resp.click(href='delete')
resp = resp.forms[0].submit('cancel')
assert resp.location == 'http://example.net/backoffice/forms/categories/1/'
assert Category.count() == 1
resp = app.get('/backoffice/forms/categories/1/')
resp = resp.click(href='delete')
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/categories/'
resp = resp.follow()
assert Category.count() == 0
def test_categories_edit_description(pub):
Category.wipe()
category = Category(name='foobar')
category.description = 'category description'
category.store()
app = login(get_app(pub))
# this URL is used for editing from the frontoffice, there's no link
# pointing to it in the admin.
resp = app.get('/backoffice/forms/categories/1/description')
assert resp.forms[0]['description'].value == 'category description'
resp.forms[0]['description'] = 'updated description'
# check cancel doesn't save the change
resp2 = resp.forms[0].submit('cancel')
assert resp2.location == 'http://example.net/backoffice/forms/categories/1/'
assert Category.get(1).description == 'category description'
# check submit does it properly
resp2 = resp.forms[0].submit('submit')
assert resp2.location == 'http://example.net/backoffice/forms/categories/1/'
resp2 = resp2.follow()
assert Category.get(1).description == 'updated description'
def test_categories_new_duplicate_name(pub):
Category.wipe()
category = Category(name='foobar')
category.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/categories/')
resp = resp.click('New Category')
resp.forms[0]['name'] = 'foobar'
resp = resp.forms[0].submit('submit')
assert 'This name is already used' in resp.body
def test_categories_reorder(pub):
Category.wipe()
category = Category(name='foo')
category.store()
category = Category(name='bar')
category.store()
category = Category(name='baz')
category.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/categories/update_order?order=1;2;3;')
categories = Category.select()
Category.sort_by_position(categories)
assert [x.id for x in categories] == ['1', '2', '3']
resp = app.get('/backoffice/forms/categories/update_order?order=3;1;2;')
categories = Category.select()
Category.sort_by_position(categories)
assert [x.id for x in categories] == ['3', '1', '2']
def test_settings(pub):
create_superuser(pub)
app = login(get_app(pub))
app.get('/backoffice/settings/')
app.get('/backoffice/settings/misc')
app.get('/backoffice/settings/debug_options')
app.get('/backoffice/settings/language')
app.get('/backoffice/settings/import')
app.get('/backoffice/settings/export')
app.get('/backoffice/settings/identification')
app.get('/backoffice/settings/sitename')
app.get('/backoffice/settings/sms')
app.get('/backoffice/settings/session')
app.get('/backoffice/settings/admin-permissions')
def test_settings_disabled_screens(pub):
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/settings/')
assert 'Identification' in resp.body
assert 'Theme' in resp.body
if not pub.site_options.has_section('options'):
pub.site_options.add_section('options')
pub.site_options.set('options', 'settings-disabled-screens', 'identification, theme')
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
pub.site_options.write(fd)
resp = app.get('/backoffice/settings/')
assert 'Identification' not in resp.body
assert 'Theme' not in resp.body
def test_settings_export_import(pub, studio):
def wipe():
FormDef.wipe()
CardDef.wipe()
Workflow.wipe()
Role.wipe()
Category.wipe()
NamedDataSource.wipe()
NamedWsCall.wipe()
wipe()
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/settings/export')
resp = resp.form.submit('cancel')
resp = app.get('/backoffice/settings/export')
resp = resp.form.submit('submit')
assert resp.location.startswith('http://example.net/backoffice/settings/export?job=')
job_id = urlparse.parse_qs(urlparse.urlparse(resp.location).query)['job'][0]
resp = resp.follow()
assert 'completed' in resp.body
resp = resp.click('Download Export')
zip_content = StringIO.StringIO(resp.body)
zipf = zipfile.ZipFile(zip_content, 'a')
filelist = zipf.namelist()
assert len(filelist) == 0
# check afterjob ajax call
status_resp = app.get('/afterjobs/' + job_id)
assert status_resp.body == 'completed|completed'
formdef = FormDef()
formdef.name = 'foo'
formdef.store()
carddef = CardDef()
carddef.name = 'bar'
carddef.store()
Category(name='baz').store()
Role(name='qux').store()
NamedDataSource(name='quux').store()
NamedWsCall(name='corge').store()
wf = Workflow(name='bar')
st1 = wf.add_status('Status1', 'st1')
export_to = ExportToModel()
export_to.label = 'test'
upload = QuixoteUpload('/foo/bar', content_type='application/vnd.oasis.opendocument.text')
file_content = '''PK\x03\x04\x14\x00\x00\x08\x00\x00\'l\x8eG^\xc62\x0c\'\x00'''
upload.fp = StringIO.StringIO()
upload.fp.write(file_content)
upload.fp.seek(0)
export_to.model_file = UploadedFile('models', 'export_to_model-1.upload', upload)
st1.items.append(export_to)
export_to.parent = st1
wf.store()
resp = app.get('/backoffice/settings/export')
resp = resp.form.submit('submit')
assert resp.location.startswith('http://example.net/backoffice/settings/export?job=')
job_id = urlparse.parse_qs(urlparse.urlparse(resp.location).query)['job'][0]
resp = resp.follow()
resp = resp.click('Download Export')
zip_content = StringIO.StringIO(resp.body)
zipf = zipfile.ZipFile(zip_content, 'a')
filelist = zipf.namelist()
assert 'formdefs/1' not in filelist
assert 'formdefs_xml/1' in filelist
assert 'carddefs/1' not in filelist
assert 'carddefs_xml/1' in filelist
assert 'workflows/1' not in filelist
assert 'workflows_xml/1' in filelist
assert 'models/export_to_model-1.upload' not in filelist
assert 'roles/1' in filelist
assert 'categories/1' in filelist
assert 'datasources/1' in filelist
assert 'wscalls/corge' in filelist
for filename in filelist:
assert not '.indexes' in filename
wipe()
assert FormDef.count() == 0
resp = app.get('/backoffice/settings/import')
resp = resp.form.submit('cancel')
resp = app.get('/backoffice/settings/import')
resp.form['file'] = Upload('export.wcs', 'invalid content')
resp = resp.form.submit('submit')
assert 'Error: Not a valid export file' in resp.body
resp = app.get('/backoffice/settings/import')
resp.form['file'] = Upload('export.wcs', zip_content.getvalue())
resp = resp.form.submit('submit')
assert 'Imported successfully' in resp.body
assert '1 forms' in resp.body
assert '1 cards' in resp.body
assert FormDef.count() == 1
assert FormDef.select()[0].url_name == 'foo'
assert CardDef.count() == 1
assert CardDef.select()[0].url_name == 'bar'
# check roles are found by name
wipe()
role = Role(name='qux')
role.store()
workflow = Workflow(name='Workflow One')
st1 = workflow.add_status(name='st1')
commentable = CommentableWorkflowStatusItem()
commentable.id = '_commentable'
commentable.by = [role.id]
commentable.label = 'foobar'
st1.items.append(commentable)
commentable.parent = st1
workflow.store()
formdef = FormDef()
formdef.name = 'foo'
formdef.workflow_id = workflow.id
formdef.roles = [role.id]
formdef.backoffice_submission_roles = [role.id]
formdef.workflow_roles = {'_receiver': role.id}
formdef.store()
resp = app.get('/backoffice/settings/export')
resp.form['formdefs'] = True
resp.form['workflows'] = True
resp.form['roles'] = False
resp.form['categories'] = False
resp.form['datasources'] = False
resp.form['wscalls'] = False
resp = resp.form.submit('submit')
assert resp.location.startswith('http://example.net/backoffice/settings/export?job=')
job_id = urlparse.parse_qs(urlparse.urlparse(resp.location).query)['job'][0]
resp = resp.follow()
resp = resp.click('Download Export')
zip_content = StringIO.StringIO(resp.body)
zipf = zipfile.ZipFile(zip_content, 'a')
filelist = zipf.namelist()
assert 'formdefs_xml/%s' % formdef.id in filelist
assert 'workflows_xml/%s' % workflow.id in filelist
assert 'roles/%s' % role.id not in filelist
FormDef.wipe()
Workflow.wipe()
Role.wipe()
# create role beforehand, it should be matched by name
role = Role(name='qux')
role.id = '012345'
role.store()
resp = app.get('/backoffice/settings/import')
resp.form['file'] = Upload('export.wcs', zip_content.getvalue())
resp = resp.form.submit('submit')
assert FormDef.select()[0].roles == ['012345']
assert FormDef.select()[0].backoffice_submission_roles == ['012345']
assert FormDef.select()[0].workflow_roles == {'_receiver': '012345'}
assert Workflow.select()[0].possible_status[0].items[0].by == ['012345']
# do not export roles when managed by idp
pub.cfg['sp'] = {'idp-manage-roles': True}
pub.write_cfg()
resp = app.get('/backoffice/settings/export')
resp = resp.form.submit('submit')
assert resp.location.startswith('http://example.net/backoffice/settings/export?job=')
job_id = urlparse.parse_qs(urlparse.urlparse(resp.location).query)['job'][0]
resp = resp.follow()
resp = resp.click('Download Export')
zip_content = StringIO.StringIO(resp.body)
zipf = zipfile.ZipFile(zip_content, 'a')
filelist = zipf.namelist()
assert len([x for x in filelist if 'roles/' in x]) == 0
def test_settings_themes(pub):
create_superuser(pub)
app = login(get_app(pub))
# create mock theme
os.mkdir(os.path.join(pub.app_dir, 'themes'))
os.mkdir(os.path.join(pub.app_dir, 'themes', 'test'))
fd = open(os.path.join(pub.app_dir, 'themes', 'test', 'desc.xml'), 'w')
fd.write('<?xml version="1.0"?>'\
'<theme name="test" version="1.0">'\
' <label>Test Theme</label>'\
'</theme>')
fd.close()
resp = app.get('/backoffice/settings/themes')
assert 'biglist themes' in resp.body
assert 'Test Theme (1.0)' in resp.body
# just for the kick, there's no support for uploading file in webtest 1.3
resp = app.get('/backoffice/settings/themes')
resp.click('Install New Theme')
# select the theme
resp = app.get('/backoffice/settings/themes')
resp.forms[0]['theme'].value = 'test'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/settings/'
resp = app.get('/backoffice/settings/themes')
assert 'checked' in resp.body
assert get_current_theme()['name'] == 'test'
def test_settings_template(pub):
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/settings/template')
# change template
orig_value = resp.forms[0]['template'].value
assert not 'foobar' in orig_value
resp.forms[0]['template'] = orig_value + '<!-- foobar -->'
resp = resp.forms[0].submit('submit')
# restore default template
resp = app.get('/backoffice/settings/template')
assert 'foobar' in resp.forms[0]['template'].value
resp = resp.forms[0].submit('restore-default')
# check
resp = app.get('/backoffice/settings/template')
assert resp.forms[0]['template'].value == orig_value
def test_settings_user(pub):
user = create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/settings/users').follow().follow()
# add a field
resp.forms[1]['label'] = 'foobar'
resp = resp.forms[1].submit()
assert resp.location == 'http://example.net/backoffice/settings/users/fields/'
resp = resp.follow()
assert 'foobar' in pub.cfg['users']['formdef']
assert 'foobar' in resp.body
# set field as email
resp.forms[0]['field_email'] = '1'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/settings/users/fields/'
resp = resp.follow()
assert pub.cfg['users']['field_email'] == '1'
# and unset it
resp.forms[0]['field_email'] = ''
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/settings/users/fields/'
resp = resp.follow()
assert pub.cfg['users']['field_email'] == None
# add a comment field
resp.forms[1]['label'] = 'barfoo'
resp.forms[1]['type'] = 'Comment'
resp = resp.forms[1].submit()
assert resp.location == 'http://example.net/backoffice/settings/users/fields/'
resp = resp.follow()
assert 'barfoo' in pub.cfg['users']['formdef']
assert 'barfoo' in resp.body
# check fields are present in edit form
resp = app.get('/backoffice/users/%s/edit' % user.id)
assert 'barfoo' in resp.body
assert 'f1' in resp.forms[0].fields
assert 'email' in resp.forms[0].fields
# check the email field is not displayed if it's overridden by a custom
# field.
pub.cfg['users']['field_email'] = '1'
pub.write_cfg()
resp = app.get('/backoffice/users/%s/edit' % user.id)
assert 'f1' in resp.forms[0].fields
assert 'email' not in resp.forms[0].fields
# restore config
pub.cfg['users']['field_email'] = None
pub.write_cfg()
def test_settings_emails(pub):
create_superuser(pub)
app = login(get_app(pub))
pub.cfg['debug'] = {'mail_redirection': 'foo@example.net'}
pub.write_cfg()
resp = app.get('/backoffice/settings/emails/')
resp = resp.click('General Options')
assert 'Warning: all emails are sent to &lt;foo@example.net&gt;' in resp.body
pub.cfg['debug'] = {}
pub.write_cfg()
resp = app.get('/backoffice/settings/emails/')
resp = resp.click('General Options')
assert 'Warning: all emails are sent to &lt;foo@example.net&gt;' not in resp.body
resp = app.get('/backoffice/settings/emails/')
resp = resp.click('Approval of new account')
resp.forms[0]['email-new-account-approved_subject'] = 'bla'
resp.forms[0]['email-new-account-approved'] = 'bla bla bla'
resp = resp.forms[0].submit()
assert pub.cfg['emails']['email-new-account-approved_subject'] == 'bla'
assert pub.cfg['emails']['email-new-account-approved'] == 'bla bla bla'
# reset to default value
resp = app.get('/backoffice/settings/emails/')
resp = resp.click('Approval of new account')
resp.forms[0]['email-new-account-approved_subject'] = 'Your account has been approved'
resp = resp.forms[0].submit()
assert pub.cfg['emails']['email-new-account-approved_subject'] is None
def test_settings_texts(pub):
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/settings/texts/')
resp = resp.click('Text on top of the login page')
resp.forms[0]['text-top-of-login'] = 'Hello world'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/settings/texts/'
assert pub.cfg['texts']['text-top-of-login'] == 'Hello world'
resp = app.get('/backoffice/settings/texts/')
resp = resp.click('Text on top of the login page')
resp = resp.forms[0].submit('restore-default')
assert resp.location == 'http://example.net/backoffice/settings/texts/'
assert pub.cfg['texts']['text-top-of-login'] == None
@pytest.mark.skipif('lasso is None')
def test_settings_auth(pub):
pub.user_class.wipe() # makes sure there are no users
pub.cfg['identification'] = {}
pub.write_cfg()
app = get_app(pub)
resp = app.get('/backoffice/settings/')
assert not 'identification/password/' in resp.body
assert not 'identification/idp/' in resp.body
resp = resp.click('Identification')
assert resp.forms[0]['methods$elementidp'].checked is False
assert resp.forms[0]['methods$elementpassword'].checked is False
resp.forms[0]['methods$elementidp'].checked = True
resp = resp.forms[0].submit()
resp = resp.follow()
assert 'identification/idp/' in resp.body
assert pub.cfg['identification']['methods'] == ['idp']
resp = resp.click('Identification')
assert resp.forms[0]['methods$elementidp'].checked is True
assert resp.forms[0]['methods$elementpassword'].checked is False
resp.forms[0]['methods$elementidp'].checked = False
resp.forms[0]['methods$elementpassword'].checked = True
resp = resp.forms[0].submit()
resp = resp.follow()
assert 'identification/password/' in resp.body
assert pub.cfg['identification']['methods'] == ['password']
@pytest.mark.skipif('lasso is None')
def test_settings_idp(pub):
# create admin session
create_superuser(pub)
app = login(get_app(pub))
pub.cfg['identification'] = {'methods': ['idp']}
pub.write_cfg()
app.get('/saml/metadata', status=404)
resp = app.get('/backoffice/settings/')
resp = resp.click(href='identification/idp/')
resp = resp.click('Service Provider')
resp = resp.form.submit('generate_rsa').follow()
resp = resp.form.submit('submit')
resp = resp.follow()
resp2 = resp.click('Identities')
resp2 = resp2.form.submit('cancel').follow()
resp2 = resp.click('Identities')
resp2 = resp2.form.submit('submit')
resp_metadata = app.get('/saml/metadata', status=200)
assert resp_metadata.body.startswith('<?xml')
resp2 = resp.click('Identity Providers')
resp2 = resp2.click('New')
idp_metadata_filename = os.path.join(os.path.dirname(__file__), 'idp_metadata.xml')
resp2.form['metadata'] = Upload('idp_metadata.xml', open(idp_metadata_filename).read())
resp2 = resp2.form.submit('submit')
resp = resp.click('Identity Providers')
assert 'http://authentic.example.net/' in resp.body
resp2 = resp.click(href='http-authentic.example.net-idp-saml2-metadata/', index=0)
assert 'ns0:EntityDescriptor' in resp2.body
resp = resp.click(href='http-authentic.example.net-idp-saml2-metadata/edit')
resp = resp.forms[0].submit('submit')
resp = resp.follow()
# test that login initiates a SSO
login_resp = app.get('/login/', status=302)
assert login_resp.location.startswith('http://authentic.example.net/idp/saml2/sso?SAMLRequest')
resp = resp.click(href='/backoffice/settings/identification/idp/idp/', index=0) # breadcrumb
resp = resp.click(href='http-authentic.example.net-idp-saml2-metadata/delete')
resp = resp.forms[0].submit() # confirm delete
assert len(pub.cfg['idp']) == 0
with mock.patch('wcs.qommon.misc.urlopen') as urlopen:
idp_metadata_filename = os.path.join(os.path.dirname(__file__), 'idp_metadata.xml')
urlopen.side_effect = lambda *args: open(idp_metadata_filename)
resp = app.get('/backoffice/settings/identification/idp/idp/')
resp = resp.click('Create new from remote URL')
resp.form['metadata_url'] = 'http://authentic.example.net/idp/saml2/metadata'
resp = resp.form.submit('submit')
resp = resp.follow()
assert 'http://authentic.example.net/idp/saml2/metadata' in resp.body
assert urlopen.call_count == 1
resp = resp.click('View')
resp = resp.click('Update from remote URL')
assert urlopen.call_count == 2
def test_settings_auth_password(pub):
Role.wipe()
pub.user_class.wipe() # makes sure there are no users
pub.cfg['identification'] = {'methods': ['password']}
assert pub.cfg['identification']['methods'] == ['password']
pub.write_cfg()
app = get_app(pub)
resp = app.get('/backoffice/settings/identification/password/')
resp = resp.click('Identities')
resp = resp.forms[0].submit()
resp = app.get('/backoffice/settings/identification/password/')
resp = resp.click('Passwords')
resp = resp.forms[0].submit()
resp = app.get('/backoffice/settings/identification/password/')
resp = resp.click('Bulk Import')
resp = resp.forms[0].submit()
# same with existing roles
Role(name='blah').store()
resp = app.get('/backoffice/settings/identification/password/')
resp = resp.click('Bulk Import')
resp = resp.forms[0].submit()
def test_settings_filetypes(pub):
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/settings/filetypes/')
assert 'There are no file type defined at the moment.' in resp.body
resp.forms[0]['label'] = 'Text files'
resp.forms[0]['mimetypes'] = '.odt'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/settings/filetypes/'
resp = resp.follow()
assert pub.cfg['filetypes'][1]['label'] == 'Text files'
resp = resp.click('Text files')
assert resp.forms[0]['mimetypes'].value == 'application/vnd.oasis.opendocument.text'
resp.forms[0]['mimetypes'] = 'application/vnd.oasis.opendocument.text, .doc, .docx, .pdf'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/settings/filetypes/'
resp = resp.follow()
assert 'application/msword (.do' in resp.body
assert 'application/pdf' in pub.cfg['filetypes'][1]['mimetypes']
resp.forms[0]['label'] = 'HTML files'
resp.forms[0]['mimetypes'] = '.html'
resp = resp.forms[0].submit('submit')
resp = resp.follow()
resp = resp.click('HTML files') # go to form
resp = resp.forms[0].submit('cancel') # and cancel
assert resp.location == 'http://example.net/backoffice/settings/filetypes/'
resp = resp.follow()
assert 'HTML files' in resp.body
resp = resp.click('HTML files') # go to form
resp = resp.forms[0].submit('delete') # and delete
assert resp.location == 'http://example.net/backoffice/settings/filetypes/'
resp = resp.follow()
assert 'HTML files' not in resp.body
def test_settings_filetypes_update(pub):
create_superuser(pub)
app = login(get_app(pub))
pub.cfg['filetypes'] = {
1: {'mimetypes': ['application/pdf', 'application/msword'],
'label': 'Text files'}
}
pub.write_cfg()
resp = app.get('/backoffice/settings/filetypes/')
assert 'Text files' in resp.body
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [fields.FileField(
id='1', label='1st field', type='file',
document_type={
'id': 1,
'mimetypes': ['application/pdf', 'application/msword'],
'label': 'Text files',
})]
formdef.store()
assert FormDef.get(formdef.id).fields[0].document_type == {
'id': 1,
'mimetypes': ['application/pdf', 'application/msword'],
'label': 'Text files',
}
resp = resp.click('Text files')
resp.forms[0]['mimetypes'] = 'application/vnd.oasis.opendocument.text, .doc, .docx, .pdf'
resp = resp.forms[0].submit('submit')
assert 'application/pdf' in pub.cfg['filetypes'][1]['mimetypes']
assert FormDef.get(formdef.id).fields[0].document_type == {
'id': 1,
'mimetypes': ['application/vnd.oasis.opendocument.text',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/pdf' ],
'label': 'Text files',
}
def test_settings_logs(pub):
# reset logging state
logging.shutdown()
if os.path.exists(os.path.join(pub.app_dir, 'wcs.log')):
os.unlink(os.path.join(pub.app_dir, 'wcs.log'))
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/settings/')
assert 'Logs' in resp.body
resp = resp.click('Logs')
assert '<td class="message">login</td>' in resp.body
resp = app.get('/backoffice/settings/debug_options')
assert resp.form['logger'].checked is True
resp.form['logger'].checked = False
resp = resp.form.submit()
resp = resp.follow()
assert 'Logs' not in resp.body
def test_settings_geolocation(pub):
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/settings/')
resp = resp.click('Geolocation')
resp.form['default-position$latlng'].value = '1.234;-1.234'
resp = resp.form.submit('cancel').follow()
resp = resp.click('Geolocation')
assert not 'value="1.234;-1.234' in resp.body
resp.form['default-position$latlng'].value = '1.234;-1.234'
resp = resp.form.submit().follow()
resp = resp.click('Geolocation')
assert 'value="1.234;-1.234' in resp.body
pub.reload_cfg()
assert pub.cfg['misc']['default-position'] == '1.234;-1.234'
def test_data_sources(pub):
create_superuser(pub)
app = login(get_app(pub))
app.get('/backoffice/settings/data-sources/')
# also check it's accessible from forms and workflows sections
app.get('/backoffice/forms/data-sources/')
app.get('/backoffice/workflows/data-sources/')
# unknown datasource
app.get('/backoffice/settings/data-sources/42/', status=404)
app.get('/backoffice/forms/data-sources/42/', status=404)
app.get('/backoffice/workflows/data-sources/42/', status=404)
def test_data_sources_new(pub):
create_superuser(pub)
NamedDataSource.wipe()
app = login(get_app(pub))
# go to the page and cancel
resp = app.get('/backoffice/settings/data-sources/')
resp = resp.click('New Data Source')
resp = resp.forms[0].submit('cancel')
assert resp.location == 'http://example.net/backoffice/settings/data-sources/'
# go to the page and add a data source
resp = app.get('/backoffice/settings/data-sources/')
resp = resp.click('New Data Source')
resp.forms[0]['name'] = 'a new data source'
resp.forms[0]['description'] = 'description of the data source'
resp.forms[0]['data_source$type'] = 'python'
resp = resp.forms[0].submit('data_source$apply')
resp.forms[0]['data_source$value'] = repr(
[{'id': '1', 'text': 'un'}, {'id': '2', 'text': 'deux'}])
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/settings/data-sources/'
resp = resp.follow()
assert 'a new data source' in resp.body
resp = resp.click('a new data source')
assert 'Data Source - a new data source' in resp.body
resp = resp.click('Edit')
assert 'Edit Data Source' in resp.body
assert NamedDataSource.get(1).name == 'a new data source'
assert NamedDataSource.get(1).description == 'description of the data source'
# add a second one
resp = app.get('/backoffice/settings/data-sources/')
resp = resp.click('New Data Source')
resp.forms[0]['name'] = 'an other data source'
resp.forms[0]['description'] = 'description of the data source'
resp.forms[0]['data_source$type'] = 'python'
resp = resp.forms[0].submit('data_source$apply')
resp.forms[0]['data_source$value'] = repr(
[{'id': '1', 'text': 'un'}, {'id': '2', 'text': 'deux'}])
resp = resp.forms[0].submit('submit')
assert NamedDataSource.count() == 2
def test_data_sources_view(pub):
create_superuser(pub)
NamedDataSource.wipe()
data_source = NamedDataSource(name='foobar')
app = login(get_app(pub))
data_source.data_source = {'type': 'formula', 'value': '[]'}
data_source.store()
resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
assert 'Type of source: Python Expression' in resp.body
assert 'Python Expression' in resp.body
assert not 'Preview' in resp.body
data_source.data_source = {'type': 'formula', 'value': '["AAA", "BBB"]'}
data_source.store()
resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
assert 'Preview' in resp.body
assert resp.body.count('AAA') == 3 # expression + id + text
# check unicode
data_source.data_source = {'type': 'formula',
'value': repr([('Y', 'Domicilié'), ('N', u'Pas domicilié')])}
data_source.store()
resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
assert 'Preview' in resp.body
assert 'error: not a string' in resp.body
# check json
json_file_path = os.path.join(pub.app_dir, 'test.json')
json_file = open(json_file_path, 'w')
json.dump({'data': [{'id': '1', 'text': 'foo'}, {'id': '2', 'text': 'bar'}]}, json_file)
json_file.close()
data_source.data_source = {'type': 'json', 'value': 'file://%s' % json_file_path}
data_source.store()
with HttpRequestsMocking() as http_requests:
resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
assert 'Preview' in resp.body
assert 'foo' in resp.body
data_source.data_source = {'type': 'formula', 'value': '[str(x) for x in range(100)]'}
data_source.store()
resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
assert 'Preview' in resp.body
assert resp.body.count('<li>') < 100
assert '<li>...</li>' in resp.body
data_source.data_source = {'type': 'formula', 'value': repr([
{'id': 'a', 'text': 'BBB', 'foo': 'bar1'},
{'id': 'b', 'text': 'BBB', 'foo': 'bar2'},
])}
data_source.store()
resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
assert 'Preview' in resp.body
assert 'Additional keys are available: foo' in resp.body
# check formdef listing
FormDef.wipe()
formdef = FormDef()
formdef.name = 'test data source'
formdef.fields = [
fields.ItemField(id='1', label='item', data_source={'type': data_source.slug})
]
formdef.store()
resp = app.get('/backoffice/settings/data-sources/%s/' % data_source.id)
assert 'Usage in forms' in resp.body
assert '/backoffice/forms/%s/' % formdef.id in resp.body
def test_data_sources_edit(pub):
create_superuser(pub)
NamedDataSource.wipe()
data_source = NamedDataSource(name='foobar')
data_source.data_source = {'type': 'formula', 'value': '[]'}
data_source.store()
FormDef.wipe()
app = login(get_app(pub))
resp = app.get('/backoffice/settings/data-sources/1/')
resp = resp.click(href='edit')
assert resp.forms[0]['name'].value == 'foobar'
resp.forms[0]['description'] = 'data source description'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/settings/data-sources/1/'
resp = resp.follow()
assert NamedDataSource.get(1).description == 'data source description'
def test_data_sources_edit_duplicate_name(pub):
create_superuser(pub)
NamedDataSource.wipe()
data_source = NamedDataSource(name='foobar')
data_source.data_source = {'type': 'formula', 'value': '[]'}
data_source.store()
data_source = NamedDataSource(name='foobar2')
data_source.data_source = {'type': 'formula', 'value': '[]'}
data_source.store()
app = login(get_app(pub))
resp = app.get('/backoffice/settings/data-sources/1/')
resp = resp.click(href='edit')
assert resp.forms[0]['name'].value == 'foobar'
resp.forms[0]['name'] = 'foobar2'
resp = resp.forms[0].submit('submit')
assert 'This name is already used' in resp.body
resp = resp.forms[0].submit('cancel')
assert resp.location == 'http://example.net/backoffice/settings/data-sources/1/'
def test_data_sources_delete(pub):
create_superuser(pub)
NamedDataSource.wipe()
category = NamedDataSource(name='foobar')
category.store()
FormDef.wipe()
app = login(get_app(pub))
resp = app.get('/backoffice/settings/data-sources/1/')
resp = resp.click(href='delete')
resp = resp.forms[0].submit('cancel')
assert resp.location == 'http://example.net/backoffice/settings/data-sources/'
assert NamedDataSource.count() == 1
resp = app.get('/backoffice/settings/data-sources/1/')
resp = resp.click(href='delete')
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/settings/data-sources/'
resp = resp.follow()
assert NamedDataSource.count() == 0
def test_data_sources_in_use_delete(pub):
create_superuser(pub)
NamedDataSource.wipe()
category = NamedDataSource(name='foobar')
category.store()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [
fields.ItemField(id='0', label='string', type='item',
data_source={'type': 'foobar'}),
]
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/settings/data-sources/1/')
resp = resp.click(href='delete')
assert 'This datasource is still used, it cannot be deleted.' in resp.text
assert 'delete-button' not in resp.text
formdef.fields = []
formdef.store()
resp = app.get('/backoffice/settings/data-sources/1/')
resp = resp.click(href='delete')
assert 'delete-button' in resp.text
def test_data_sources_edit_slug(pub):
create_superuser(pub)
NamedDataSource.wipe()
data_source = NamedDataSource(name='foobar')
data_source.data_source = {'type': 'formula', 'value': '[]'}
data_source.store()
assert NamedDataSource.get(1).slug == 'foobar'
FormDef.wipe()
app = login(get_app(pub))
resp = app.get('/backoffice/settings/data-sources/1/')
resp = resp.click(href='edit')
assert resp.forms[0]['name'].value == 'foobar'
resp.forms[0]['slug'] = 'foo_bar'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/settings/data-sources/1/'
assert NamedDataSource.get(1).slug == 'foo_bar'
data_source = NamedDataSource(name='barfoo')
data_source.data_source = {'type': 'formula', 'value': '[]'}
data_source.store()
resp = app.get('/backoffice/settings/data-sources/1/')
resp = resp.click(href='edit')
assert resp.forms[0]['name'].value == 'foobar'
resp.forms[0]['slug'] = 'barfoo'
resp = resp.forms[0].submit('submit')
assert 'This value is already used' in resp.body
resp.forms[0]['slug'] = 'foobar'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/settings/data-sources/1/'
def test_data_sources_in_use_edit_slug(pub):
create_superuser(pub)
NamedDataSource.wipe()
data_source = NamedDataSource(name='foobar')
data_source.data_source = {'type': 'formula', 'value': '[]'}
data_source.store()
assert NamedDataSource.get(1).slug == 'foobar'
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [
fields.ItemField(id='0', label='string', type='item',
data_source={'type': 'foobar'}),
]
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/settings/data-sources/1/')
resp = resp.click(href='edit')
assert 'form_slug' not in resp.text
formdef.fields = []
formdef.store()
resp = app.get('/backoffice/settings/data-sources/1/')
resp = resp.click(href='edit')
assert 'form_slug' in resp.text
def test_wscalls_new(pub):
create_superuser(pub)
NamedWsCall.wipe()
app = login(get_app(pub))
# go to the page and cancel
resp = app.get('/backoffice/settings/wscalls/')
resp = resp.click('New webservice call')
resp = resp.forms[0].submit('cancel')
assert resp.location == 'http://example.net/backoffice/settings/wscalls/'
# go to the page and add a webservice call
resp = app.get('/backoffice/settings/wscalls/')
resp = resp.click('New webservice call')
resp.form['name'] = 'a new webservice call'
resp.form['description'] = 'description'
resp.form['request$url'] = 'http://remote.example.net/json'
resp = resp.form.submit('submit')
assert resp.location == 'http://example.net/backoffice/settings/wscalls/'
resp = resp.follow()
assert 'a new webservice call' in resp.body
resp = resp.click('a new webservice call')
assert 'Webservice Call - a new webservice call' in resp.body
resp = resp.click('Edit')
assert 'Edit webservice call' in resp.body
assert NamedWsCall.get('a_new_webservice_call').name == 'a new webservice call'
def test_wscalls_view(pub):
create_superuser(pub)
NamedWsCall.wipe()
wscall = NamedWsCall(name='xxx')
wscall.description = 'description'
wscall.request = {
'url': 'http://remote.example.net/json',
'request_signature_key': 'xxx',
'qs_data': {'a': 'b'},
'method': 'POST',
'post_data': {'c': 'd'},
}
wscall.store()
app = login(get_app(pub))
resp = app.get('/backoffice/settings/wscalls/%s/' % wscall.id)
assert 'http://remote.example.net/json' in resp.body
def test_wscalls_edit(pub):
test_wscalls_view(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/settings/wscalls/xxx/')
resp = resp.click(href='edit')
assert resp.form['name'].value == 'xxx'
assert 'slug' in resp.form.fields
resp.form['description'] = 'bla bla bla'
resp = resp.form.submit('submit')
assert resp.location == 'http://example.net/backoffice/settings/wscalls/xxx/'
resp = resp.follow()
assert NamedWsCall.get('xxx').description == 'bla bla bla'
resp = app.get('/backoffice/settings/wscalls/xxx/')
resp = resp.click(href='edit')
assert resp.form['name'].value == 'xxx'
assert 'slug' in resp.form.fields
resp.form['slug'] = 'yyy'
resp = resp.form.submit('submit')
assert resp.location == 'http://example.net/backoffice/settings/wscalls/yyy/'
def test_wscalls_delete(pub):
test_wscalls_view(pub)
assert NamedWsCall.count() == 1
app = login(get_app(pub))
resp = app.get('/backoffice/settings/wscalls/xxx/')
resp = resp.click(href='delete')
resp = resp.form.submit('cancel')
assert resp.location == 'http://example.net/backoffice/settings/wscalls/'
resp = app.get('/backoffice/settings/wscalls/xxx/')
resp = resp.click(href='delete')
resp = resp.form.submit('submit')
assert resp.location == 'http://example.net/backoffice/settings/wscalls/'
assert NamedWsCall.count() == 0
def test_settings_permissions(pub):
create_superuser(pub)
role1 = create_role()
role1.name = 'foobar1'
role1.store()
role2 = Role(name='foobar2')
role2.store()
role3 = Role(name='foobar3')
role3.store()
app = login(get_app(pub))
resp = app.get('/backoffice/settings/admin-permissions')
# assert all first checkboxes are checked
assert resp.forms[0]['permissions$c-0-0'].checked
assert resp.forms[0]['permissions$c-1-0'].checked
assert resp.forms[0]['permissions$c-2-0'].checked
role2.allows_backoffice_access = False
role2.store()
resp = app.get('/backoffice/settings/admin-permissions')
assert resp.forms[0]['permissions$c-0-0'].checked
assert not resp.forms[0]['permissions$c-1-0'].checked
assert resp.forms[0]['permissions$c-2-0'].checked
resp.forms[0]['permissions$c-0-0'].checked = False
resp.forms[0]['permissions$c-1-0'].checked = True
resp = resp.forms[0].submit()
assert Role.get(role1.id).allows_backoffice_access is False
assert Role.get(role2.id).allows_backoffice_access is True
# give some roles access to the forms workshop (2nd checkbox) and to the
# workflows workshop (4th)
resp = app.get('/backoffice/settings/admin-permissions')
resp.forms[0]['permissions$c-1-1'].checked = True
resp.forms[0]['permissions$c-2-1'].checked = True
resp.forms[0]['permissions$c-2-3'].checked = True
resp = resp.forms[0].submit()
pub.reload_cfg()
assert set(pub.cfg['admin-permissions']['forms']) == set([role2.id, role3.id])
assert set(pub.cfg['admin-permissions']['workflows']) == set([role3.id])
# remove accesses
resp = app.get('/backoffice/settings/admin-permissions')
resp.forms[0]['permissions$c-1-1'].checked = False
resp.forms[0]['permissions$c-2-1'].checked = False
resp.forms[0]['permissions$c-2-3'].checked = False
resp = resp.forms[0].submit()
pub.reload_cfg()
assert pub.cfg['admin-permissions']['forms'] == []
assert pub.cfg['admin-permissions']['workflows'] == []
def test_settings_theme_preview(pub):
create_superuser(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
assert not 'alto/wcs.css' in app.get('/').body
resp = app.get('/backoffice/settings/themes')
assert resp.form['theme'].value in ('default', 'django')
# visit theme preview
resp = resp.click(href='theme_preview/alto/')
assert 'alto/wcs.css' in resp.body
# get into a form, making sure we are kept in theme preview
resp = resp.click('form title')
assert 'alto/wcs.css' in resp.body
# verify submits are not allowed
resp = resp.form.submit('submit')
assert "The theme preview doesn't support this." in resp.body
def test_settings_theme_download_upload(pub):
create_superuser(pub)
# download existing theme
app = login(get_app(pub))
resp = app.get('/backoffice/settings/themes')
resp = resp.click('download', index=0)
assert resp.headers['content-type'] == 'application/zip'
zip_content = StringIO.StringIO(resp.body)
zipf = zipfile.ZipFile(zip_content, 'a')
filelist = zipf.namelist()
assert 'alto/icon.png' in filelist
assert 'alto/desc.xml' in filelist
assert 'alto/template.ezt' in filelist
assert 'alto/wcs.css' in filelist
# modify it
zipf.writestr('alto/foobar.txt', 'XXX')
zipf.close()
# upload it
resp = app.get('/backoffice/settings/themes')
resp = resp.click('Install New Theme')
resp.form['file'] = Upload('alto-modified.zip', zip_content.getvalue())
resp = resp.form.submit()
assert os.path.exists(os.path.join(pub.app_dir, 'themes/alto/foobar.txt'))
assert app.get('/themes/alto/foobar.txt').body == 'XXX'
def test_bounces(pub):
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/')
assert not 'bounces' in resp.body
resp = app.get('/backoffice/settings/emails/options')
resp.form['from'] = 'noreply@localhost'
resp.form['bounce_handler'].checked = True
resp = resp.form.submit('submit')
pub.reload_cfg()
assert pub.cfg['emails']['bounce_handler']
bounce = Bounce()
bounce.arrival_time = time.time()
bounce.bounce_message = 'foobar'
bounce.addrs = ['foo@localhost']
bounce.email_type = 'change-password-request'
bounce.original_rcpts = ['foo@localhost', 'bar@localhost']
msg = MIMEText('hello world')
msg['Subject'] = 'hello world'
bounce.original_message = msg.as_string()
bounce.store()
resp = app.get('/backoffice/')
assert 'bounces' in resp.body
resp = resp.click('Bounces')
resp = resp.click(href='%s/' % bounce.id, index=0)
assert 'hello world' in resp.body
resp = app.get('/backoffice/bounces/')
resp = resp.click(href='%s/delete' % bounce.id, index=0)
resp = resp.form.submit('cancel').follow()
assert Bounce.count() == 1
resp = resp.click(href='%s/delete' % bounce.id, index=0)
resp = resp.form.submit('delete')
assert Bounce.count() == 0
def test_postgresql_settings(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
return
create_superuser(pub)
database = pub.cfg['postgresql']['database']
assert pub.cfg['postgresql'].get('port') == None
app = login(get_app(pub))
resp = app.get('/backoffice/settings/postgresql')
assert resp.form['database'].value == database
assert resp.form['port'].value == ''
resp = resp.form.submit()
assert pub.cfg['postgresql']['port'] == None
pub.cfg['postgresql']['port'] = 5432
pub.write_cfg()
resp = app.get('/backoffice/settings/postgresql')
assert resp.form['port'].value == '5432'
resp = resp.form.submit()
assert pub.cfg['postgresql']['port'] == 5432
resp = app.get('/backoffice/settings/postgresql')
resp.form['port'] = ''
resp = resp.form.submit()
assert pub.cfg['postgresql']['port'] == None
pub.cfg['postgresql']['port'] = '5432' # from an old convert-to-sql (before #10170)
pub.write_cfg()
resp = app.get('/backoffice/settings/postgresql')
assert resp.form['port'].value == '5432'
resp = resp.form.submit()
assert pub.cfg['postgresql']['port'] == 5432
def test_studio_home(pub, studio):
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/')
assert 'studio' in resp.body
resp = app.get('/backoffice/studio/')
assert '../forms/' in resp.body
assert '../cards/' in resp.body
assert '../workflows/' in resp.body
pub.cfg['admin-permissions'] = {}
for part in ('forms', 'cards', 'workflows'):
# check section link are not displayed if user has no access right
pub.cfg['admin-permissions'].update({part: ['x']}) # block access
pub.write_cfg()
if part != 'workflows':
resp = app.get('/backoffice/studio/')
assert '../%s/' % part not in resp.body
else:
resp = app.get('/backoffice/studio/', status=403) # totally closed
resp = app.get('/backoffice/')
assert 'studio' not in resp.body
def test_studio_workflows(pub, studio):
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/workflows/')
assert '<h2>Workflows for cards</h2>' in resp.body
resp = resp.click(r'Default \(cards\)')
assert 'status/recorded/' in resp.body
assert 'status/deleted/' in resp.body
assert 'This is the default workflow,' in resp.body
def test_cards_new(pub, studio):
CardDef.wipe()
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/cards/')
resp = resp.click('New Card')
resp.form['name'] = 'card title'
resp = resp.form.submit()
assert resp.location == 'http://example.net/backoffice/cards/1/'
resp = resp.follow()
assert '<h2>card title' in resp.body
assert CardDef.get(1).workflow_id is None
assert CardDef.get(1).disabled is False
def test_cards_duplicate(pub, studio):
test_cards_new(pub, studio)
app = login(get_app(pub))
resp = app.get('http://example.net/backoffice/cards/1/')
resp = resp.click('Duplicate')
assert CardDef.get(2).name == 'card title (copy)'
assert CardDef.get(2).disabled is False
def test_card_workflow_change(pub, studio):
Workflow.wipe()
workflow = Workflow(name='Workflow Two')
workflow.add_status('plop')
workflow.store()
CardDef.wipe()
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/cards/')
resp = resp.click('New Card')
resp.form['name'] = 'card title'
resp = resp.form.submit()
resp = resp.follow()
resp = resp.click(href='workflow', index=1)
assert resp.form['workflow_id'].options[0][2] == 'Default (cards)'
resp = resp.form.submit('submit').follow()
assert CardDef.select()[0].workflow_id is None
carddata = CardDef.select()[0].data_class()()
carddata.status = 'wf-recorded'
carddata.store()
resp = resp.click(href='workflow', index=1)
resp.form['workflow_id'] = '%s' % workflow.id
resp = resp.form.submit('submit')
assert resp.location == 'http://example.net/backoffice/cards/1/workflow-status-remapping?new=%s' % workflow.id
resp = resp.follow()
resp = resp.form.submit('submit').follow()
resp = resp.click(href='workflow', index=1)
resp.form['workflow_id'] = ''
resp = resp.form.submit('submit')
assert resp.location == 'http://example.net/backoffice/cards/1/workflow-status-remapping?new=%s' % '_carddef_default'
resp = resp.follow()
resp = resp.form.submit('submit').follow()