From 2162c8c2503b1b27ab3109127c35efe2340f993b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Tue, 4 Aug 2020 11:45:22 +0200 Subject: [PATCH] tests: split admin form pages test into their own module --- tests/test_admin_pages.py | 2221 +----------------------------- tests/test_forms_admin_pages.py | 2267 +++++++++++++++++++++++++++++++ 2 files changed, 2268 insertions(+), 2220 deletions(-) create mode 100644 tests/test_forms_admin_pages.py diff --git a/tests/test_admin_pages.py b/tests/test_admin_pages.py index 5aa19a422..43d41efe0 100644 --- a/tests/test_admin_pages.py +++ b/tests/test_admin_pages.py @@ -1,12 +1,8 @@ # -*- coding: utf-8 -*- -import datetime import logging import os import re -import tarfile -import time -import xml.etree.ElementTree as ET import zipfile try: @@ -18,7 +14,7 @@ import pytest from webtest import Upload import mock -from django.utils.six import StringIO, BytesIO +from django.utils.six import BytesIO from django.utils.six.moves.urllib import parse as urlparse from quixote.http_request import Upload as QuixoteUpload @@ -187,2221 +183,6 @@ def test_admin_for_all(pub): user.store() -def test_forms(pub): - user = create_superuser(pub) - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/') - assert 'You first have to define roles.' in resp.text - assert not 'New Form' in resp.text - - -def test_forms_new(pub): - user = create_superuser(pub) - app = login(get_app(pub)) - create_role() - - # create a new form - resp = app.get('/backoffice/forms/') - assert 'New Form' in resp.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 == True - assert formdef.last_modification_user_id == str(user.id) - - -def test_forms_new_popup(pub): - FormDef.wipe() - user = create_superuser(pub) - app = login(get_app(pub)) - create_role() - - # create a new form - resp = app.get('/backoffice/forms/') - assert 'New Form' in resp.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 == True - assert formdef.last_modification_user_id == str(user.id) - - -def assert_option_display(resp, label, value): - option_line = re.findall('%s.*%s' % (label, value), resp.text, re.DOTALL) - assert option_line - assert not '' in option_line - - -def test_forms_edit(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - - # try changing an option - - # confirmation page - assert_option_display(resp, 'Confirmation Page', 'Enabled') - resp = resp.click('Confirmation Page') - assert resp.forms[0]['confirmation'].checked - resp.forms[0]['confirmation'].checked = False - resp = resp.forms[0].submit() - assert resp.location == 'http://example.net/backoffice/forms/1/' - resp = resp.follow() - assert_option_display(resp, 'Confirmation Page', 'Disabled') - assert FormDef.get(1).confirmation == False - - # try cancel button - resp = resp.click('Confirmation Page') - assert resp.forms[0]['confirmation'].checked is False - resp.forms[0]['confirmation'].checked = True - resp = resp.forms[0].submit('cancel') - assert resp.location == 'http://example.net/backoffice/forms/1/' - resp = resp.follow() - assert_option_display(resp, 'Confirmation Page', 'Disabled') - assert FormDef.get(1).confirmation == False - - # Limit to one form - assert_option_display(resp, 'Limit to one form', 'Disabled') - resp = resp.click('Limit to one form') - assert resp.forms[0]['only_allow_one'].checked is False - resp.forms[0]['only_allow_one'].checked = True - resp = resp.forms[0].submit() - assert resp.location == 'http://example.net/backoffice/forms/1/' - resp = resp.follow() - assert_option_display(resp, 'Limit to one form', 'Enabled') - assert FormDef.get(1).only_allow_one is True - - # 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 - - # Tracking code - assert_option_display(resp, 'Tracking Code', 'Disabled') - resp = resp.click('Tracking Code') - assert resp.forms[0]['enable_tracking_codes'].checked is False - resp.forms[0]['enable_tracking_codes'].checked = True - resp = resp.forms[0].submit() - assert resp.location == 'http://example.net/backoffice/forms/1/' - resp = resp.follow() - assert_option_display(resp, 'Tracking Code', 'Enabled') - assert FormDef.get(1).enable_tracking_codes is True - - # CAPTCHA - assert_option_display(resp, 'CAPTCHA for anonymous users', 'Disabled') - resp = resp.click('CAPTCHA for anonymous users') - assert resp.forms[0]['has_captcha'].checked is False - resp.forms[0]['has_captcha'].checked = True - resp = resp.forms[0].submit() - assert resp.location == 'http://example.net/backoffice/forms/1/' - resp = resp.follow() - assert_option_display(resp, 'CAPTCHA for anonymous users', 'Enabled') - assert FormDef.get(1).has_captcha is True - - # Appearance - assert_option_display(resp, 'Appearance', 'Standard') - resp = resp.click('Appearance') - assert resp.forms[0]['appearance_keywords'].value == '' - resp.forms[0]['appearance_keywords'] = 'foobar' - resp = resp.forms[0].submit() - assert resp.location == 'http://example.net/backoffice/forms/1/' - resp = resp.follow() - assert_option_display(resp, 'Appearance', 'foobar') - assert FormDef.get(1).appearance_keywords == 'foobar' - - # Publication - assert_option_display(resp, 'Online Status', 'Active') - resp = resp.click('Online Status') - assert resp.forms[0]['disabled'].checked is False - resp.forms[0]['disabled'].checked = True - resp = resp.forms[0].submit() - assert resp.location == 'http://example.net/backoffice/forms/1/' - resp = resp.follow() - assert_option_display(resp, 'Online Status', 'Disabled') - assert FormDef.get(1).disabled is True - - resp = resp.click('Online Status') - assert resp.forms[0]['disabled'].checked is True - resp.forms[0]['disabled_redirection'] = 'http://www.example.net' - resp = resp.forms[0].submit() - assert resp.location == 'http://example.net/backoffice/forms/1/' - resp = resp.follow() - assert_option_display(resp, 'Online Status', 'Redirected') - assert FormDef.get(1).disabled is True - assert FormDef.get(1).disabled_redirection == 'http://www.example.net' - - resp = resp.click('Online Status') - resp.forms[0]['disabled'].checked = False - resp.forms[0]['expiration_date$date'] = '2000-01-01' # this is past(tm) - resp = resp.forms[0].submit() - assert resp.location == 'http://example.net/backoffice/forms/1/' - resp = resp.follow() - assert_option_display(resp, 'Online Status', 'Inactive by date') - - # enable geolocation - resp = resp.click('Geolocation') - resp.forms[0]['geoloc_label'] = 'Foobar' - resp = resp.forms[0].submit() - assert resp.location == 'http://example.net/backoffice/forms/1/' - resp = resp.follow() - assert_option_display(resp, 'Geolocation', 'Enabled') - assert FormDef.get(formdef.id).geolocations == {'base': 'Foobar'} - - # and disable it - resp = resp.click('Geolocation') - resp.forms[0]['geoloc_label'] = '' - resp = resp.forms[0].submit() - assert resp.location == 'http://example.net/backoffice/forms/1/' - resp = resp.follow() - assert_option_display(resp, 'Geolocation', 'Disabled') - assert FormDef.get(formdef.id).geolocations is None - - -def test_form_title_change(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - app = login(get_app(pub)) - - resp = app.get('/backoffice/forms/1/') - resp = resp.click('change title') - assert resp.form['name'].value == 'form title' - assert 'data-slug-sync' in resp.text - assert not 'change-nevertheless' 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 not 'data-slug-sync' in resp.text - assert not 'change-nevertheless' 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_forms_edit_publication_date(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/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() - - 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() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - Category.wipe() - cat = Category(name='Foo') - cat.store() - cat = Category(name='Bar') - cat.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='category') - resp = resp.forms[0].submit('cancel') - assert FormDef.get(formdef.id).category_id is None - - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='category') - resp.forms[0]['category_id'] = cat.id - resp = resp.forms[0].submit('submit') - assert FormDef.get(formdef.id).category_id == cat.id - - -def test_form_workflow(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - assert_option_display(resp, 'Workflow', 'Default') - - Workflow.wipe() - workflow = Workflow(name='Workflow One') - workflow.store() - workflow = Workflow(name='Workflow Two') - workflow.store() - - resp = app.get('/backoffice/forms/1/') - assert_option_display(resp, 'Workflow', 'Default') - - -def test_form_workflow_change(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - Workflow.wipe() - workflow = Workflow(name='Workflow One') - workflow.store() - workflow = Workflow(name='Workflow Two') - workflow.possible_status = Workflow.get_default_workflow().possible_status[:] - workflow.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='workflow', index=1) - resp = resp.forms[0].submit('cancel') - assert FormDef.get(formdef.id).workflow_id is None - - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='workflow', index=1) - assert 'Workflow One' not in resp.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 - - -def test_form_workflow_link(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - Workflow.wipe() - workflow = Workflow(name='Workflow One') - workflow.store() - - app = login(get_app(pub)) - - resp = app.get('/backoffice/forms/%s/' % formdef.id) - assert '../workflows/_default/' in resp.text - - formdef.workflow = workflow - formdef.store() - - resp = app.get('/backoffice/forms/%s/' % formdef.id) - assert '../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 '../workflows/%s/' % workflow.id not in resp.text - - -def test_form_workflow_remapping(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - data_class = formdef.data_class() - data_class.wipe() - formdata1 = data_class() - formdata1.status = 'wf-new' - formdata1.store() - - formdata2 = data_class() - formdata2.status = 'draft' - formdata2.store() - - Workflow.wipe() - workflow = Workflow(name='Workflow One') - workflow.store() - workflow = Workflow(name='Workflow Two') - # create it with a single status - workflow.possible_status = [Workflow.get_default_workflow().possible_status[-1]] - workflow.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='workflow', index=1) - resp.forms[0]['workflow_id'] = workflow.id - resp = resp.forms[0].submit('submit') - assert resp.location == 'http://example.net/backoffice/forms/1/workflow-status-remapping?new=2' - resp = resp.follow() - for status in Workflow.get_default_workflow().possible_status: - assert resp.forms[0]['mapping-%s' % status.id] - # there's only one possible new status - assert len(resp.forms[0]['mapping-%s' % status.id].options) == 1 - assert data_class.get(formdata1.id).status == 'wf-new' - assert data_class.get(formdata2.id).status == 'draft' - resp = resp.forms[0].submit() - assert data_class.get(formdata1.id).status == 'wf-finished' - assert data_class.get(formdata2.id).status == 'draft' - - # 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.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' - - -def test_form_submitter_roles(pub): - create_superuser(pub) - role = create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href=re.compile('^roles$')) - resp.form['roles$element0'] = 'logged-users' - assert not 'required_authentication_contexts' in resp.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 = Role(name='internal') - role2.internal = True - role2.store() - - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href=re.compile('^roles$')) - assert len(resp.form['roles$element0'].options) == 3 # None, Logged users, foobar - with pytest.raises(ValueError): - resp.form['roles$element0'] = str(role2.id) - - -def test_form_workflow_role(pub): - create_superuser(pub) - role = create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='role/_receiver') - resp = resp.forms[0].submit('cancel') - - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='role/_receiver') - resp.forms[0]['role_id'] = role.id - resp = resp.forms[0].submit('submit') - assert FormDef.get(1).workflow_roles == {'_receiver': '1'} - - # check it doesn't fail if a second role with the same name exists - role = Role(name='foobar') - role.store() - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='role/_receiver') - - -def test_form_workflow_options(pub): - create_superuser(pub) - create_role() - - Workflow.wipe() - workflow = Workflow(name='Workflow One') - workflow.store() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.workflow_id = workflow.id - formdef.workflow_options = {'2*1*body': 'xxx'} - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - assert '"workflow-options"' in resp.text - - -def test_form_workflow_variables(pub): - create_superuser(pub) - create_role() - - Workflow.wipe() - workflow = Workflow(name='Workflow One') - from wcs.workflows import WorkflowVariablesFieldsFormDef - workflow.variables_formdef = WorkflowVariablesFieldsFormDef(workflow=workflow) - workflow.variables_formdef.fields.append( - fields.StringField(id='1', varname='test', label='Test', type='string')) - workflow.store() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.workflow_id = workflow.id - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - assert '"workflow-variables"' in resp.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() - - Workflow.wipe() - workflow = Workflow(name='Workflow One') - from wcs.workflows import WorkflowVariablesFieldsFormDef - workflow.variables_formdef = WorkflowVariablesFieldsFormDef(workflow=workflow) - workflow.variables_formdef.fields.append( - fields.TableRowsField(id='1', varname='test', label='Test2', - type='tablerows', columns=['a'])) - workflow.variables_formdef.fields.append( - fields.StringField(id='2', varname='test2', label='Test', type='string')) - workflow.store() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.workflow_id = workflow.id - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - assert '"workflow-variables"' in resp.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_roles(pub): - create_superuser(pub) - role = create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - - resp = resp.click('User Roles') - resp = resp.forms[0].submit('cancel') - - resp = app.get('/backoffice/forms/1/') - resp = resp.click('User Roles') - resp.forms[0]['roles$element0'].value = role.id - resp = resp.forms[0].submit('submit') - assert FormDef.get(1).roles == [role.id] - - -def test_form_always_advertise(pub): - create_superuser(pub) - role = create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - - # Display to unlogged users - formdef.roles = [role.id] - formdef.store() - resp = app.get('/backoffice/forms/1/') - assert_option_display(resp, 'Display to unlogged users', 'Disabled') - resp = resp.click('Display to unlogged users') - assert resp.forms[0]['always_advertise'].checked is False - resp.forms[0]['always_advertise'].checked = True - resp = resp.forms[0].submit() - assert resp.location == 'http://example.net/backoffice/forms/1/' - resp = resp.follow() - assert_option_display(resp, 'Display to unlogged users', 'Enabled') - assert FormDef.get(1).always_advertise is True - - -def test_form_digest_template(pub): - create_superuser(pub) - role = create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [fields.StringField(id='1', varname='test', label='Test', type='string')] - formdef.store() - - formdata = formdef.data_class()() - formdata.just_created() - formdata.data = {'1': 'hello'} - formdata.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - - # Display to unlogged users - assert_option_display(resp, 'Digest Template', 'None') - resp = resp.click('Digest Template') - resp.form['digest_template'] = 'X{{form_var_test}}Y' - resp = resp.form.submit() - assert resp.location == 'http://example.net/backoffice/forms/1/' - resp = resp.follow() - assert_option_display(resp, 'Digest Template', 'Custom') - formdef = FormDef.get(formdef.id) - assert formdef.digest_template == 'X{{form_var_test}}Y' - - assert 'Existing forms will be updated in the background.' in resp.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).digest == 'XhelloY' - - -def test_form_delete(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - - resp = resp.click(href='delete') - resp = resp.forms[0].submit() - assert resp.location == 'http://example.net/backoffice/forms/' - resp = resp.follow() - assert FormDef.count() == 0 - - -def test_form_duplicate(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - - resp = resp.click(href='duplicate') - assert resp.location == 'http://example.net/backoffice/forms/2/' - resp = resp.follow() - assert FormDef.count() == 2 - assert FormDef.get(2).name == 'form title (copy)' - - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='duplicate') - assert resp.location == 'http://example.net/backoffice/forms/3/' - resp = resp.follow() - assert FormDef.count() == 3 - assert FormDef.get(3).name == 'form title (copy 2)' - - -def test_form_export(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - - resp = resp.click(href='export') - xml_export = resp.text - - fd = StringIO(xml_export) - formdef2 = FormDef.import_from_xml(fd) - assert formdef2.name == 'form title' - - -def test_form_import(pub): - user = create_superuser(pub) - role = create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - formdef_xml = ET.tostring(formdef.export_to_xml(include_id=True)) - - FormDef.wipe() - assert FormDef.count() == 0 - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/') - resp = resp.click(href='import') - resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml) - resp = resp.forms[0].submit() - assert FormDef.count() == 1 - - # import the same formdef a second time, make sure url name and internal - # identifier are not reused - resp = app.get('/backoffice/forms/') - resp = resp.click(href='import') - resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml) - resp = resp.forms[0].submit() - assert FormDef.count() == 2 - assert FormDef.get(1).url_name == 'form-title' - assert FormDef.get(2).url_name == 'form-title-1' - assert FormDef.get(1).internal_identifier == 'form-title' - assert FormDef.get(2).internal_identifier == 'form-title-1' - - # import a formdef with an url name that doesn't match its title, - # it should be kept intact. - formdef.url_name = 'xxx-other-form-title' - formdef_xml = ET.tostring(formdef.export_to_xml(include_id=True)) - - resp = app.get('/backoffice/forms/') - resp = resp.click(href='import') - resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml) - resp = resp.forms[0].submit() - assert FormDef.get(3).url_name == 'xxx-other-form-title' - assert FormDef.get(3).internal_identifier == 'form-title-2' - - # import an invalid file - resp = app.get('/backoffice/forms/') - resp = resp.click(href='import') - resp.form['file'] = Upload('formdef.wcs', 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_qrcode(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - - resp = resp.click(href='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() - - 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_new_field(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='fields/') - assert 'There are not yet any fields for this form' in resp.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 '

