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 '

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 '

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 '' 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 '' in resp assert '' 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 '
' 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 = '

Hello World

' 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' 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' 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 ( ""1st field" 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 == '

a comment field

\n

a second line

' # starting with a < 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 # 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

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 == '

foobar

' # unless label is already given as HTML resp = app.get('/backoffice/forms/1/fields/') resp.forms[0]['label'] = '
blah
' 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 == '
blah
' 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 '

New Field

' 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 '

New Field

' 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 '

New Field

' 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 '

form title - page 1 - first page

' 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 'option title' 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' )