wcs/tests/admin_pages/test_form.py

3535 lines
119 KiB
Python

import io
import os
import re
import time
import xml.etree.ElementTree as ET
from unittest import mock
import pytest
from webtest import Upload
from wcs import fields
from wcs.blocks import BlockDef
from wcs.carddef import CardDef
from wcs.categories import Category, DataSourceCategory, WorkflowCategory
from wcs.data_sources import NamedDataSource
from wcs.formdef import FormDef
from wcs.qommon.errors import ConnectionError
from wcs.qommon.http_request import HTTPRequest
from wcs.workflows import Workflow, WorkflowBackofficeFieldsFormDef, WorkflowVariablesFieldsFormDef
from wcs.wscalls import NamedWsCall
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app, login
from .test_all import create_role, create_superuser
@pytest.fixture
def pub(emails):
pub = create_temporary_pub()
req = HTTPRequest(None, {'SCRIPT_NAME': '/', 'SERVER_NAME': 'example.net'})
pub.set_app_dir(req)
pub.cfg['identification'] = {'methods': ['password']}
pub.cfg['language'] = {'language': 'en'}
pub.write_cfg()
return pub
def teardown_module(module):
clean_temporary_pub()
@pytest.fixture
def formdef(pub):
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
return formdef
def test_forms(pub):
create_superuser(pub)
pub.role_class.wipe()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/')
assert 'You first have to define roles.' in resp.text
assert 'New Form' not in resp.text
def test_forms_new(pub):
create_superuser(pub)
app = login(get_app(pub))
create_role(pub)
FormDef.wipe()
# create a new form
resp = app.get('/backoffice/forms/')
assert 'New Form' in resp.text
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.text
# 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 is True
# check workflow selection is available when there are workflows
Workflow.wipe()
workflow = Workflow(name='Workflow One')
workflow.possible_status = Workflow.get_default_workflow().possible_status[:]
workflow.store()
workflow = Workflow(name='Workflow Two')
workflow.possible_status = Workflow.get_default_workflow().possible_status[:]
workflow.store()
resp = app.get('/backoffice/forms/')
resp = resp.click('New Form')
resp.forms[0]['name'] = 'second form'
resp.forms[0]['workflow_id'].select(text='Workflow Two')
# check select is setup for autocompletion
assert resp.pyquery('select#form_workflow_id')[0].attrib['data-autocomplete']
assert 'select2.min.js' in resp.text
resp = resp.forms[0].submit()
formdef = FormDef.get(2)
assert formdef.name == 'second form'
assert formdef.workflow_id == workflow.id
def test_forms_new_popup(pub):
FormDef.wipe()
create_superuser(pub)
app = login(get_app(pub))
create_role(pub)
# create a new form
resp = app.get('/backoffice/forms/')
assert 'New Form' in resp.text
resp = resp.click('New Form', extra_environ={'HTTP_X_POPUP': 'true'})
assert 'popup-content' in resp.text
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.text
# 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 is True
def assert_option_display(resp, label, value):
option_line = re.findall('%s.*%s' % (label, value), resp.text, re.DOTALL)
assert option_line
assert '</li>' not in option_line
def test_forms_edit_confirmation_page(pub, formdef):
create_superuser(pub)
create_role(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
# 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 is 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 is False
def test_forms_edit_limit_one_form(pub, formdef):
create_superuser(pub)
role = create_role(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
# Limit to one form
assert formdef.roles is None
assert_option_display(resp, 'Limit to one form', 'Disabled')
resp = resp.click('Limit to one form')
assert (
'Warning: this option concerns logged in users only, however this form is accessible anonymously. Consider adding an sender role.'
in resp
)
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
formdef.roles = ['logged-users']
formdef.store()
resp = app.get('/backoffice/forms/1/options/only_allow_one')
assert (
'Warning: this option concerns logged in users only, however this form is accessible anonymously. Consider adding an sender role.'
not in resp
)
formdef.roles = [str(role.id)]
formdef.store()
resp = app.get('/backoffice/forms/1/options/only_allow_one')
assert (
'Warning: this option concerns logged in users only, however this form is accessible anonymously. Consider adding an sender role.'
not in resp
)
formdef.roles = []
formdef.store()
resp = app.get('/backoffice/forms/1/options/only_allow_one')
assert (
'Warning: this option concerns logged in users only, however this form is accessible anonymously. Consider adding an sender role.'
in resp
)
def test_forms_edit_management(pub, formdef):
create_superuser(pub)
create_role(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
# Misc management
assert_option_display(resp, 'Management', 'Default')
resp = resp.click('Management', href='options/management')
assert resp.forms[0]['include_download_all_button'].checked is False
resp.forms[0]['include_download_all_button'].checked = True
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/'
resp = resp.follow()
assert_option_display(resp, 'Management', 'Custom')
assert FormDef.get(1).include_download_all_button is True
def test_forms_edit_tracking_code(pub, formdef):
create_superuser(pub)
create_role(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
# 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
resp = resp.click('Tracking Code')
assert resp.forms[0]['drafts_lifespan'].value == ''
resp.forms[0]['drafts_lifespan'].value = 'xxx'
resp = resp.forms[0].submit()
assert 'Lifespan must be between 2 and 100 days.' in resp
resp.forms[0]['drafts_lifespan'].value = '120'
resp = resp.forms[0].submit()
assert 'Lifespan must be between 2 and 100 days.' in resp
resp.forms[0]['drafts_lifespan'].value = '5'
resp = resp.forms[0].submit().follow()
assert FormDef.get(1).drafts_lifespan == '5'
formdef.fields = [
fields.StringField(id='1', label='VerifyString', type='string'),
fields.DateField(id='2', label='VerifyDate', type='date'),
fields.ItemField(id='3', label='CannotVerify', type='item'),
]
formdef.store()
resp = resp.click('Tracking Code')
assert '<option value="1">VerifyString</option>' in resp
assert '<option value="2">VerifyDate</option>' in resp
assert 'CannotVerify' not in resp
resp.forms[0]['tracking_code_verify_fields$element0'].value = '1'
resp = resp.forms[0].submit().follow()
assert FormDef.get(1).tracking_code_verify_fields == ['1']
def test_forms_edit_captcha(pub, formdef):
create_superuser(pub)
create_role(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
# 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
def test_forms_edit_appearance(pub, formdef):
create_superuser(pub)
create_role(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
# 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'
def test_forms_edit_publication(pub, formdef):
create_superuser(pub)
create_role(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
# 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$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')
def test_form_title_change(pub):
create_superuser(pub)
create_role(pub)
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.text
assert 'change-nevertheless' not in resp.text
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 'data-slug-sync' not in resp.text
assert 'change-nevertheless' not in resp.text
formdef.data_class()().store()
resp = app.get('/backoffice/forms/1/')
resp = resp.click('change title')
assert 'change-nevertheless' in resp.text
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.text
resp.form['url_name'] = 'foobar'
resp = resp.form.submit().follow()
assert FormDef.get(formdef2.id).url_name == 'foobar'
def test_form_url_name_change(pub):
create_superuser(pub)
create_role(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/%s/title' % formdef.id)
assert resp.form['name'].value == 'form title'
resp.form['name'] = 'new title'
resp = resp.form.submit(status=302)
formdef = FormDef.get(formdef.id)
assert formdef.name == 'new title'
assert formdef.url_name == 'form-title'
resp = app.get('/backoffice/forms/%s/title' % formdef.id)
resp.form['url_name'] = 'new-title'
resp = resp.form.submit(status=302)
assert FormDef.get(formdef.id).url_name == 'new-title'
resp = app.get('/backoffice/forms/%s/title' % formdef.id)
resp.form['url_name'] = 'New-title'
resp = resp.form.submit(status=200)
assert 'wrong format' in resp.text
formdef.url_name = 'New-title' # preexisting uppercase
formdef.store()
resp = app.get('/backoffice/forms/%s/title' % formdef.id)
resp.form['url_name'] = 'New-Title'
resp = resp.form.submit(status=302)
assert FormDef.get(formdef.id).url_name == 'New-Title'
def test_forms_edit_publication_date(pub):
create_superuser(pub)
create_role(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/options/online_status')
resp.form['publication_date$date'] = '2020-01-01'
resp = resp.form.submit()
assert FormDef.get(formdef.id).publication_date == '2020-01-01 00:00'
resp = app.get('/backoffice/forms/1/options/online_status')
assert resp.form['publication_date$date'].value == '2020-01-01'
resp.form['publication_date$time'] = '12:00'
resp = resp.form.submit()
assert FormDef.get(formdef.id).publication_date == '2020-01-01 12:00'
resp = app.get('/backoffice/forms/1/options/online_status')
assert resp.form['publication_date$date'].value == '2020-01-01'
assert resp.form['publication_date$time'].value == '12:00'
formdef.publication_date = None
formdef.store()
resp = app.get('/backoffice/forms/1/options/online_status')
resp.form['publication_date$time'] = '12:00'
resp = resp.form.submit()
assert 'invalid value' in resp
def test_form_category(pub):
create_superuser(pub)
create_role(pub)
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.text
assert_option_display(resp, 'Category', 'None')
def test_form_category_select(pub):
create_superuser(pub)
create_role(pub)
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(pub)
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(pub)
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.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(workflow)
workflow.backoffice_fields_formdef.fields = [
fields.StringField(id='bo3-3x', label='bo field', type='string'),
]
workflow.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='workflow', index=1)
# check select is setup for autocompletion
assert resp.pyquery('select#form_workflow_id')[0].attrib['data-autocomplete']
assert 'select2.min.js' in resp.text
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)
# no categories, no optgroup
assert [x[2] for x in resp.form['workflow_id'].options] == ['Default', 'Workflow Two']
assert 'Workflow One' not in resp.text # 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
# run a SQL SELECT and we known all columns are defined.
FormDef.get(formdef.id).data_class().select()
Category.wipe()
WorkflowCategory.wipe()
cat1 = WorkflowCategory(name='Foo')
cat1.store()
cat2 = WorkflowCategory(name='Bar')
cat2.store()
wf = Workflow(name='Workflow Foo zz')
wf.possible_status = Workflow.get_default_workflow().possible_status[:]
wf.category = cat1
wf.store()
wf = Workflow(name='Workflow Foo aa')
wf.possible_status = Workflow.get_default_workflow().possible_status[:]
wf.category = cat1
wf.store()
wf = Workflow(name='Workflow Bar bb')
wf.possible_status = Workflow.get_default_workflow().possible_status[:]
wf.category = cat2
wf.store()
wf = Workflow(name='Workflow Bar (bb)')
wf.possible_status = Workflow.get_default_workflow().possible_status[:]
wf.category = cat2
wf.store()
resp = app.get('/backoffice/forms/1/workflow')
assert [x[2] for x in resp.form['workflow_id'].options] == [
'Default',
'Workflow Bar bb',
'Workflow Bar (bb)',
'Workflow Foo aa',
'Workflow Foo zz',
'Workflow Two',
]
cat = Category(name='Foo')
cat.store()
formdef.category = cat
formdef.store()
resp = app.get('/backoffice/forms/1/workflow')
assert [x[2] for x in resp.form['workflow_id'].options] == [
'Default',
'Workflow Foo aa',
'Workflow Foo zz',
'Workflow Bar bb',
'Workflow Bar (bb)',
'Workflow Two',
]
workflow.category = cat1
workflow.store()
resp = app.get('/backoffice/forms/1/workflow')
assert [x[2] for x in resp.form['workflow_id'].options] == [
'Default',
'Workflow Foo aa',
'Workflow Foo zz',
'Workflow Two',
'Workflow Bar bb',
'Workflow Bar (bb)',
]
def test_form_workflow_link(pub):
create_superuser(pub)
create_role(pub)
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 '/backoffice/workflows/_default/' in resp.text
formdef.workflow = workflow
formdef.store()
resp = app.get('/backoffice/forms/%s/' % formdef.id)
assert '/backoffice/workflows/%s/' % workflow.id in resp.text
# 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 '/backoffice/workflows/%s/' % workflow.id not in resp.text
def _test_form_workflow_remapping(pub):
create_superuser(pub)
create_role(pub)
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()
formdata3 = data_class()
formdata3.status = 'wf-1'
formdata3.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.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(workflow)
workflow.backoffice_fields_formdef.fields = [
fields.StringField(id='bo3-3x', label='bo field', type='string'),
]
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-%s' % status.id].options) == 1
assert data_class.get(formdata1.id).status == 'wf-new'
assert data_class.get(formdata2.id).status == 'draft'
assert data_class.get(formdata3.id).status == 'wf-1'
resp = resp.forms[0].submit()
# run a SQL SELECT and we known all columns are defined.
FormDef.get(formdef.id).data_class().select()
assert data_class.get(formdata1.id).status == 'wf-finished'
assert data_class.get(formdata2.id).status == 'draft'
assert data_class.get(formdata3.id).status == 'wf-1-invalid-default'
# change to another workflow, with no mapping change
workflow2 = workflow
workflow = Workflow(name='Workflow Three')
workflow.possible_status = Workflow.get_default_workflow().possible_status[-2:][:]
workflow.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(workflow)
workflow.backoffice_fields_formdef.fields = [
fields.StringField(id='bo4', label='another bo field', type='string'),
]
workflow.store()
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=3'
resp = resp.follow()
for status in workflow2.possible_status:
assert resp.forms[0]['mapping-%s' % status.id]
# there are two status
assert len(resp.forms[0]['mapping-%s' % status.id].options) == 2
resp = resp.forms[0].submit()
assert data_class.get(formdata1.id).status == 'wf-finished'
assert data_class.get(formdata2.id).status == 'draft'
assert data_class.get(formdata3.id).status == 'wf-1-invalid-default'
# run a SQL SELECT and we known all columns are defined.
FormDef.get(formdef.id).data_class().select()
def test_form_workflow_remapping(pub):
_test_form_workflow_remapping(pub)
def test_form_submitter_roles(pub):
create_superuser(pub)
create_role(pub)
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 'required_authentication_contexts' not in resp.text
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.text
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 = pub.role_class(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(pub)
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 = pub.role_class(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(pub)
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.text
def test_form_workflow_variables(pub):
create_superuser(pub)
create_role(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
# check it's not visible
assert '"workflow-variables"' not in resp
# check it doesn't crash anyway
resp = app.get('/backoffice/forms/1/workflow-variables', status=404)
Workflow.wipe()
workflow = Workflow(name='Workflow One')
workflow.variables_formdef = WorkflowVariablesFieldsFormDef(workflow=workflow)
workflow.variables_formdef.fields.append(
fields.StringField(id='1', varname='test', label='Test', type='string')
)
workflow.store()
formdef.workflow_id = workflow.id
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
assert '"workflow-variables"' in resp.text
# 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(pub)
Workflow.wipe()
workflow = Workflow(name='Workflow One')
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.text
# 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_workflow_invalid_file_variable(pub):
create_superuser(pub)
create_role(pub)
FormDef.wipe()
Workflow.wipe()
workflow = Workflow(name='Workflow One')
workflow.variables_formdef = WorkflowVariablesFieldsFormDef(workflow=workflow)
workflow.variables_formdef.fields = [
fields.StringField(id='1', varname='test', label='Test', type='string')
]
workflow.store()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
formdef.workflow_id = workflow.id
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/workflow-variables')
resp.forms[0]['f1'] = 'foobar'
resp = resp.forms[0].submit()
# check the value has been correctly saved
assert FormDef.get(formdef.id).workflow_options == {'test': 'foobar'}
# modify option type
workflow.variables_formdef.fields = [fields.FileField(id='1', varname='test', label='Test', type='file')]
workflow.store()
# do not crash when getting back
resp = app.get('/backoffice/forms/1/workflow-variables')
def test_form_roles(pub):
create_superuser(pub)
role = create_role(pub)
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(pub)
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_templates(pub):
create_superuser(pub)
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/')
assert_option_display(resp, 'Templates', 'None')
assert resp.pyquery('[href="options/templates"]').attr.rel == '' # no popup
resp = resp.click('Templates')
resp.form['digest_template'] = 'X{{form_var_test}}Y'
resp = resp.form.submit()
assert resp.location == 'http://example.net/backoffice/forms/1/'
resp = resp.follow()
assert_option_display(resp, 'Templates', 'Custom')
formdef = FormDef.get(formdef.id)
assert formdef.digest_templates['default'] == 'X{{form_var_test}}Y'
assert formdef.lateral_template is None
assert formdef.submission_lateral_template is None
assert 'Existing forms will be updated in the background.' in resp.text
# afterjobs are actually run synchronously during tests; we don't have
# to wait to check the digest has been updated:
assert formdef.data_class().get(formdata.id).digests['default'] == 'XhelloY'
resp = app.get('/backoffice/forms/1/options/templates')
resp.form['lateral_template'] = 'X{{form_var_test}}Y'
resp.form['submission_lateral_template'] = 'X{{form_var_test}}YZ'
resp = resp.form.submit().follow()
assert_option_display(resp, 'Templates', 'Custom')
formdef = FormDef.get(formdef.id)
assert formdef.digest_templates['default'] == 'X{{form_var_test}}Y'
assert formdef.lateral_template == 'X{{form_var_test}}Y'
assert formdef.submission_lateral_template == 'X{{form_var_test}}YZ'
assert 'Existing forms will be updated in the background.' not in resp.text
def test_form_delete(pub):
create_superuser(pub)
create_role(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
formdef2 = FormDef()
formdef2.name = 'form title'
formdef2.fields = []
formdef2.store()
CardDef.wipe()
carddef = CardDef()
carddef.name = 'Baz'
carddef.store()
pub.custom_view_class.wipe()
custom_view = pub.custom_view_class()
custom_view.title = 'foo'
custom_view.formdef = formdef
custom_view.store()
custom_view2 = pub.custom_view_class()
custom_view2.title = 'foo'
custom_view2.formdef = formdef2
custom_view2.store()
custom_view3 = pub.custom_view_class()
custom_view3.title = 'foo'
custom_view3.formdef = carddef
custom_view3.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/%s/' % formdef.id)
resp = resp.click(href='delete')
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/'
resp = resp.follow()
assert FormDef.count() == 1
assert FormDef.select()[0].id == formdef2.id
assert pub.custom_view_class.count() == 2
assert pub.custom_view_class.get(custom_view2.id)
assert pub.custom_view_class.get(custom_view3.id)
def test_form_delete_with_data(pub):
create_superuser(pub)
create_role(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/%s/' % formdef.id)
resp = resp.click(href='delete')
assert 'Deletion is not possible' in resp
formdata.status = 'draft'
formdata.store()
resp = app.get('/backoffice/forms/%s/' % formdef.id)
resp = resp.click(href='delete')
assert 'Deletion is not possible' not in resp
formdata.status = 'wf-rejected'
formdata.store()
resp = app.get('/backoffice/forms/%s/' % formdef.id)
resp = resp.click(href='delete')
assert 'Deletion is not possible' not in resp
def test_form_duplicate(pub):
create_superuser(pub)
create_role(pub)
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.form['name'].value == 'form title (copy)'
resp = resp.form.submit('cancel').follow()
assert FormDef.count() == 1
resp = resp.click(href='duplicate')
assert resp.form['name'].value == 'form title (copy)'
resp = resp.form.submit('submit')
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.form['name'].value == 'form title (copy 2)'
resp.form['name'].value = 'other copy'
resp = resp.form.submit('submit').follow()
assert FormDef.count() == 3
assert FormDef.get(3).name == 'other copy'
def test_form_export(pub):
create_superuser(pub)
create_role(pub)
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.text
assert ET.fromstring(xml_export).attrib['url'] == 'http://example.net/backoffice/forms/1/'
fd = io.StringIO(xml_export)
formdef2 = FormDef.import_from_xml(fd)
assert formdef2.name == 'form title'
def test_form_import(pub):
create_superuser(pub)
create_role(pub)
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', b'garbage')
resp = resp.form.submit()
assert 'Invalid File' in resp.text
# 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.text
assert FormDef.count() == 1
assert FormDef.get(1).fields[0].id == '1'
assert FormDef.get(1).fields[1].id == '2'
def test_form_import_from_url(pub):
create_superuser(pub)
create_role(pub)
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 = resp.form.submit()
assert 'You have to enter a file or a URL' in resp
with mock.patch('wcs.qommon.misc.urlopen') as urlopen:
urlopen.side_effect = ConnectionError('...')
resp.form['url'] = 'http://remote.invalid/test.wcs'
resp = resp.form.submit()
assert 'Error loading form' in resp
urlopen.side_effect = lambda *args: io.StringIO(formdef_xml.decode())
resp.form['url'] = 'http://remote.invalid/test.wcs'
resp = resp.form.submit()
assert FormDef.count() == 1
def test_form_qrcode(pub):
create_superuser(pub)
create_role(pub)
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.text
resp = resp.click('Download')
assert resp.content_type == 'image/png'
def test_form_description(pub):
create_superuser(pub)
create_role(pub)
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_enable_from_fields_page(pub):
create_superuser(pub)
create_role(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.disabled = True
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
resp = resp.click(href='fields/')
assert 'This form is currently disabled.' in resp
resp = resp.click('Enable').follow()
assert resp.request.path == '/backoffice/forms/1/fields/'
assert 'This form is currently disabled.' not in resp
def test_form_new_field(pub):
create_superuser(pub)
create_role(pub)
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' in resp.text
resp.forms[0]['label'] = 'foobar'
resp.forms[0]['type'] = 'string'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/1/fields/'
resp = resp.follow()
assert 'foobar' in resp.text
assert 'Use drag and drop' in resp.text
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 resp.pyquery('.form-preview h3').text() == 'baz'
def test_form_field_without_label(pub):
create_superuser(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [fields.CommentField(id='1', label=None, type='comment')]
formdef.store()
app = login(get_app(pub))
app.get('/backoffice/forms/1/fields/', status=200) # ok, no error
def test_form_field_varname_values(pub):
create_superuser(pub)
create_role(pub)
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.forms[0]['varname'] = 'id'
resp = resp.forms[0].submit('submit')
assert 'this value is reserved for internal use.' in resp.text
resp.forms[0]['varname'] = '0123'
resp = resp.forms[0].submit('submit')
assert 'must only consist of letters, numbers, or underscore' in resp.text
resp.forms[0]['varname'] = 'plop'
resp = resp.forms[0].submit('submit')
formdef.refresh_from_storage()
assert formdef.fields[0].varname == 'plop'
def test_form_delete_field(pub):
create_superuser(pub)
create_role(pub)
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.text
assert 'Use drag and drop' in resp.text
assert 'Also remove all fields from the page' not in resp.text
resp = resp.click(href='1/delete')
assert 'You are about to remove the "1st field" field.' in resp.text
assert 'Warning:' not in resp.text
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(pub)
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.text
assert 'Warning:' in resp.text
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.text
assert 'Warning:' not in resp.text
resp = resp.forms[0].submit()
resp = resp.follow()
assert len(FormDef.get(1).fields) == 0
def test_form_delete_page_field(pub):
create_superuser(pub)
create_role(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [
fields.PageField(id='1', label='page 1', type='page'),
fields.StringField(id='2', label='field 1 1', type='string'),
fields.StringField(id='3', label='field 1 2', type='string'),
fields.PageField(id='4', label='page 2', type='page'),
fields.PageField(id='5', label='page 3', type='page'),
fields.StringField(id='6', label='field 3 1', type='string'),
fields.StringField(id='7', label='field 3 2', type='string'),
]
formdef.store()
formdef.data_class().wipe()
app = login(get_app(pub))
# delete fields from the page
resp = app.get('/backoffice/forms/1/fields/1/delete')
assert 'You are about to remove the "page 1" page.' in resp.text
assert 'Also remove all fields from the page' in resp.text
resp.forms[0]['delete_fields'] = True
resp = resp.forms[0].submit()
resp = resp.follow()
assert len(FormDef.get(1).fields) == 4
# empty page
resp = app.get('/backoffice/forms/1/fields/4/delete')
assert 'You are about to remove the "page 2" page.' in resp.text
assert 'Also remove all fields from the page' not in resp.text
resp = resp.forms[0].submit()
resp = resp.follow()
assert len(FormDef.get(1).fields) == 3
# keep fields
resp = app.get('/backoffice/forms/1/fields/5/delete')
assert 'You are about to remove the "page 3" page.' in resp.text
assert 'Also remove all fields from the page' in resp.text
resp.forms[0]['delete_fields'] = False
resp = resp.forms[0].submit()
resp = resp.follow()
assert len(FormDef.get(1).fields) == 2
def test_form_duplicate_field(pub):
create_superuser(pub)
create_role(pub)
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/')
assert '1st field' in resp.text
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_page_field(pub):
create_superuser(pub)
create_role(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [
fields.PageField(id='0', label='1st page', type='page'),
fields.StringField(id='1', label='1st field', type='string', varname='foobar'),
fields.PageField(id='2', label='2nd page', type='page'),
fields.StringField(id='3', label='2nd field', type='string', varname='baz'),
]
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/fields/')
# duplicate 1st page only
resp = resp.click(href='0/duplicate')
assert 'Also duplicate all fields of the page' in resp.text
resp = resp.form.submit().follow()
assert [f.label for f in FormDef.get(1).fields] == [
'1st page',
'1st field',
'1st page',
'2nd page',
'2nd field',
]
assert [str(f.id) for f in FormDef.get(1).fields] == ['0', '1', '4', '2', '3']
# duplicate 1st page and fields
resp = resp.click(href='0/duplicate')
assert 'Also duplicate all fields of the page' in resp.text
resp.form['duplicate_fields'] = True
resp = resp.form.submit().follow()
assert [f.label for f in FormDef.get(1).fields] == [
'1st page',
'1st field',
'1st page',
'1st field',
'1st page',
'2nd page',
'2nd field',
]
assert [str(f.id) for f in FormDef.get(1).fields] == ['0', '1', '5', '6', '4', '2', '3']
# duplicate copy of 1st page without fields
resp = resp.click(href='4/duplicate')
assert 'Also duplicate all fields of the page' not in resp.text
resp = resp.form.submit().follow()
assert [f.label for f in FormDef.get(1).fields] == [
'1st page',
'1st field',
'1st page',
'1st field',
'1st page',
'1st page',
'2nd page',
'2nd field',
]
assert [str(f.id) for f in FormDef.get(1).fields] == ['0', '1', '5', '6', '4', '7', '2', '3']
# duplicate last page and fields
resp = resp.click(href='2/duplicate')
assert 'Also duplicate all fields of the page' in resp.text
resp.form['duplicate_fields'] = True
resp = resp.form.submit().follow()
assert [f.label for f in FormDef.get(1).fields] == [
'1st page',
'1st field',
'1st page',
'1st field',
'1st page',
'1st page',
'2nd page',
'2nd field',
'2nd page',
'2nd field',
]
assert [str(f.id) for f in FormDef.get(1).fields] == ['0', '1', '5', '6', '4', '7', '2', '3', '8', '9']
# duplicate last page only
resp = resp.click(href='8/duplicate')
assert 'Also duplicate all fields of the page' in resp.text
resp = resp.form.submit().follow()
assert [f.label for f in FormDef.get(1).fields] == [
'1st page',
'1st field',
'1st page',
'1st field',
'1st page',
'1st page',
'2nd page',
'2nd field',
'2nd page',
'2nd field',
'2nd page',
]
assert [str(f.id) for f in FormDef.get(1).fields] == [
'0',
'1',
'5',
'6',
'4',
'7',
'2',
'3',
'8',
'9',
'10',
]
def test_form_duplicate_file_field(pub):
create_superuser(pub)
create_role(pub)
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'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/%s/fields/' % formdef.id
resp = resp.follow()
assert 'foobar' in resp.text
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(pub)
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.text
resp = resp.click('Edit', href='1/')
assert '/backoffice/forms/1/fields/#itemId_1' in resp
assert resp.pyquery('.field-edit--title').text() == '1st field'
assert resp.pyquery('.field-edit--subtitle').text() == 'Text (line)'
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 is False
def test_form_edit_field_advanced(pub):
create_superuser(pub)
create_role(pub)
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.text
resp = resp.click('Edit', href='1/')
assert resp.forms[0]['label'].value == '1st field'
assert '>Prefill</label>' in resp.text
# check the "prefill" field is in advanced panel and there's no visual marker
assert resp.pyquery('#panel-advanced .PrefillSelectionWidget')
assert not resp.pyquery('#tab-advanced.pk-tabs--button-marker')
# 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', 'locked': False}
# do the same with 'data sources' field
resp = resp.click('Edit', href='1/')
assert resp.forms[0]['label'].value == '1st field'
assert '>Data Source</label>' in resp.text
# check the "data source" field is in advanced panel
assert resp.pyquery('#panel-advanced .DataSourceSelectionWidget')
# 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 is still in the advanced panel, with a visual marker
resp = resp.click('Edit', href='1/')
assert resp.pyquery('#panel-advanced .DataSourceSelectionWidget')
assert resp.pyquery('#tab-advanced.pk-tabs--button-marker')
resp = app.get('/backoffice/forms/1/fields/1/')
assert resp.forms[0]['label'].value == '1st field'
resp.forms[0]['prefill$type'] = 'User Field'
resp.forms[0]['prefill$value_user'] = 'Email (builtin)'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/forms/1/fields/'
resp = resp.follow()
assert (
"&quot;1st field&quot; is not an email field. Are you sure you want to prefill it with user's email?"
in resp.text
)
formdef.fields += [fields.EmailField(id='2', label='2nd field')]
formdef.store()
resp = app.get('/backoffice/forms/1/fields/2/')
assert resp.forms[0]['label'].value == '2nd field'
resp.forms[0]['prefill$type'] = 'User Field'
resp.forms[0]['prefill$value_string'] = 'email'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/forms/1/fields/#itemId_2'
resp = resp.follow()
assert "Are you sure you want to prefill" not in resp.text
def test_form_prefill_field(pub):
create_superuser(pub)
create_role(pub)
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', 'locked': False}
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', 'locked': False}
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}}',
'locked': False,
}
# 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.text
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.text
def test_form_prefill_type_options(pub):
create_superuser(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [fields.StringField(id='1', label='1st field', type='string')]
formdef.store()
if not pub.site_options.has_section('options'):
pub.site_options.add_section('options')
pub.site_options.set('options', 'disable-python-expressions', 'false')
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/fields/1/')
assert resp.forms[0]['prefill$type'].options == [
('None', True, 'None'),
('String / Template', False, 'String / Template'),
('Python Expression', False, 'Python Expression'),
('User Field', False, 'User Field'),
('Geolocation', False, 'Geolocation'),
]
pub.site_options.set('options', 'disable-python-expressions', 'true')
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
pub.site_options.write(fd)
resp = app.get('/backoffice/forms/1/fields/1/')
assert resp.forms[0]['prefill$type'].options == [
('None', True, 'None'),
('String / Template', False, 'String / Template'),
('User Field', False, 'User Field'),
('Geolocation', False, 'Geolocation'),
]
def test_form_edit_string_field_validation(pub):
create_superuser(pub)
create_role(pub)
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.text
resp = resp.click('Edit', href='1/')
resp.form['validation$type'] = 'Regular Expression'
resp.form['validation$value_regex'] = r'\d+'
resp.form['validation$error_message'] = 'Foo Error'
resp = resp.form.submit('submit').follow()
assert FormDef.get(formdef.id).fields[0].validation == {
'type': 'regex',
'value': r'\d+',
'error_message': 'Foo Error',
}
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.form['validation$error_message'] = 'Bar Error'
resp = resp.form.submit('submit').follow()
assert FormDef.get(formdef.id).fields[0].validation == {
'type': 'django',
'value': 'value|decimal < 20',
'error_message': 'Bar Error',
}
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.text
def test_form_edit_item_field(pub):
create_superuser(pub)
create_role(pub)
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.text
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 is 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(pub)
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 == [
('None', True, 'None'),
('json', False, 'JSON URL'),
('jsonp', False, 'JSONP URL'),
('python', False, 'Python Expression'),
]
resp = resp.form.submit('submit').follow()
data_source = NamedDataSource(name='Foobar')
data_source.data_source = {'type': 'json', 'value': 'http://remote.example.net/404'}
data_source.record_on_errors = True
data_source.notify_on_errors = True
data_source.store()
resp = app.get('/backoffice/forms/1/fields/1/')
assert resp.form['data_source$type'].options == [
('None', True, 'None'),
('foobar', False, 'Foobar'),
('json', False, 'JSON URL'),
('jsonp', False, 'JSONP URL'),
('python', False, 'Python Expression'),
]
resp.form['data_mode'].value = 'data-source'
resp.form['data_source$type'].value = 'foobar'
resp.form.submit('submit').follow()
resp = app.get('/backoffice/forms/1/')
assert FormDef.get(formdef.id).fields[0].data_source == {'type': 'foobar'}
assert pub.loggederror_class.count() == 0 # error not recorded
carddef = CardDef()
carddef.name = 'Baz'
carddef.store()
resp = app.get('/backoffice/forms/1/fields/1/')
assert resp.form['data_source$type'].options == [
('None', False, 'None'),
('foobar', True, 'Foobar'),
('json', False, 'JSON URL'),
('jsonp', False, 'JSONP URL'),
('python', False, 'Python Expression'),
]
carddef.digest_templates = {'default': 'plop'}
carddef.store()
resp = app.get('/backoffice/forms/1/fields/1/')
assert resp.form['data_source$type'].options == [
('None', False, 'None'),
('carddef:%s' % carddef.url_name, False, 'Baz'),
('foobar', True, 'Foobar'),
('json', False, 'JSON URL'),
('jsonp', False, 'JSONP URL'),
('python', False, 'Python Expression'),
]
assert (
resp.pyquery('select#form_data_source__type option')[1].attrib['data-goto-url']
== carddef.get_admin_url()
)
assert (
resp.pyquery('select#form_data_source__type option')[2].attrib['data-goto-url']
== data_source.get_admin_url()
)
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/')
# change configuration for items
resp = app.get('/backoffice/forms/1/fields/1/')
resp.form['data_mode'].value = 'simple-list'
resp.form['items$element0'] = 'XXX'
resp = resp.form.submit('submit').follow()
assert FormDef.get(1).fields[0].data_source is None
assert FormDef.get(1).fields[0].items == ['XXX']
def test_form_edit_item_field_data_source_with_categories(pub):
create_superuser(pub)
create_role(pub)
FormDef.wipe()
CardDef.wipe()
DataSourceCategory.wipe()
NamedDataSource.wipe()
data_source = NamedDataSource(name='test')
data_source.store()
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 [o[0] for o in resp.form['data_source$type'].options] == [
'None',
'test',
'json',
'jsonp',
'python',
]
cat_b = DataSourceCategory(name='Cat B')
cat_b.store()
data_source = NamedDataSource(name='foo bar')
data_source.category_id = cat_b.id
data_source.store()
data_source = NamedDataSource(name='bar foo')
data_source.category_id = cat_b.id
data_source.store()
cat_a = DataSourceCategory(name='Cat A')
cat_a.store()
data_source = NamedDataSource(name='foo baz')
data_source.category_id = cat_a.id
data_source.store()
resp = app.get('/backoffice/forms/1/fields/1/')
assert [o[0] for o in resp.form['data_source$type'].options] == [
'None',
'foo_baz',
'bar_foo',
'foo_bar',
'test',
'json',
'jsonp',
'python',
]
def test_form_edit_item_field_geojson_data_source(pub, http_requests):
NamedDataSource.wipe()
create_superuser(pub)
create_role(pub)
NamedDataSource.wipe()
data_source = NamedDataSource(name='foobar')
data_source.data_source = {
'type': 'geojson',
'value': 'http://remote.example.net/geojson',
}
data_source.id_property = 'id'
data_source.label_template_property = '{{ text }}'
data_source.cache_duration = '5'
data_source.store()
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/')
resp.form['display_mode'] = 'map'
assert resp.pyquery('option[value=foobar][data-type=geojson]')
resp.form['data_mode'] = 'data-source'
resp.form['data_source$type'] = 'foobar'
resp.form['min_zoom'] = 'Wide area'
resp.form['max_zoom'] = 'Small road'
resp = resp.form.submit('submit').follow()
formdef = FormDef.get(formdef.id)
assert formdef.fields[0].data_source == {'type': 'foobar'}
assert formdef.fields[0].min_zoom == '9'
resp = app.get('/backoffice/forms/1/fields/1/')
assert resp.form['min_zoom'].value == 'Wide area'
def test_form_edit_items_field(pub):
create_superuser(pub)
create_role(pub)
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.text
resp = resp.click('Edit', href='1/')
assert resp.forms[0]['label'].value == '1st field'
assert resp.forms[0]['min_choices'].value == '0'
assert resp.forms[0]['max_choices'].value == '0'
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 is False
assert FormDef.get(1).fields[0].items is None
assert FormDef.get(1).fields[0].min_choices == 0
assert FormDef.get(1).fields[0].max_choices == 0
# 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.forms[0]['min_choices'] = 2
resp.forms[0]['max_choices'] = 5
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']
assert FormDef.get(1).fields[0].min_choices == 2
assert FormDef.get(1).fields[0].max_choices == 5
# check prefilling is possible with a template or a Python expression
resp = resp.follow()
resp = resp.click('Edit', href='1/')
assert resp.forms[0]['prefill$type'].options == [
('None', True, 'None'),
('String / Template', False, 'String / Template'),
('Python Expression', False, 'Python Expression'),
]
# change configuration for datasource
resp = app.get('/backoffice/forms/1/fields/1/')
resp.form['data_mode'].value = 'data-source'
resp.form['data_source$type'].value = 'json'
resp.form['data_source$value'].value = 'http://whatever'
resp = resp.form.submit('submit').follow()
assert FormDef.get(1).fields[0].data_source == {'type': 'json', 'value': 'http://whatever'}
# change configuration for items
resp = app.get('/backoffice/forms/1/fields/1/')
resp.form['data_mode'].value = 'simple-list'
resp = resp.form.submit('submit').follow()
assert FormDef.get(1).fields[0].data_source is None
assert FormDef.get(1).fields[0].items == ['XXX']
def test_form_edit_items_datasource(pub):
create_superuser(pub)
create_role(pub)
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.text
resp = app.get('/backoffice/forms/1/fields/1/')
resp.form['data_mode'].value = 'data-source'
resp.form['data_source$type'].value = 'json'
resp.form['data_source$value'].value = 'random string'
resp = resp.form.submit('submit')
assert 'Value must be a full URL.' in resp.text
resp.form['data_source$value'].value = 'http://whatever'
resp = resp.form.submit('submit').follow()
assert FormDef.get(1).fields[0].data_source == {'type': 'json', 'value': 'http://whatever'}
# check template strings are ok
resp = app.get('/backoffice/forms/1/fields/1/')
resp.form['data_mode'].value = 'data-source'
resp.form['data_source$type'].value = 'json'
resp.form['data_source$value'].value = '{{url}}'
resp = resp.form.submit('submit').follow()
assert FormDef.get(1).fields[0].data_source == {'type': 'json', 'value': '{{url}}'}
def test_form_edit_page_field(pub):
create_superuser(pub)
create_role(pub)
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' in resp.text
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.text
assert 'foobar' in resp.text
assert 'Use drag and drop' in resp.text
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')
# check advanced tab is open after adding a line
assert resp.pyquery('[aria-selected="true"]').text() == 'Advanced'
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.text
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'},
]
# check error in expression
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')
assert 'syntax error: Unexpected end of expression in if tag.' in resp.text
def test_form_edit_comment_field(pub):
create_superuser(pub)
create_role(pub)
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.text
assert 'WysiwygTextWidget' in resp.text
# 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.text
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.text
# 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.text
# 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_comment_field_textwidget_validation(pub):
create_superuser(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
# 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()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/fields/1/')
# bad {% %} Django template syntax
assert 'WysiwygTextWidget' not in resp.text
resp.form.fields['label'][0].value = '{% if cond %}no endif provided'
resp = resp.form.submit('submit')
assert 'syntax error in Django template: Unclosed tag on line 1' in resp.text
# bad {{ }} Django template syntax
assert 'WysiwygTextWidget' not in resp.text
resp.form.fields['label'][0].value = '{{0+0}}'
resp = resp.form.submit('submit')
assert 'syntax error in Django template: Could not parse' in resp.text
# bad EZT syntax
assert 'WysiwygTextWidget' not in resp.text
resp.form.fields['label'][0].value = '[end]'
resp = resp.form.submit('submit')
assert 'syntax error in ezt template: unmatched [end]' in resp.text
# good syntax
assert 'WysiwygTextWidget' not in resp.text
resp.form.fields['label'][0].value = '{{variable}}'
resp = resp.form.submit('submit')
assert FormDef.get(formdef.id).fields[0].label == '{{variable}}'
def test_form_comment_field_wysiwygtextwidget_validation(pub):
create_superuser(pub)
create_role(pub)
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.text
# bad {% %} Django template syntax
assert 'WysiwygTextWidget' in resp.text
resp.form.fields['label'][0].value = '{% if cond %}no endif provided'
resp = resp.form.submit('submit')
assert 'syntax error in Django template: Unclosed tag on line 1' in resp.text
# bad {{ }} Django template syntax
assert 'WysiwygTextWidget' in resp.text
resp.form.fields['label'][0].value = '{{0+0}}'
resp = resp.form.submit('submit')
assert 'syntax error in Django template: Could not parse' in resp.text
# bad EZT syntax
assert 'WysiwygTextWidget' in resp.text
resp.form.fields['label'][0].value = '[end]'
resp = resp.form.submit('submit')
assert 'syntax error in ezt template: unmatched [end]' in resp.text
# good syntax
assert 'WysiwygTextWidget' in resp.text
resp.form.fields['label'][0].value = '{{variable}}'
resp = resp.form.submit('submit')
assert FormDef.get(formdef.id).fields[0].label == '{{variable}}'
def test_form_edit_map_field(pub):
create_superuser(pub)
create_role(pub)
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.text
# 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.text
# 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',
'locked': False,
}
def test_form_edit_field_warnings(pub):
create_superuser(pub)
create_role(pub)
if not pub.site_options.has_section('options'):
pub.site_options.add_section('options')
pub.site_options.set('options', 'ignore-hard-limits', 'false')
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
pub.site_options.write(fd)
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/%s/fields/' % formdef.id)
assert 'more than 200 fields' not in resp.text
assert 'first field should be of type "page"' not in resp.text
formdef.fields.append(fields.PageField(id='1000', label='page', type='page'))
formdef.store()
resp = app.get('/backoffice/forms/%s/fields/' % formdef.id)
assert 'more than 200 fields' not in resp.text
assert 'first field should be of type "page"' in resp.text
assert '<div id="new-field"><h3>New Field</h3>' in resp.text
formdef.fields.extend(
[fields.StringField(id='%d' % i, label='field %d' % i, type='string') for i in range(10, 210)]
)
formdef.store()
resp = app.get('/backoffice/forms/%s/fields/' % formdef.id)
assert 'more than 200 fields' in resp.text
assert 'first field should be of type "page"' in resp.text
assert '>Duplicate<' in resp.text
formdef.fields.extend(
[fields.StringField(id='%d' % i, label='field %d' % i, type='string') for i in range(210, 410)]
)
formdef.store()
resp = app.get('/backoffice/forms/%s/fields/' % formdef.id)
assert 'This form contains 410 fields.' in resp.text
assert 'no new fields can be added.' in resp.text
assert 'first field should be of type "page"' in resp.text
assert '<div id="new-field"><h3>New Field</h3>' not in resp.text
assert '>Duplicate<' not in resp.text
assert resp.pyquery('aside .errornotice')
assert not resp.pyquery('aside form[action=new]')
if not pub.site_options.has_section('options'):
pub.site_options.add_section('options')
pub.site_options.set('options', 'ignore-hard-limits', 'true')
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
pub.site_options.write(fd)
resp = app.get('/backoffice/forms/%s/fields/' % formdef.id)
assert 'no new fields should be added.' in resp.text
assert '<div id="new-field"><h3>New Field</h3>' in resp.text
assert '>Duplicate<' in resp.text
assert not resp.pyquery('aside .errornotice')
assert resp.pyquery('aside form[action=new]')
FormDef.wipe()
def test_form_limit_display_to_page(pub):
create_superuser(pub)
create_role(pub)
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'),
fields.PageField(id='4', label='3rd page', type='page'),
fields.StringField(id='5', label='string 3', type='string', varname='baz2'),
]
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/fields/')
assert '{{ form_var_foobar }}' in resp.text
assert '2nd page' in resp.text
resp = resp.click('Limit display to this page', index=0)
hidden_fields = ''.join(re.findall('display: none.*', resp.text))
assert 'All pages' in resp.text
assert '1st page' not in hidden_fields
assert '2nd page' in hidden_fields
assert '{{ form_var_foobar }}' not in hidden_fields
assert '{{ form_var_baz }}' in hidden_fields
assert resp.pyquery('.form-pages-navigation a:first-child').hasClass('disabled')
assert not resp.pyquery('.form-pages-navigation a:last-child').hasClass('disabled')
resp = resp.click('Next page')
assert not resp.pyquery('.form-pages-navigation a:first-child').hasClass('disabled')
assert not resp.pyquery('.form-pages-navigation a:last-child').hasClass('disabled')
resp = resp.click('Next page')
assert not resp.pyquery('.form-pages-navigation a:first-child').hasClass('disabled')
assert resp.pyquery('.form-pages-navigation a:last-child').hasClass('disabled')
# remove field on current page
resp = resp.click(href='5/delete')
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/%s/fields/pages/4/#itemId_4' % formdef.id
resp = resp.follow()
# remove current page itself
resp = resp.click(href='4/delete')
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/forms/%s/fields/#itemId_3' % formdef.id
# visit a page that doesn't exist
app.get('/backoffice/forms/1/fields/pages/123/', status=404)
def test_form_page_field_condition_types(pub):
create_superuser(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [
fields.PageField(id='0', label='1st page', type='page'),
]
formdef.store()
if not pub.site_options.has_section('options'):
pub.site_options.add_section('options')
pub.site_options.set('options', 'disable-python-expressions', 'false')
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/fields/0/')
assert resp.form['condition$type'].options == [
('django', False, 'Django Expression'),
('python', False, 'Python Expression'),
]
pub.site_options.set('options', 'disable-python-expressions', 'true')
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
pub.site_options.write(fd)
resp = app.get('/backoffice/forms/1/fields/0/')
assert resp.form['condition$type'].options == [
('django', False, 'Django Expression'),
]
def test_form_fields_reorder(pub):
create_superuser(pub)
create_role(pub)
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'),
fields.PageField(id='2', label='2nd page', type='page'),
fields.StringField(id='3', label='string 2', type='string'),
]
formdef.store()
app = login(get_app(pub))
# missing element in params: do nothing
resp = app.get('/backoffice/forms/%s/fields/update_order?order=0;3;1;2;' % formdef.id)
assert resp.json == {'success': 'ko'}
# missing order in params: do nothing
resp = app.get('/backoffice/forms/%s/fields/update_order?element=0' % formdef.id)
assert resp.json == {'success': 'ko'}
resp = app.get('/backoffice/forms/%s/fields/update_order?order=0;3;1;2;&element=3' % formdef.id)
assert resp.json == {'success': 'ok'}
formdef = FormDef.get(formdef.id)
assert [x.id for x in formdef.fields] == ['0', '3', '1', '2']
# unknown id: ignored
resp = app.get('/backoffice/forms/%s/fields/update_order?order=0;1;2;3;4;&element=3' % formdef.id)
assert resp.json == {'success': 'ok'}
formdef = FormDef.get(formdef.id)
assert [x.id for x in formdef.fields] == ['0', '1', '2', '3']
# missing id: do nothing
resp = app.get('/backoffice/forms/%s/fields/update_order?order=0;3;1;&element=3' % formdef.id)
assert resp.json == {'success': 'ko'}
formdef = FormDef.get(formdef.id)
assert [x.id for x in formdef.fields] == ['0', '1', '2', '3']
# move a page
resp = app.get('/backoffice/forms/%s/fields/update_order?order=2;0;1;3;&element=2' % formdef.id)
assert resp.json == {
'success': 'ok',
'additional-action': {
'message': 'Also move the fields of the page',
'url': 'move_page_fields?fields=3&page=2',
},
}
# reset
resp = app.get('/backoffice/forms/%s/fields/update_order?order=0;1;2;3;&element=2' % formdef.id)
assert resp.json == {'success': 'ok'}
# move the first page
resp = app.get('/backoffice/forms/%s/fields/update_order?order=1;2;3;0;&element=0' % formdef.id)
assert resp.json == {
'success': 'ok',
'additional-action': {
'message': 'Also move the fields of the page',
'url': 'move_page_fields?fields=1&page=0',
},
}
def test_form_move_page_fields(pub):
create_superuser(pub)
create_role(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [
fields.PageField(id='2', label='2nd page', type='page'),
fields.PageField(id='0', label='1st page', type='page'),
fields.StringField(id='1', label='string', type='string'),
fields.StringField(id='3', label='string 2', type='string'),
]
formdef.store()
app = login(get_app(pub))
# missing element in params: do nothing
app.get('/backoffice/forms/%s/fields/move_page_fields?fields=3' % formdef.id)
formdef = FormDef.get(formdef.id)
assert [x.id for x in formdef.fields] == ['2', '0', '1', '3']
# missing order in params: do nothing
app.get('/backoffice/forms/%s/fields/move_page_fields?page=2' % formdef.id)
formdef = FormDef.get(formdef.id)
assert [x.id for x in formdef.fields] == ['2', '0', '1', '3']
# unknown id: do nothing
app.get('/backoffice/forms/%s/fields/move_page_fields?fields=4&page=2' % formdef.id)
formdef = FormDef.get(formdef.id)
assert [x.id for x in formdef.fields] == ['2', '0', '1', '3']
# move the fields of the page
app.get('/backoffice/forms/%s/fields/move_page_fields?fields=3&page=2' % formdef.id)
formdef = FormDef.get(formdef.id)
assert [x.id for x in formdef.fields] == ['2', '3', '0', '1']
# move the new first page
app.get('/backoffice/forms/%s/fields/update_order?order=3;0;1;2&element=2' % formdef.id)
formdef = FormDef.get(formdef.id)
assert [x.id for x in formdef.fields] == ['3', '0', '1', '2']
# and the fields
app.get('/backoffice/forms/%s/fields/move_page_fields?fields=3&page=2' % formdef.id)
formdef = FormDef.get(formdef.id)
assert [x.id for x in formdef.fields] == ['0', '1', '2', '3']
def test_form_legacy_int_id(pub):
create_superuser(pub)
create_role(pub)
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 = pub.role_class(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_public_url(pub):
create_superuser(pub)
create_role(pub)
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.text
def test_form_management_view(pub):
create_superuser(pub)
create_role(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/1/')
assert 'backoffice/management/form-title/' in resp
def test_form_overwrite(pub):
create_superuser(pub)
create_role(pub)
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 'Overwrite - Summary of changes' in resp.text
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.text
# check with added/removed field
new_formdef = FormDef()
new_formdef.name = 'form test overwrite'
new_formdef.fields = [
fields.StringField(id='2', label='2nd field', type='string'),
fields.StringField(id='3', label='3rd field', type='string'),
]
new_formdef_xml = ET.tostring(new_formdef.export_to_xml(include_id=True))
# and no data within
formdef.data_class().wipe()
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', new_formdef_xml)
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'
# and data within
formdef.store()
formdata.data = {'1': 'foo', '2': 'bar'}
formdata.just_created()
formdata.store()
resp = app.get('/backoffice/forms/%s/' % formdef_id)
resp = resp.click(href='overwrite')
resp.forms[0]['file'] = Upload('formdef.wcs', new_formdef_xml)
resp = resp.forms[0].submit()
assert 'The form removes or changes fields' in resp.text
assert resp.forms[0]['force'].checked is False
resp = resp.forms[0].submit() # without checkbox (back to same form)
resp.forms[0]['force'].checked = True
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.get(formdef_id)
formdata = formdef.data_class()()
formdata.data = {'1': 'foo', '2': 'bar', '3': 'baz'}
formdata.just_created()
formdata.store()
new_formdef = FormDef()
new_formdef.name = 'form test overwrite'
new_formdef.fields = [
fields.StringField(id='2', label='2nd field', type='string'),
fields.DateField(id='3', label='3rd field, date', type='date'),
] # (string -> date)
new_formdef_xml = ET.tostring(new_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', new_formdef_xml)
resp = resp.forms[0].submit()
assert 'The form removes or changes fields' in resp.text
resp.forms[0]['force'].checked = 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, date'
assert FormDef.get(formdef_id).fields[1].type == 'date'
# check we kept stable references
assert FormDef.get(formdef_id).url_name == 'form-test'
assert FormDef.get(formdef_id).table_name == 'xxx'
# check existing data
data = FormDef.get(formdef_id).data_class().get(formdata.id).data
assert data.get('2') == 'bar'
# in SQL, check data with different type has been removed
assert data.get('3') is None
def test_form_export_import_export_overwrite(pub):
create_superuser(pub)
create_role(pub)
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()
# add data
formdata = formdef.data_class()()
formdata.data = {'1': 'foo'}
formdata.just_created()
formdata.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()
assert 'Overwrite - Summary of changes' in resp.text
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_with_custom_views_import_export_overwrite(pub):
user = create_superuser(pub)
create_role(pub)
FormDef.wipe()
pub.custom_view_class.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()
# add data
formdata = formdef.data_class()()
formdata.data = {'1': 'foo'}
formdata.just_created()
formdata.store()
# add custom view
custom_view = pub.custom_view_class()
custom_view.title = 'custom test view'
custom_view.formdef = formdef
custom_view.visibility = 'any'
custom_view.columns = {'list': [{'id': 'id'}]}
custom_view.filters = {}
custom_view.store()
# add private custom view
custom_view2 = pub.custom_view_class()
custom_view2.title = 'private custom test view'
custom_view2.formdef = formdef
custom_view2.visibility = 'owner'
custom_view2.user_id = str(user.id)
custom_view2.columns = {'list': [{'id': 'id'}]}
custom_view2.filters = {}
custom_view2.store()
formdef_xml = ET.tostring(formdef.export_to_xml(include_id=True))
# alter initial custom view
custom_view.title = 'modified custom test view'
custom_view.store()
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() # -> confirmation
resp = resp.forms[0].submit() # -> overwrite
assert {x.title for x in pub.custom_view_class.select()} == {
'custom test view',
'private custom test view',
}
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.record_on_errors = True
wscall.notify_on_errors = True
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.text
assert pub.loggederror_class.count() == 0 # error not recorded
def test_form_new_computed_field(pub):
create_superuser(pub)
create_role(pub)
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/')
resp.forms[0]['label'] = 'foobar'
resp.forms[0]['type'] = 'computed'
resp = resp.forms[0].submit().follow()
assert len(FormDef.get(1).fields) == 1
assert FormDef.get(1).fields[0].key == 'computed'
assert FormDef.get(1).fields[0].label == 'foobar'
assert FormDef.get(1).fields[0].varname == 'foobar'
def test_form_category_management_roles(pub, backoffice_user, backoffice_role):
app = login(get_app(pub), username='backoffice-user', password='backoffice-user')
app.get('/backoffice/forms/', status=403)
Category.wipe()
cat = Category(name='Foo')
cat.store()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.category_id = cat.id
formdef.fields = []
formdef.store()
cat = Category(name='Bar')
cat.management_roles = [backoffice_role]
cat.store()
resp = app.get('/backoffice/forms/')
assert 'Foo' not in resp.text # not a category managed by user
assert 'form title' not in resp.text # formdef in that category
assert 'Bar' not in resp.text # not yet any form in this category
app.get('/backoffice/forms/%s/' % formdef.id, status=403)
resp = resp.click('New Form')
resp.forms[0]['name'] = 'form in category'
assert len(resp.forms[0]['category_id'].options) == 1 # single option
assert resp.forms[0]['category_id'].value == cat.id # the category managed by user
resp = resp.forms[0].submit().follow()
new_formdef = FormDef.get_by_urlname('form-in-category')
# check category select only let choose one
resp = resp.click(href='/category')
assert len(resp.forms[0]['category_id'].options) == 1 # single option
assert resp.forms[0]['category_id'].value == cat.id # the category managed by user
resp = app.get('/backoffice/forms/')
assert 'Bar' in resp.text # now there's a form in this category
assert 'form in category' in resp.text
# no access to subdirectories
assert 'href="categories/"' not in resp.text
assert 'href="data-sources/"' not in resp.text
assert 'href="blocks/"' not in resp.text
app.get('/backoffice/forms/categories/', status=403)
app.get('/backoffice/forms/data-sources/', status=403)
app.get('/backoffice/forms/blocks/', status=403)
# no import into other category
formdef_xml = ET.tostring(formdef.export_to_xml(include_id=True))
resp = resp.click(href='import')
resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml)
resp = resp.forms[0].submit()
assert 'Invalid File (unauthorized category)' in resp.text
# check access to inspect page
formdef.workflow_roles = {'_receiver': int(backoffice_role.id)}
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.store()
resp = app.get(formdata.get_backoffice_url())
assert 'inspect' not in resp.text
resp = app.get(formdata.get_backoffice_url() + 'inspect', status=403)
new_formdef.workflow_roles = {'_receiver': int(backoffice_role.id)}
new_formdef.store()
formdata = new_formdef.data_class()()
formdata.just_created()
formdata.store()
resp = app.get(formdata.get_backoffice_url())
assert 'inspect' in resp.text
resp = app.get(formdata.get_backoffice_url() + 'inspect')
def test_form_restricted_access_import_error(pub, backoffice_user, backoffice_role):
Category.wipe()
cat = Category(name='Foo')
cat.management_roles = [backoffice_role]
cat.store()
FormDef.wipe()
app = login(get_app(pub), username='backoffice-user', password='backoffice-user')
resp = app.get('/backoffice/forms/import')
resp.forms[0]['file'] = Upload('formdef.wcs', b'broken content')
resp = resp.forms[0].submit()
assert 'Invalid File' in resp.text
assert FormDef.count() == 0
def test_form_preview_edit_page_fields(pub):
create_superuser(pub)
create_role(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [
fields.PageField(id='1', label='first page', type='page'),
fields.StringField(id='2', label='a field', type='string'),
fields.StringField(id='3', label='another field', type='string'),
fields.PageField(id='4', label='second page', type='page'),
]
formdef.store()
formdef.data_class().wipe()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/%s/' % formdef.id)
assert resp.pyquery('fieldset.formpage a')
assert [x.attrib['href'] for x in resp.pyquery('fieldset.formpage a')] == [
'fields/pages/1/',
'fields/pages/4/',
]
resp = resp.click('edit page fields', index=0)
assert '<h2>form title - page 1 - first page</h2>' in resp.text
resp = resp.click('Edit', index=0)
assert '/backoffice/forms/1/fields/pages/1/#itemId_1' in resp
assert '/backoffice/forms/1/fields/pages/1/1/' in resp # without anchor
def test_field_display_locations_statistics_choice(pub):
create_superuser(pub)
create_role(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [
fields.StringField(id='0', label='String field', varname='var_1'),
fields.ItemField(id='1', label='Item field', type='item'),
fields.ItemsField(id='2', label='Items field', type='items'),
fields.BoolField(id='3', label='Bool field', type='bool'),
]
formdef.store()
formdef.data_class().wipe()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/%s/fields/0/' % formdef.id)
assert 'Statistics' not in resp.text
for i in range(1, 4):
resp = app.get('/backoffice/forms/%s/fields/%s/' % (formdef.id, i))
assert 'Statistics' in resp.text
resp.form['display_locations$element3'] = True
resp = resp.form.submit('submit')
assert 'Field must have a varname in order to be displayed in statistics.' in resp.text
assert 'statistics' not in FormDef.get(formdef.id).fields[i].display_locations
resp.form['varname'] = 'var_%s' % i
resp = resp.form.submit('submit')
assert 'statistics' in FormDef.get(formdef.id).fields[i].display_locations
def test_admin_form_inspect(pub):
create_superuser(pub)
create_role(pub)
NamedDataSource.wipe()
data_source = NamedDataSource(name='Foobar')
data_source.data_source = {'type': 'json', 'value': 'http://remote.example.net/404'}
data_source.store()
CardDef.wipe()
carddef = CardDef()
carddef.name = 'Baz'
carddef.digest_templates = {'default': 'plop'}
carddef.store()
Workflow.wipe()
workflow = Workflow(name='Workflow One')
workflow.variables_formdef = WorkflowVariablesFieldsFormDef(workflow=workflow)
workflow.variables_formdef.fields = [
fields.TitleField(id='0', label='option title', type='title'),
fields.StringField(id='1', varname='test', label='Test', type='string'),
]
workflow.store()
BlockDef.wipe()
block = BlockDef()
block.name = 'foobar'
block.fields = [
fields.StringField(id='123', required=True, label='Test', type='string'),
fields.StringField(id='234', required=True, label='Test2', type='string'),
]
block.store()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.workflow_id = workflow.id
formdef.fields = [
fields.PageField(
id='0',
label='1st page',
type='page',
post_conditions=[
{'condition': {'type': 'django', 'value': 'false'}, 'error_message': 'You shall not pass.'}
],
),
fields.StringField(
id='1', label='String field', varname='var_1', condition={'type': 'django', 'value': 'true'}
),
fields.StringField(id='2', label='String field digits', validation={'type': 'digits'}),
fields.StringField(id='3', label='String field regex', validation={'type': 'regex', 'value': r'\d+'}),
fields.ItemField(
id='4',
label='Date field',
type='date',
),
fields.ItemField(id='5', label='Item field', type='item', items=['One', 'Two', 'Three']),
fields.ItemField(
id='6', label='Item field named data source', type='item', data_source={'type': 'foobar'}
),
fields.ItemField(
id='7', label='Item field carddef data source', type='item', data_source={'type': 'carddef:baz'}
),
fields.ItemField(
id='8',
label='Item field json data source',
type='item',
data_source={'type': 'json', 'value': 'http://test'},
),
fields.ItemsField(id='9', label='Items field', type='items', items=['One', 'Two', 'Three']),
fields.StringField(id='10', label='prefill', prefill={'type': 'user', 'value': 'email'}),
fields.StringField(
id='11', label='prefill2', prefill={'type': 'string', 'value': '{{plop}}', 'locked': True}
),
fields.FileField(
id='12', label='file', automatic_image_resize=True, display_locations=['validation']
),
fields.BlockField(id='13', label='Block field', type='block:foobar'),
]
formdef.workflow_options = {'test': 'plop'}
formdef.store()
app = login(get_app(pub))
resp = app.get('/backoffice/forms/%s/inspect' % formdef.id)
assert 'Test → plop' in resp.text # workflow option
assert '<strong>option title</strong>' in resp.text # title field as workflow option
assert (
resp.pyquery('[data-field-id="0"] .parameter-post_conditions').text()
== 'Post Conditions:\nfalse (Django) - You shall not pass.'
)
assert (
resp.pyquery('[data-field-id="1"] .parameter-condition').text() == 'Display Condition: true (Django)'
)
assert resp.pyquery('[data-field-id="2"] .parameter-validation').text() == 'Validation: Digits'
assert (
resp.pyquery('[data-field-id="3"] .parameter-validation').text()
== 'Validation: Regular Expression - \\d+'
)
assert resp.pyquery('[data-field-id="5"] .parameter-items').text() == 'Choices: One, Two, Three'
assert resp.pyquery('[data-field-id="6"] .parameter-data_source').text() == 'Data source: Foobar'
assert (
resp.pyquery('[data-field-id="7"] .parameter-data_source').text() == 'Data source: card model - Baz'
)
assert (
resp.pyquery('[data-field-id="8"] .parameter-data_source').text()
== 'Data source: JSON URL - http://test'
)
assert (
resp.pyquery('[data-field-id="10"] .parameter-prefill').text()
== 'Prefill:\nType: User Field\nValue: Email (builtin)'
)
assert (
resp.pyquery('[data-field-id="11"] .parameter-prefill').text()
== 'Prefill:\nType: String / Template\nValue: {{plop}}\nLocked'
)
assert (
resp.pyquery('[data-field-id="12"] .parameter-automatic_image_resize').text()
== 'Automatically resize uploaded images: Yes'
)
assert (
resp.pyquery('[data-field-id="12"] .parameter-display_locations').text()
== 'Display Locations: Validation Page'
)
assert resp.pyquery('[data-field-id="13"] h4 .inspect-field-type a').attr.href.endswith(
block.get_admin_url() + 'inspect'
)