baz

' in resp.text - - -def test_form_delete_field(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [fields.StringField(id='1', label='1st field', type='string')] - formdef.store() - formdef.data_class().wipe() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='fields/') - assert '1st field' in resp.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() - - 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() - - 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): - user = create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [fields.StringField(id='1', label='1st field', type='string')] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='fields/') - assert '1st field' in resp.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_file_field(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='fields/') - - # add a first field - resp.forms[0]['label'] = 'foobar' - resp.forms[0]['type'] = 'file' - 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() - - 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' - resp.forms[0]['label'] = 'changed field' - resp.forms[0]['required'] = False - resp = resp.forms[0].submit('submit') - assert resp.location == 'http://example.net/backoffice/forms/1/fields/#itemId_1' - - assert FormDef.get(1).fields[0].label == 'changed field' - assert FormDef.get(1).fields[0].required == False - - -def test_form_edit_field_advanced(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [fields.StringField(id='1', label='1st field', type='string')] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='fields/') - assert '1st field' in resp.text - - resp = resp.click('Edit', href='1/') - assert resp.forms[0]['label'].value == '1st field' - assert 'Additional parameters' in resp.text - assert '>Prefill' in resp.text - # check the "prefill" field is under additional parameters - assert resp.text.index('Additional parameters') < \ - resp.text.index('>Prefill') - - # 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 'Additional parameters' in resp.text - assert '>Data Source' in resp.text - # check the "data source" field is under additional parameters - assert resp.text.index('Additional parameters') < \ - resp.text.index('>Data Source') - - # start filling the "data source" field - resp.forms[0]['data_source$type'] = 'json' - resp.forms[0]['data_source$value'] = 'http://example.net' - resp = resp.forms[0].submit('submit') - resp = resp.follow() - - # it should now appear before the additional parameters section - resp = resp.click('Edit', href='1/') - assert resp.text.index('Additional parameters') > resp.text.index('>Data Source') - - -def test_form_prefill_field(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [fields.StringField(id='1', label='1st field', type='string')] - formdef.store() - - app = login(get_app(pub)) - - resp = app.get('/backoffice/forms/1/fields/1/') - resp.form['prefill$type'] = 'String / Template' - resp.form['prefill$value_string'] = 'test' - resp = resp.form.submit('submit').follow() - assert FormDef.get(formdef.id).fields[0].prefill == {'type': 'string', 'value': 'test', '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_edit_string_field_validation(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [fields.StringField(id='1', label='1st field', type='string')] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='fields/') - assert '1st field' in resp.text - - resp = resp.click('Edit', href='1/') - resp.form['validation$type'] = 'Regular Expression' - resp.form['validation$value_regex'] = r'\d+' - resp = resp.form.submit('submit').follow() - assert FormDef.get(formdef.id).fields[0].validation == {'type': 'regex', 'value': r'\d+'} - - resp = resp.click('Edit', href='1/') - resp.form['validation$type'] = 'None' - resp = resp.form.submit('submit').follow() - assert FormDef.get(formdef.id).fields[0].validation is None - - resp = resp.click('Edit', href='1/') - resp.form['validation$type'] = 'Django Condition' - resp.form['validation$value_django'] = 'value|decimal < 20' - resp = resp.form.submit('submit').follow() - assert FormDef.get(formdef.id).fields[0].validation == {'type': 'django', 'value': 'value|decimal < 20'} - - resp = resp.click('Edit', href='1/') - resp.form['validation$type'] = 'Django Condition' - resp.form['validation$value_django'] = '{{ value|decimal < 20 }}' - resp = resp.form.submit('submit') - assert 'syntax error' in resp.text - - -def test_form_edit_item_field(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [fields.ItemField(id='1', label='1st field', type='item')] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='fields/') - assert '1st field' in resp.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 == False - assert FormDef.get(1).fields[0].items is None - - # edit and fill with one item - resp = resp.click('Edit', href='1/') - assert resp.forms[0]['label'].value == 'changed field' - resp.forms[0]['items$element0'] = 'XXX' - resp = resp.forms[0].submit('submit') - assert resp.location == 'http://example.net/backoffice/forms/1/fields/#itemId_1' - assert FormDef.get(1).fields[0].items == ['XXX'] - - -def test_form_edit_item_field_data_source(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [fields.ItemField(id='1', label='1st field', type='item')] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/fields/1/') - assert resp.form['data_source$type'].options == [ - (u'None', True, u'None'), - (u'json', False, u'JSON URL'), - (u'jsonp', False, u'JSONP URL'), - (u'geojson', False, u'GeoJSON URL'), - (u'python', False, u'Python Expression') - ] - resp = resp.form.submit('submit').follow() - - data_source = NamedDataSource(name='Foobar') - data_source.data_source = {'type': 'formula', 'value': '[]'} - data_source.store() - - resp = app.get('/backoffice/forms/1/fields/1/') - assert resp.form['data_source$type'].options == [ - (u'None', True, u'None'), - (u'foobar', False, u'Foobar'), - (u'json', False, u'JSON URL'), - (u'jsonp', False, u'JSONP URL'), - (u'geojson', False, u'GeoJSON URL'), - (u'python', False, u'Python Expression') - ] - resp.form['data_source$type'].value = 'foobar' - resp = resp.form.submit('submit').follow() - assert FormDef.get(formdef.id).fields[0].data_source == {'type': 'foobar'} - - carddef = CardDef() - carddef.name = 'Baz' - carddef.store() - - resp = app.get('/backoffice/forms/1/fields/1/') - assert resp.form['data_source$type'].options == [ - (u'None', False, u'None'), - (u'foobar', True, u'Foobar'), - (u'json', False, u'JSON URL'), - (u'jsonp', False, u'JSONP URL'), - (u'geojson', False, u'GeoJSON URL'), - (u'python', False, u'Python Expression') - ] - - carddef.digest_template = 'plop' - carddef.store() - - resp = app.get('/backoffice/forms/1/fields/1/') - assert resp.form['data_source$type'].options == [ - (u'None', False, u'None'), - (u'carddef:%s' % carddef.url_name, False, u'Baz'), - (u'foobar', True, u'Foobar'), - (u'json', False, u'JSON URL'), - (u'jsonp', False, u'JSONP URL'), - (u'geojson', False, u'GeoJSON URL'), - (u'python', False, u'Python Expression') - ] - - resp.form['data_source$type'].value = 'carddef:%s' % carddef.url_name - resp = resp.form.submit('submit').follow() - assert FormDef.get(formdef.id).fields[0].data_source == {'type': 'carddef:%s' % carddef.url_name} - - # set json source then back to none - resp = app.get('/backoffice/forms/1/fields/1/') - resp.form['data_source$type'].value = 'json' - resp.form['data_source$value'].value = 'http://whatever' - resp = resp.form.submit('submit').follow() - assert FormDef.get(formdef.id).fields[0].data_source == {'type': 'json', 'value': 'http://whatever'} - - resp = app.get('/backoffice/forms/1/fields/1/') - resp.form['data_source$type'].value = 'None' - resp = resp.form.submit('submit').follow() - resp = app.get('/backoffice/forms/1/') - - -def test_form_edit_items_field(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [fields.ItemsField(id='1', label='1st field', type='items')] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='fields/') - assert '1st field' in resp.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 == False - assert FormDef.get(1).fields[0].items is None - - # edit and fill with one item - resp = resp.click('Edit', href='1/') - assert resp.forms[0]['label'].value == 'changed field' - resp.forms[0]['items$element0'] = 'XXX' - resp = resp.forms[0].submit('submit') - assert resp.location == 'http://example.net/backoffice/forms/1/fields/#itemId_1' - assert FormDef.get(1).fields[0].items == ['XXX'] - - # check prefilling is only possible with Python - resp = resp.follow() - resp = resp.click('Edit', href='1/') - assert resp.forms[0]['prefill$type'].options == [ - (u'None', True, u'None'), (u'Python Expression', False, u'Python Expression')] - - -def test_form_edit_page_field(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='fields/') - assert 'There are not yet any fields for this form' in resp.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') - 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'}, - ] - - -def test_form_edit_comment_field(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [fields.CommentField(id='1', label='a comment field', type='comment')] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/fields/1/') - assert 'a comment field' in resp.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() - - 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() - - 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() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [fields.StringField(id='%d' % i, label='field %d' % i, type='string') - for i in range(1,10)] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='fields/') - assert 'more than 500 fields' not in resp.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/1/') - resp = resp.click(href='fields/') - assert 'more than 500 fields' not in resp.text - assert 'first field should be of type "page"' in resp.text - - formdef.fields.extend([fields.StringField(id='%d' % i, label='field %d' % i, type='string') - for i in range(10,510)]) - formdef.store() - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='fields/') - assert 'more than 500 fields' in resp.text - assert 'first field should be of type "page"' in resp.text - - FormDef.wipe() - - -def test_form_limit_display_to_page(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [fields.PageField(id='0', label='1st page', type='page'), - fields.StringField(id='1', label='string', type='string', varname='foobar'), - fields.PageField(id='2', label='2nd page', type='page'), - fields.StringField(id='3', label='string 2', type='string', varname='baz')] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/fields/') - assert '{{form_var_foobar}}' in resp.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 'Display all pages' in resp.text - assert '{{form_var_foobar}}' not in hidden_fields - assert '{{form_var_baz}}' in hidden_fields - - -def test_form_fields_reorder(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [ - fields.PageField(id='0', label='1st page', type='page'), - fields.StringField(id='1', label='string', type='string'), - 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)) - app.get('/backoffice/forms/%s/fields/update_order?order=0;3;1;2;' % formdef.id) - formdef = FormDef.get(formdef.id) - assert [x.id for x in formdef.fields] == ['0', '3', '1', '2'] - - # unknown id: ignored - app.get('/backoffice/forms/%s/fields/update_order?order=0;1;2;3;4;' % formdef.id) - formdef = FormDef.get(formdef.id) - assert [x.id for x in formdef.fields] == ['0', '1', '2', '3'] - # missing id: do nothing - app.get('/backoffice/forms/%s/fields/update_order?order=0;3;1;' % 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() - - Category.wipe() - cat = Category(name='Foo') - cat.store() - - Workflow.wipe() - workflow = Workflow(name='Workflow One') - # create it with a single status - workflow.possible_status = [Workflow.get_default_workflow().possible_status[-1]] - workflow.store() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - - role = Role(name='ZAB') # Z to get sorted last - role.store() - - # set attributes using integers - formdef.category_id = int(cat.id) - formdef.workflow_id = int(workflow.id) - formdef.workflow_roles = {'_receiver': int(role.id)} - formdef.roles = ['logged-users', int(role.id)] - - formdef.store() - - formdef = FormDef.get(formdef.id) # will run migrate - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - - resp = resp.click(href='category') - assert resp.forms[0]['category_id'].value - - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='workflow', index=1) - assert resp.forms[0]['workflow_id'].value - - resp = app.get('/backoffice/forms/1/') - resp = resp.click('User Roles') - assert resp.forms[0]['roles$element0'].value == 'logged-users' - assert resp.forms[0]['roles$element1'].value == role.id - - resp = app.get('/backoffice/forms/1/') - resp = resp.click('Recipient') - assert resp.forms[0]['role_id'].value == role.id - - -def test_form_anonymise(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - data_class = formdef.data_class() - data_class.wipe() - for i in range(10): - formdata = data_class() - formdata.just_created() - if i < 3: - formdata.status = 'wf-new' - else: - formdata.status = 'wf-rejected' - formdata.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='anonymise') - resp = resp.form.submit('cancel') - assert len([x for x in formdef.data_class().select() if x.anonymised]) == 0 - assert resp.location == 'http://example.net/backoffice/forms/1/' - - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='anonymise') - resp = resp.form.submit('submit') - assert resp.location == 'http://example.net/backoffice/forms/1/' - assert len([x for x in formdef.data_class().select() if x.anonymised]) == 0 - - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='anonymise') - resp.form['before_request_date'].value = (datetime.datetime.today() + - datetime.timedelta(days=1)).strftime('%Y-%m-%d') - resp = resp.form.submit('submit') - assert resp.location == 'http://example.net/backoffice/forms/1/' - assert len([x for x in formdef.data_class().select() if x.anonymised]) == 7 - - data_class.wipe() - for i in range(110): - formdata = data_class() - formdata.just_created() - if i < 3: - formdata.status = 'wf-rejected' - else: - formdata.status = 'wf-finished' - formdata.store() - - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='anonymise') - resp.form['before_request_date'].value = (datetime.datetime.today() + - datetime.timedelta(days=1)).strftime('%Y-%m-%d') - resp.form['endpoints$elementfinished'].checked = False - resp = resp.form.submit('submit') - assert '?job=' in resp.location - resp = resp.follow() - assert 'job-status' in resp.text - assert 'completed' in resp.text - assert len([x for x in formdef.data_class().select() if x.anonymised]) == 3 - - -def test_form_public_url(pub): - create_superuser(pub) - create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - resp = resp.click('Display public URL') - assert 'http://example.net/form-title/' in resp.text - - -def test_form_archive(pub): - create_superuser(pub) - create_role() - - if pub.is_using_postgresql(): - # this doesn't exist in SQL - pytest.skip('no archive in SQL mode') - return - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [] - formdef.store() - - data_class = formdef.data_class() - data_class.wipe() - for i in range(10): - formdata = data_class() - formdata.just_created() - if i < 3: - formdata.status = 'wf-new' - else: - formdata.status = 'wf-rejected' - formdata.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='archive') - resp = resp.form.submit('cancel') - assert data_class.count() == 10 - assert resp.location == 'http://example.net/backoffice/forms/1/' - - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='archive') - resp = resp.form.submit('submit') - assert resp.content_type == 'application/x-wcs-archive' - tf = tarfile.open(fileobj=BytesIO(resp.body)) - assert 'formdef' in [x.name for x in tf.getmembers()] - assert len(tf.getmembers()) == 8 # 7 formdata + 1 formdef - - # second archive, it shouldn't get anything (but the formdef) - resp = app.get('/backoffice/forms/1/') - resp = resp.click(href='archive') - resp = resp.form.submit('submit') - assert resp.content_type == 'application/x-wcs-archive' - tf = tarfile.open(fileobj=BytesIO(resp.body)) - assert 'formdef' in [x.name for x in tf.getmembers()] - assert len(tf.getmembers()) == 1 # 0 formdata + 1 formdef - - -def test_form_overwrite(pub): - user = create_superuser(pub) - role = create_role() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form test' - formdef.table_name = 'xxx' - formdef.fields = [fields.StringField(id='1', label='1st field', type='string'), - fields.StringField(id='2', label='2nd field', type='string')] - formdef.store() - - formdata = formdef.data_class()() - formdata.data = {'1': 'foo', '2': 'bar'} - formdata.just_created() - formdata.store() - - formdef_id = formdef.id - formdef.fields[0].label = '1st modified field' - formdef_xml = ET.tostring(formdef.export_to_xml(include_id=True)) - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/%s/' % formdef_id) - resp = resp.click(href='overwrite') - resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml) - resp = resp.forms[0].submit() - assert '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' - if pub.is_using_postgresql(): - # 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() - - 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_comment_with_error_in_wscall(http_requests, pub): - create_superuser(pub) - NamedWsCall.wipe() - - wscall = NamedWsCall(name='xxx') - wscall.description = 'description' - wscall.request = { - 'url': 'http://remote.example.net/404', - 'request_signature_key': 'xxx', - 'qs_data': {'a': 'b'}, - 'method': 'POST', - 'post_data': {'c': 'd'}, - } - wscall.store() - - FormDef.wipe() - formdef = FormDef() - formdef.name = 'form title' - formdef.fields = [fields.CommentField(id='1', - label='x [webservice.xxx.foobar] x', type='comment')] - formdef.store() - - app = login(get_app(pub)) - resp = app.get('/backoffice/forms/%s/' % formdef.id) - assert 'x [webservice.xxx.foobar] x' in resp.text - - def test_workflows(pub): create_superuser(pub) app = login(get_app(pub)) diff --git a/tests/test_forms_admin_pages.py b/tests/test_forms_admin_pages.py new file mode 100644 index 000000000..ed6a1c0f5 --- /dev/null +++ b/tests/test_forms_admin_pages.py @@ -0,0 +1,2267 @@ +# -*- coding: utf-8 -*- + +import datetime +import os +import re +import tarfile +import time +import xml.etree.ElementTree as ET + +import pytest +from webtest import Upload + +from django.utils.six import StringIO, BytesIO + +from wcs.qommon.http_request import HTTPRequest +from wcs.categories import Category +from wcs.data_sources import NamedDataSource +from wcs.wscalls import NamedWsCall +from wcs.roles import Role +from wcs.workflows import Workflow +from wcs.formdef import FormDef +from wcs.carddef import CardDef +from wcs import fields + +from utilities import get_app, login, create_temporary_pub, clean_temporary_pub + +from test_admin_pages import create_superuser, create_role + + +def pytest_generate_tests(metafunc): + if 'pub' in metafunc.fixturenames: + metafunc.parametrize('pub', ['pickle', 'sql', 'pickle-templates'], indirect=True) + + +@pytest.fixture +def pub(request): + pub = create_temporary_pub( + sql_mode=bool('sql' in request.param), + templates_mode=bool('templates' in request.param) + ) + + req = HTTPRequest(None, {'SCRIPT_NAME': '/', 'SERVER_NAME': 'example.net'}) + pub.set_app_dir(req) + pub.cfg['identification'] = {'methods': ['password']} + pub.cfg['language'] = {'language': 'en'} + pub.write_cfg() + + return pub + + +def teardown_module(module): + clean_temporary_pub() + + +def test_forms(pub): + user = create_superuser(pub) + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/') + assert 'You first have to define roles.' in resp.text + assert not 'New Form' in resp.text + + +def test_forms_new(pub): + user = create_superuser(pub) + app = login(get_app(pub)) + create_role() + + # create a new form + resp = app.get('/backoffice/forms/') + assert 'New Form' in resp.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 == True + assert formdef.last_modification_user_id == str(user.id) + + +def test_forms_new_popup(pub): + FormDef.wipe() + user = create_superuser(pub) + app = login(get_app(pub)) + create_role() + + # create a new form + resp = app.get('/backoffice/forms/') + assert 'New Form' in resp.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 == True + assert formdef.last_modification_user_id == str(user.id) + + +def assert_option_display(resp, label, value): + option_line = re.findall('%s.*%s' % (label, value), resp.text, re.DOTALL) + assert option_line + assert not '' in option_line + + +def test_forms_edit(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + + # try changing an option + + # confirmation page + assert_option_display(resp, 'Confirmation Page', 'Enabled') + resp = resp.click('Confirmation Page') + assert resp.forms[0]['confirmation'].checked + resp.forms[0]['confirmation'].checked = False + resp = resp.forms[0].submit() + assert resp.location == 'http://example.net/backoffice/forms/1/' + resp = resp.follow() + assert_option_display(resp, 'Confirmation Page', 'Disabled') + assert FormDef.get(1).confirmation == False + + # try cancel button + resp = resp.click('Confirmation Page') + assert resp.forms[0]['confirmation'].checked is False + resp.forms[0]['confirmation'].checked = True + resp = resp.forms[0].submit('cancel') + assert resp.location == 'http://example.net/backoffice/forms/1/' + resp = resp.follow() + assert_option_display(resp, 'Confirmation Page', 'Disabled') + assert FormDef.get(1).confirmation == False + + # Limit to one form + assert_option_display(resp, 'Limit to one form', 'Disabled') + resp = resp.click('Limit to one form') + assert resp.forms[0]['only_allow_one'].checked is False + resp.forms[0]['only_allow_one'].checked = True + resp = resp.forms[0].submit() + assert resp.location == 'http://example.net/backoffice/forms/1/' + resp = resp.follow() + assert_option_display(resp, 'Limit to one form', 'Enabled') + assert FormDef.get(1).only_allow_one is True + + # 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 + + # Tracking code + assert_option_display(resp, 'Tracking Code', 'Disabled') + resp = resp.click('Tracking Code') + assert resp.forms[0]['enable_tracking_codes'].checked is False + resp.forms[0]['enable_tracking_codes'].checked = True + resp = resp.forms[0].submit() + assert resp.location == 'http://example.net/backoffice/forms/1/' + resp = resp.follow() + assert_option_display(resp, 'Tracking Code', 'Enabled') + assert FormDef.get(1).enable_tracking_codes is True + + # CAPTCHA + assert_option_display(resp, 'CAPTCHA for anonymous users', 'Disabled') + resp = resp.click('CAPTCHA for anonymous users') + assert resp.forms[0]['has_captcha'].checked is False + resp.forms[0]['has_captcha'].checked = True + resp = resp.forms[0].submit() + assert resp.location == 'http://example.net/backoffice/forms/1/' + resp = resp.follow() + assert_option_display(resp, 'CAPTCHA for anonymous users', 'Enabled') + assert FormDef.get(1).has_captcha is True + + # Appearance + assert_option_display(resp, 'Appearance', 'Standard') + resp = resp.click('Appearance') + assert resp.forms[0]['appearance_keywords'].value == '' + resp.forms[0]['appearance_keywords'] = 'foobar' + resp = resp.forms[0].submit() + assert resp.location == 'http://example.net/backoffice/forms/1/' + resp = resp.follow() + assert_option_display(resp, 'Appearance', 'foobar') + assert FormDef.get(1).appearance_keywords == 'foobar' + + # Publication + assert_option_display(resp, 'Online Status', 'Active') + resp = resp.click('Online Status') + assert resp.forms[0]['disabled'].checked is False + resp.forms[0]['disabled'].checked = True + resp = resp.forms[0].submit() + assert resp.location == 'http://example.net/backoffice/forms/1/' + resp = resp.follow() + assert_option_display(resp, 'Online Status', 'Disabled') + assert FormDef.get(1).disabled is True + + resp = resp.click('Online Status') + assert resp.forms[0]['disabled'].checked is True + resp.forms[0]['disabled_redirection'] = 'http://www.example.net' + resp = resp.forms[0].submit() + assert resp.location == 'http://example.net/backoffice/forms/1/' + resp = resp.follow() + assert_option_display(resp, 'Online Status', 'Redirected') + assert FormDef.get(1).disabled is True + assert FormDef.get(1).disabled_redirection == 'http://www.example.net' + + resp = resp.click('Online Status') + resp.forms[0]['disabled'].checked = False + resp.forms[0]['expiration_date$date'] = '2000-01-01' # this is past(tm) + resp = resp.forms[0].submit() + assert resp.location == 'http://example.net/backoffice/forms/1/' + resp = resp.follow() + assert_option_display(resp, 'Online Status', 'Inactive by date') + + # enable geolocation + resp = resp.click('Geolocation') + resp.forms[0]['geoloc_label'] = 'Foobar' + resp = resp.forms[0].submit() + assert resp.location == 'http://example.net/backoffice/forms/1/' + resp = resp.follow() + assert_option_display(resp, 'Geolocation', 'Enabled') + assert FormDef.get(formdef.id).geolocations == {'base': 'Foobar'} + + # and disable it + resp = resp.click('Geolocation') + resp.forms[0]['geoloc_label'] = '' + resp = resp.forms[0].submit() + assert resp.location == 'http://example.net/backoffice/forms/1/' + resp = resp.follow() + assert_option_display(resp, 'Geolocation', 'Disabled') + assert FormDef.get(formdef.id).geolocations is None + + +def test_form_title_change(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + app = login(get_app(pub)) + + resp = app.get('/backoffice/forms/1/') + resp = resp.click('change title') + assert resp.form['name'].value == 'form title' + assert 'data-slug-sync' in resp.text + assert not 'change-nevertheless' 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 not 'data-slug-sync' in resp.text + assert not 'change-nevertheless' 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_forms_edit_publication_date(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/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() + + 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() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + Category.wipe() + cat = Category(name='Foo') + cat.store() + cat = Category(name='Bar') + cat.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='category') + resp = resp.forms[0].submit('cancel') + assert FormDef.get(formdef.id).category_id is None + + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='category') + resp.forms[0]['category_id'] = cat.id + resp = resp.forms[0].submit('submit') + assert FormDef.get(formdef.id).category_id == cat.id + + +def test_form_workflow(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + assert_option_display(resp, 'Workflow', 'Default') + + Workflow.wipe() + workflow = Workflow(name='Workflow One') + workflow.store() + workflow = Workflow(name='Workflow Two') + workflow.store() + + resp = app.get('/backoffice/forms/1/') + assert_option_display(resp, 'Workflow', 'Default') + + +def test_form_workflow_change(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + Workflow.wipe() + workflow = Workflow(name='Workflow One') + workflow.store() + workflow = Workflow(name='Workflow Two') + workflow.possible_status = Workflow.get_default_workflow().possible_status[:] + workflow.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='workflow', index=1) + resp = resp.forms[0].submit('cancel') + assert FormDef.get(formdef.id).workflow_id is None + + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='workflow', index=1) + assert 'Workflow One' not in resp.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 + + +def test_form_workflow_link(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + Workflow.wipe() + workflow = Workflow(name='Workflow One') + workflow.store() + + app = login(get_app(pub)) + + resp = app.get('/backoffice/forms/%s/' % formdef.id) + assert '../workflows/_default/' in resp.text + + formdef.workflow = workflow + formdef.store() + + resp = app.get('/backoffice/forms/%s/' % formdef.id) + assert '../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 '../workflows/%s/' % workflow.id not in resp.text + + +def test_form_workflow_remapping(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + data_class = formdef.data_class() + data_class.wipe() + formdata1 = data_class() + formdata1.status = 'wf-new' + formdata1.store() + + formdata2 = data_class() + formdata2.status = 'draft' + formdata2.store() + + Workflow.wipe() + workflow = Workflow(name='Workflow One') + workflow.store() + workflow = Workflow(name='Workflow Two') + # create it with a single status + workflow.possible_status = [Workflow.get_default_workflow().possible_status[-1]] + workflow.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='workflow', index=1) + resp.forms[0]['workflow_id'] = workflow.id + resp = resp.forms[0].submit('submit') + assert resp.location == 'http://example.net/backoffice/forms/1/workflow-status-remapping?new=2' + resp = resp.follow() + for status in Workflow.get_default_workflow().possible_status: + assert resp.forms[0]['mapping-%s' % status.id] + # there's only one possible new status + assert len(resp.forms[0]['mapping-%s' % status.id].options) == 1 + assert data_class.get(formdata1.id).status == 'wf-new' + assert data_class.get(formdata2.id).status == 'draft' + resp = resp.forms[0].submit() + assert data_class.get(formdata1.id).status == 'wf-finished' + assert data_class.get(formdata2.id).status == 'draft' + + # 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.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' + + +def test_form_submitter_roles(pub): + create_superuser(pub) + role = create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href=re.compile('^roles$')) + resp.form['roles$element0'] = 'logged-users' + assert not 'required_authentication_contexts' in resp.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 = Role(name='internal') + role2.internal = True + role2.store() + + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href=re.compile('^roles$')) + assert len(resp.form['roles$element0'].options) == 3 # None, Logged users, foobar + with pytest.raises(ValueError): + resp.form['roles$element0'] = str(role2.id) + + +def test_form_workflow_role(pub): + create_superuser(pub) + role = create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='role/_receiver') + resp = resp.forms[0].submit('cancel') + + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='role/_receiver') + resp.forms[0]['role_id'] = role.id + resp = resp.forms[0].submit('submit') + assert FormDef.get(1).workflow_roles == {'_receiver': '1'} + + # check it doesn't fail if a second role with the same name exists + role = Role(name='foobar') + role.store() + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='role/_receiver') + + +def test_form_workflow_options(pub): + create_superuser(pub) + create_role() + + Workflow.wipe() + workflow = Workflow(name='Workflow One') + workflow.store() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.workflow_id = workflow.id + formdef.workflow_options = {'2*1*body': 'xxx'} + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + assert '"workflow-options"' in resp.text + + +def test_form_workflow_variables(pub): + create_superuser(pub) + create_role() + + Workflow.wipe() + workflow = Workflow(name='Workflow One') + from wcs.workflows import WorkflowVariablesFieldsFormDef + workflow.variables_formdef = WorkflowVariablesFieldsFormDef(workflow=workflow) + workflow.variables_formdef.fields.append( + fields.StringField(id='1', varname='test', label='Test', type='string')) + workflow.store() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.workflow_id = workflow.id + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + assert '"workflow-variables"' in resp.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() + + Workflow.wipe() + workflow = Workflow(name='Workflow One') + from wcs.workflows import WorkflowVariablesFieldsFormDef + workflow.variables_formdef = WorkflowVariablesFieldsFormDef(workflow=workflow) + workflow.variables_formdef.fields.append( + fields.TableRowsField(id='1', varname='test', label='Test2', + type='tablerows', columns=['a'])) + workflow.variables_formdef.fields.append( + fields.StringField(id='2', varname='test2', label='Test', type='string')) + workflow.store() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.workflow_id = workflow.id + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + assert '"workflow-variables"' in resp.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_roles(pub): + create_superuser(pub) + role = create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + + resp = resp.click('User Roles') + resp = resp.forms[0].submit('cancel') + + resp = app.get('/backoffice/forms/1/') + resp = resp.click('User Roles') + resp.forms[0]['roles$element0'].value = role.id + resp = resp.forms[0].submit('submit') + assert FormDef.get(1).roles == [role.id] + + +def test_form_always_advertise(pub): + create_superuser(pub) + role = create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + + # Display to unlogged users + formdef.roles = [role.id] + formdef.store() + resp = app.get('/backoffice/forms/1/') + assert_option_display(resp, 'Display to unlogged users', 'Disabled') + resp = resp.click('Display to unlogged users') + assert resp.forms[0]['always_advertise'].checked is False + resp.forms[0]['always_advertise'].checked = True + resp = resp.forms[0].submit() + assert resp.location == 'http://example.net/backoffice/forms/1/' + resp = resp.follow() + assert_option_display(resp, 'Display to unlogged users', 'Enabled') + assert FormDef.get(1).always_advertise is True + + +def test_form_digest_template(pub): + create_superuser(pub) + role = create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [fields.StringField(id='1', varname='test', label='Test', type='string')] + formdef.store() + + formdata = formdef.data_class()() + formdata.just_created() + formdata.data = {'1': 'hello'} + formdata.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + + # Display to unlogged users + assert_option_display(resp, 'Digest Template', 'None') + resp = resp.click('Digest Template') + resp.form['digest_template'] = 'X{{form_var_test}}Y' + resp = resp.form.submit() + assert resp.location == 'http://example.net/backoffice/forms/1/' + resp = resp.follow() + assert_option_display(resp, 'Digest Template', 'Custom') + formdef = FormDef.get(formdef.id) + assert formdef.digest_template == 'X{{form_var_test}}Y' + + assert 'Existing forms will be updated in the background.' in resp.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).digest == 'XhelloY' + + +def test_form_delete(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + + resp = resp.click(href='delete') + resp = resp.forms[0].submit() + assert resp.location == 'http://example.net/backoffice/forms/' + resp = resp.follow() + assert FormDef.count() == 0 + + +def test_form_duplicate(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + + resp = resp.click(href='duplicate') + assert resp.location == 'http://example.net/backoffice/forms/2/' + resp = resp.follow() + assert FormDef.count() == 2 + assert FormDef.get(2).name == 'form title (copy)' + + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='duplicate') + assert resp.location == 'http://example.net/backoffice/forms/3/' + resp = resp.follow() + assert FormDef.count() == 3 + assert FormDef.get(3).name == 'form title (copy 2)' + + +def test_form_export(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + + resp = resp.click(href='export') + xml_export = resp.text + + fd = StringIO(xml_export) + formdef2 = FormDef.import_from_xml(fd) + assert formdef2.name == 'form title' + + +def test_form_import(pub): + user = create_superuser(pub) + role = create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + formdef_xml = ET.tostring(formdef.export_to_xml(include_id=True)) + + FormDef.wipe() + assert FormDef.count() == 0 + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/') + resp = resp.click(href='import') + resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml) + resp = resp.forms[0].submit() + assert FormDef.count() == 1 + + # import the same formdef a second time, make sure url name and internal + # identifier are not reused + resp = app.get('/backoffice/forms/') + resp = resp.click(href='import') + resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml) + resp = resp.forms[0].submit() + assert FormDef.count() == 2 + assert FormDef.get(1).url_name == 'form-title' + assert FormDef.get(2).url_name == 'form-title-1' + assert FormDef.get(1).internal_identifier == 'form-title' + assert FormDef.get(2).internal_identifier == 'form-title-1' + + # import a formdef with an url name that doesn't match its title, + # it should be kept intact. + formdef.url_name = 'xxx-other-form-title' + formdef_xml = ET.tostring(formdef.export_to_xml(include_id=True)) + + resp = app.get('/backoffice/forms/') + resp = resp.click(href='import') + resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml) + resp = resp.forms[0].submit() + assert FormDef.get(3).url_name == 'xxx-other-form-title' + assert FormDef.get(3).internal_identifier == 'form-title-2' + + # import an invalid file + resp = app.get('/backoffice/forms/') + resp = resp.click(href='import') + resp.form['file'] = Upload('formdef.wcs', 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_qrcode(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + + resp = resp.click(href='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() + + 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_new_field(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='fields/') + assert 'There are not yet any fields for this form' in resp.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 '

baz

' in resp.text + + +def test_form_delete_field(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [fields.StringField(id='1', label='1st field', type='string')] + formdef.store() + formdef.data_class().wipe() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='fields/') + assert '1st field' in resp.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() + + 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() + + 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): + user = create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [fields.StringField(id='1', label='1st field', type='string')] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='fields/') + assert '1st field' in resp.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_file_field(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='fields/') + + # add a first field + resp.forms[0]['label'] = 'foobar' + resp.forms[0]['type'] = 'file' + 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() + + 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' + resp.forms[0]['label'] = 'changed field' + resp.forms[0]['required'] = False + resp = resp.forms[0].submit('submit') + assert resp.location == 'http://example.net/backoffice/forms/1/fields/#itemId_1' + + assert FormDef.get(1).fields[0].label == 'changed field' + assert FormDef.get(1).fields[0].required == False + + +def test_form_edit_field_advanced(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [fields.StringField(id='1', label='1st field', type='string')] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='fields/') + assert '1st field' in resp.text + + resp = resp.click('Edit', href='1/') + assert resp.forms[0]['label'].value == '1st field' + assert 'Additional parameters' in resp.text + assert '>Prefill' in resp.text + # check the "prefill" field is under additional parameters + assert resp.text.index('Additional parameters') < \ + resp.text.index('>Prefill') + + # 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 'Additional parameters' in resp.text + assert '>Data Source' in resp.text + # check the "data source" field is under additional parameters + assert resp.text.index('Additional parameters') < \ + resp.text.index('>Data Source') + + # start filling the "data source" field + resp.forms[0]['data_source$type'] = 'json' + resp.forms[0]['data_source$value'] = 'http://example.net' + resp = resp.forms[0].submit('submit') + resp = resp.follow() + + # it should now appear before the additional parameters section + resp = resp.click('Edit', href='1/') + assert resp.text.index('Additional parameters') > resp.text.index('>Data Source') + + +def test_form_prefill_field(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [fields.StringField(id='1', label='1st field', type='string')] + formdef.store() + + app = login(get_app(pub)) + + resp = app.get('/backoffice/forms/1/fields/1/') + resp.form['prefill$type'] = 'String / Template' + resp.form['prefill$value_string'] = 'test' + resp = resp.form.submit('submit').follow() + assert FormDef.get(formdef.id).fields[0].prefill == {'type': 'string', 'value': 'test', '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_edit_string_field_validation(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [fields.StringField(id='1', label='1st field', type='string')] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='fields/') + assert '1st field' in resp.text + + resp = resp.click('Edit', href='1/') + resp.form['validation$type'] = 'Regular Expression' + resp.form['validation$value_regex'] = r'\d+' + resp = resp.form.submit('submit').follow() + assert FormDef.get(formdef.id).fields[0].validation == {'type': 'regex', 'value': r'\d+'} + + resp = resp.click('Edit', href='1/') + resp.form['validation$type'] = 'None' + resp = resp.form.submit('submit').follow() + assert FormDef.get(formdef.id).fields[0].validation is None + + resp = resp.click('Edit', href='1/') + resp.form['validation$type'] = 'Django Condition' + resp.form['validation$value_django'] = 'value|decimal < 20' + resp = resp.form.submit('submit').follow() + assert FormDef.get(formdef.id).fields[0].validation == {'type': 'django', 'value': 'value|decimal < 20'} + + resp = resp.click('Edit', href='1/') + resp.form['validation$type'] = 'Django Condition' + resp.form['validation$value_django'] = '{{ value|decimal < 20 }}' + resp = resp.form.submit('submit') + assert 'syntax error' in resp.text + + +def test_form_edit_item_field(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [fields.ItemField(id='1', label='1st field', type='item')] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='fields/') + assert '1st field' in resp.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 == False + assert FormDef.get(1).fields[0].items is None + + # edit and fill with one item + resp = resp.click('Edit', href='1/') + assert resp.forms[0]['label'].value == 'changed field' + resp.forms[0]['items$element0'] = 'XXX' + resp = resp.forms[0].submit('submit') + assert resp.location == 'http://example.net/backoffice/forms/1/fields/#itemId_1' + assert FormDef.get(1).fields[0].items == ['XXX'] + + +def test_form_edit_item_field_data_source(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [fields.ItemField(id='1', label='1st field', type='item')] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/fields/1/') + assert resp.form['data_source$type'].options == [ + (u'None', True, u'None'), + (u'json', False, u'JSON URL'), + (u'jsonp', False, u'JSONP URL'), + (u'geojson', False, u'GeoJSON URL'), + (u'python', False, u'Python Expression') + ] + resp = resp.form.submit('submit').follow() + + data_source = NamedDataSource(name='Foobar') + data_source.data_source = {'type': 'formula', 'value': '[]'} + data_source.store() + + resp = app.get('/backoffice/forms/1/fields/1/') + assert resp.form['data_source$type'].options == [ + (u'None', True, u'None'), + (u'foobar', False, u'Foobar'), + (u'json', False, u'JSON URL'), + (u'jsonp', False, u'JSONP URL'), + (u'geojson', False, u'GeoJSON URL'), + (u'python', False, u'Python Expression') + ] + resp.form['data_source$type'].value = 'foobar' + resp = resp.form.submit('submit').follow() + assert FormDef.get(formdef.id).fields[0].data_source == {'type': 'foobar'} + + carddef = CardDef() + carddef.name = 'Baz' + carddef.store() + + resp = app.get('/backoffice/forms/1/fields/1/') + assert resp.form['data_source$type'].options == [ + (u'None', False, u'None'), + (u'foobar', True, u'Foobar'), + (u'json', False, u'JSON URL'), + (u'jsonp', False, u'JSONP URL'), + (u'geojson', False, u'GeoJSON URL'), + (u'python', False, u'Python Expression') + ] + + carddef.digest_template = 'plop' + carddef.store() + + resp = app.get('/backoffice/forms/1/fields/1/') + assert resp.form['data_source$type'].options == [ + (u'None', False, u'None'), + (u'carddef:%s' % carddef.url_name, False, u'Baz'), + (u'foobar', True, u'Foobar'), + (u'json', False, u'JSON URL'), + (u'jsonp', False, u'JSONP URL'), + (u'geojson', False, u'GeoJSON URL'), + (u'python', False, u'Python Expression') + ] + + resp.form['data_source$type'].value = 'carddef:%s' % carddef.url_name + resp = resp.form.submit('submit').follow() + assert FormDef.get(formdef.id).fields[0].data_source == {'type': 'carddef:%s' % carddef.url_name} + + # set json source then back to none + resp = app.get('/backoffice/forms/1/fields/1/') + resp.form['data_source$type'].value = 'json' + resp.form['data_source$value'].value = 'http://whatever' + resp = resp.form.submit('submit').follow() + assert FormDef.get(formdef.id).fields[0].data_source == {'type': 'json', 'value': 'http://whatever'} + + resp = app.get('/backoffice/forms/1/fields/1/') + resp.form['data_source$type'].value = 'None' + resp = resp.form.submit('submit').follow() + resp = app.get('/backoffice/forms/1/') + + +def test_form_edit_items_field(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [fields.ItemsField(id='1', label='1st field', type='items')] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='fields/') + assert '1st field' in resp.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 == False + assert FormDef.get(1).fields[0].items is None + + # edit and fill with one item + resp = resp.click('Edit', href='1/') + assert resp.forms[0]['label'].value == 'changed field' + resp.forms[0]['items$element0'] = 'XXX' + resp = resp.forms[0].submit('submit') + assert resp.location == 'http://example.net/backoffice/forms/1/fields/#itemId_1' + assert FormDef.get(1).fields[0].items == ['XXX'] + + # check prefilling is only possible with Python + resp = resp.follow() + resp = resp.click('Edit', href='1/') + assert resp.forms[0]['prefill$type'].options == [ + (u'None', True, u'None'), (u'Python Expression', False, u'Python Expression')] + + +def test_form_edit_page_field(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='fields/') + assert 'There are not yet any fields for this form' in resp.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') + 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'}, + ] + + +def test_form_edit_comment_field(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [fields.CommentField(id='1', label='a comment field', type='comment')] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/fields/1/') + assert 'a comment field' in resp.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() + + 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() + + 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() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [fields.StringField(id='%d' % i, label='field %d' % i, type='string') + for i in range(1,10)] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='fields/') + assert 'more than 500 fields' not in resp.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/1/') + resp = resp.click(href='fields/') + assert 'more than 500 fields' not in resp.text + assert 'first field should be of type "page"' in resp.text + + formdef.fields.extend([fields.StringField(id='%d' % i, label='field %d' % i, type='string') + for i in range(10,510)]) + formdef.store() + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='fields/') + assert 'more than 500 fields' in resp.text + assert 'first field should be of type "page"' in resp.text + + FormDef.wipe() + + +def test_form_limit_display_to_page(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [fields.PageField(id='0', label='1st page', type='page'), + fields.StringField(id='1', label='string', type='string', varname='foobar'), + fields.PageField(id='2', label='2nd page', type='page'), + fields.StringField(id='3', label='string 2', type='string', varname='baz')] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/fields/') + assert '{{form_var_foobar}}' in resp.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 'Display all pages' in resp.text + assert '{{form_var_foobar}}' not in hidden_fields + assert '{{form_var_baz}}' in hidden_fields + + +def test_form_fields_reorder(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [ + fields.PageField(id='0', label='1st page', type='page'), + fields.StringField(id='1', label='string', type='string'), + 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)) + app.get('/backoffice/forms/%s/fields/update_order?order=0;3;1;2;' % formdef.id) + formdef = FormDef.get(formdef.id) + assert [x.id for x in formdef.fields] == ['0', '3', '1', '2'] + + # unknown id: ignored + app.get('/backoffice/forms/%s/fields/update_order?order=0;1;2;3;4;' % formdef.id) + formdef = FormDef.get(formdef.id) + assert [x.id for x in formdef.fields] == ['0', '1', '2', '3'] + # missing id: do nothing + app.get('/backoffice/forms/%s/fields/update_order?order=0;3;1;' % 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() + + Category.wipe() + cat = Category(name='Foo') + cat.store() + + Workflow.wipe() + workflow = Workflow(name='Workflow One') + # create it with a single status + workflow.possible_status = [Workflow.get_default_workflow().possible_status[-1]] + workflow.store() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + + role = Role(name='ZAB') # Z to get sorted last + role.store() + + # set attributes using integers + formdef.category_id = int(cat.id) + formdef.workflow_id = int(workflow.id) + formdef.workflow_roles = {'_receiver': int(role.id)} + formdef.roles = ['logged-users', int(role.id)] + + formdef.store() + + formdef = FormDef.get(formdef.id) # will run migrate + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + + resp = resp.click(href='category') + assert resp.forms[0]['category_id'].value + + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='workflow', index=1) + assert resp.forms[0]['workflow_id'].value + + resp = app.get('/backoffice/forms/1/') + resp = resp.click('User Roles') + assert resp.forms[0]['roles$element0'].value == 'logged-users' + assert resp.forms[0]['roles$element1'].value == role.id + + resp = app.get('/backoffice/forms/1/') + resp = resp.click('Recipient') + assert resp.forms[0]['role_id'].value == role.id + + +def test_form_anonymise(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + data_class = formdef.data_class() + data_class.wipe() + for i in range(10): + formdata = data_class() + formdata.just_created() + if i < 3: + formdata.status = 'wf-new' + else: + formdata.status = 'wf-rejected' + formdata.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='anonymise') + resp = resp.form.submit('cancel') + assert len([x for x in formdef.data_class().select() if x.anonymised]) == 0 + assert resp.location == 'http://example.net/backoffice/forms/1/' + + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='anonymise') + resp = resp.form.submit('submit') + assert resp.location == 'http://example.net/backoffice/forms/1/' + assert len([x for x in formdef.data_class().select() if x.anonymised]) == 0 + + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='anonymise') + resp.form['before_request_date'].value = (datetime.datetime.today() + + datetime.timedelta(days=1)).strftime('%Y-%m-%d') + resp = resp.form.submit('submit') + assert resp.location == 'http://example.net/backoffice/forms/1/' + assert len([x for x in formdef.data_class().select() if x.anonymised]) == 7 + + data_class.wipe() + for i in range(110): + formdata = data_class() + formdata.just_created() + if i < 3: + formdata.status = 'wf-rejected' + else: + formdata.status = 'wf-finished' + formdata.store() + + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='anonymise') + resp.form['before_request_date'].value = (datetime.datetime.today() + + datetime.timedelta(days=1)).strftime('%Y-%m-%d') + resp.form['endpoints$elementfinished'].checked = False + resp = resp.form.submit('submit') + assert '?job=' in resp.location + resp = resp.follow() + assert 'job-status' in resp.text + assert 'completed' in resp.text + assert len([x for x in formdef.data_class().select() if x.anonymised]) == 3 + + +def test_form_public_url(pub): + create_superuser(pub) + create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + resp = resp.click('Display public URL') + assert 'http://example.net/form-title/' in resp.text + + +def test_form_archive(pub): + create_superuser(pub) + create_role() + + if pub.is_using_postgresql(): + # this doesn't exist in SQL + pytest.skip('no archive in SQL mode') + return + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [] + formdef.store() + + data_class = formdef.data_class() + data_class.wipe() + for i in range(10): + formdata = data_class() + formdata.just_created() + if i < 3: + formdata.status = 'wf-new' + else: + formdata.status = 'wf-rejected' + formdata.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='archive') + resp = resp.form.submit('cancel') + assert data_class.count() == 10 + assert resp.location == 'http://example.net/backoffice/forms/1/' + + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='archive') + resp = resp.form.submit('submit') + assert resp.content_type == 'application/x-wcs-archive' + tf = tarfile.open(fileobj=BytesIO(resp.body)) + assert 'formdef' in [x.name for x in tf.getmembers()] + assert len(tf.getmembers()) == 8 # 7 formdata + 1 formdef + + # second archive, it shouldn't get anything (but the formdef) + resp = app.get('/backoffice/forms/1/') + resp = resp.click(href='archive') + resp = resp.form.submit('submit') + assert resp.content_type == 'application/x-wcs-archive' + tf = tarfile.open(fileobj=BytesIO(resp.body)) + assert 'formdef' in [x.name for x in tf.getmembers()] + assert len(tf.getmembers()) == 1 # 0 formdata + 1 formdef + + +def test_form_overwrite(pub): + user = create_superuser(pub) + role = create_role() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form test' + formdef.table_name = 'xxx' + formdef.fields = [fields.StringField(id='1', label='1st field', type='string'), + fields.StringField(id='2', label='2nd field', type='string')] + formdef.store() + + formdata = formdef.data_class()() + formdata.data = {'1': 'foo', '2': 'bar'} + formdata.just_created() + formdata.store() + + formdef_id = formdef.id + formdef.fields[0].label = '1st modified field' + formdef_xml = ET.tostring(formdef.export_to_xml(include_id=True)) + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/%s/' % formdef_id) + resp = resp.click(href='overwrite') + resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml) + resp = resp.forms[0].submit() + assert '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' + if pub.is_using_postgresql(): + # 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() + + 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_comment_with_error_in_wscall(http_requests, pub): + create_superuser(pub) + NamedWsCall.wipe() + + wscall = NamedWsCall(name='xxx') + wscall.description = 'description' + wscall.request = { + 'url': 'http://remote.example.net/404', + 'request_signature_key': 'xxx', + 'qs_data': {'a': 'b'}, + 'method': 'POST', + 'post_data': {'c': 'd'}, + } + wscall.store() + + FormDef.wipe() + formdef = FormDef() + formdef.name = 'form title' + formdef.fields = [fields.CommentField(id='1', + label='x [webservice.xxx.foobar] x', type='comment')] + formdef.store() + + app = login(get_app(pub)) + resp = app.get('/backoffice/forms/%s/' % formdef.id) + assert 'x [webservice.xxx.foobar] x' in resp.text