wcs/tests/admin_pages/test_settings.py

907 lines
33 KiB
Python

import io
import os
import urllib.parse
import zipfile
try:
import lasso # pylint: disable=unused-import
except ImportError:
lasso = None
from unittest import mock
import pytest
from quixote.http_request import Upload as QuixoteUpload
from webtest import Upload
from wcs import fields
from wcs.api_access import ApiAccess
from wcs.carddef import CardDef
from wcs.categories import CardDefCategory, Category, WorkflowCategory
from wcs.data_sources import NamedDataSource
from wcs.formdef import FormDef
from wcs.qommon.form import UploadedFile
from wcs.qommon.http_request import HTTPRequest
from wcs.qommon.template import get_current_theme
from wcs.wf.export_to_model import ExportToModel
from wcs.workflows import Workflow
from wcs.wscalls import NamedWsCall
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app, login
from .test_all import create_superuser
@pytest.fixture
def pub():
pub = create_temporary_pub()
req = HTTPRequest(None, {'SCRIPT_NAME': '/', 'SERVER_NAME': 'example.net'})
pub.set_app_dir(req)
pub.cfg['identification'] = {'methods': ['password']}
pub.cfg['language'] = {'language': 'en'}
pub.write_cfg()
return pub
def teardown_module(module):
clean_temporary_pub()
def test_settings(pub):
create_superuser(pub)
app = login(get_app(pub))
app.get('/backoffice/settings/')
app.get('/backoffice/settings/debug_options')
app.get('/backoffice/settings/language')
app.get('/backoffice/settings/import')
app.get('/backoffice/settings/export')
app.get('/backoffice/settings/identification')
app.get('/backoffice/settings/sitename')
app.get('/backoffice/settings/sms')
app.get('/backoffice/settings/admin-permissions')
def test_settings_disabled_screens(pub):
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/settings/')
assert 'Identification' in resp.text
assert 'Theme' in resp.text
if not pub.site_options.has_section('options'):
pub.site_options.add_section('options')
pub.site_options.set('options', 'settings-disabled-screens', 'identification, theme')
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
pub.site_options.write(fd)
resp = app.get('/backoffice/settings/')
assert 'Identification' not in resp.text
assert 'Theme' not in resp.text
def test_settings_export_import(pub):
def wipe():
FormDef.wipe()
CardDef.wipe()
Workflow.wipe()
pub.role_class.wipe()
Category.wipe()
CardDefCategory.wipe()
WorkflowCategory.wipe()
NamedDataSource.wipe()
NamedWsCall.wipe()
ApiAccess.wipe()
wipe()
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/settings/export')
resp = resp.form.submit('cancel')
resp = app.get('/backoffice/settings/export')
resp = resp.form.submit('submit')
assert resp.location.startswith('http://example.net/backoffice/processing?job=')
job_id = urllib.parse.parse_qs(urllib.parse.urlparse(resp.location).query)['job'][0]
resp = resp.follow()
assert 'completed' in resp.text
resp = resp.click('Download Export')
zip_content = io.BytesIO(resp.body)
with zipfile.ZipFile(zip_content, 'a') as zipf:
filelist = zipf.namelist()
assert len(filelist) == 0
# check afterjob ajax call
status_resp = app.get('/afterjobs/' + job_id)
assert status_resp.text == 'completed|completed'
formdef = FormDef()
formdef.name = 'foo'
formdef.store()
carddef = CardDef()
carddef.name = 'bar'
carddef.store()
Category(name='baz').store()
Category(name='baz2').store()
CardDefCategory(name='foobar').store()
WorkflowCategory(name='foobaz').store()
pub.role_class(name='qux').store()
NamedDataSource(name='quux').store()
ds = NamedDataSource(name='agenda')
ds.external = 'agenda'
ds.store()
NamedWsCall(name='corge').store()
wf = Workflow(name='bar')
st1 = wf.add_status('Status1', 'st1')
export_to = ExportToModel()
export_to.label = 'test'
upload = QuixoteUpload('/foo/bar', content_type='application/vnd.oasis.opendocument.text')
file_content = b'''PK\x03\x04\x14\x00\x00\x08\x00\x00\'l\x8eG^\xc62\x0c\'\x00'''
upload.fp = io.BytesIO()
upload.fp.write(file_content)
upload.fp.seek(0)
export_to.model_file = UploadedFile('models', 'export_to_model-1.upload', upload)
st1.items.append(export_to)
export_to.parent = st1
wf.store()
api_access = ApiAccess()
api_access.name = 'Jhon'
api_access.api_identifier = 'jhon'
api_access.api_key = '1234'
api_access.store()
resp = app.get('/backoffice/settings/export')
resp = resp.form.submit('submit').follow()
resp = resp.click('Download Export')
zip_content = io.BytesIO(resp.body)
with zipfile.ZipFile(zip_content, 'a') as zipf:
filelist = zipf.namelist()
assert 'formdefs/1' not in filelist
assert 'formdefs_xml/1' in filelist
assert 'carddefs/1' not in filelist
assert 'carddefs_xml/1' in filelist
assert 'workflows/1' not in filelist
assert 'workflows_xml/1' in filelist
assert 'models/export_to_model-1.upload' not in filelist
assert 'roles/1' not in filelist
assert 'roles_xml/1' in filelist
assert 'categories/1' in filelist
assert 'carddef_categories/1' in filelist
assert 'workflow_categories/1' in filelist
assert 'datasources/1' in filelist
assert 'datasources/2' not in filelist # agenda datasource, not exported
assert 'wscalls/corge' in filelist
assert 'apiaccess/1' in filelist
for filename in filelist:
assert '.indexes' not in filename
wipe()
assert FormDef.count() == 0
resp = app.get('/backoffice/settings/import')
assert 'This site has existing' not in resp.text
resp = resp.form.submit('cancel')
resp = app.get('/backoffice/settings/import')
resp.form['file'] = Upload('export.wcs', b'invalid content')
resp = resp.form.submit('submit')
assert 'Error: Not a valid export file' in resp.text
resp = app.get('/backoffice/settings/import')
resp.form['file'] = Upload('export.wcs', zip_content.getvalue())
resp = resp.form.submit('submit')
assert 'Imported successfully' in resp.text
assert '1 form' in resp.text
assert '1 card' in resp.text
assert '2 categories' in resp.text
assert '1 card category' in resp.text
assert '1 workflow category' in resp.text
assert FormDef.count() == 1
assert FormDef.select()[0].url_name == 'foo'
assert CardDef.count() == 1
assert CardDef.select()[0].url_name == 'bar'
assert ApiAccess.count() == 1
assert pub.role_class.count() == 1
# check roles are found by name
wipe()
role = pub.role_class(name='qux')
role.store()
workflow = Workflow(name='Workflow One')
st1 = workflow.add_status(name='st1')
commentable = st1.add_action('commentable', id='_commentable')
commentable.by = [role.id]
commentable.label = 'foobar'
workflow.store()
formdef = FormDef()
formdef.name = 'foo'
formdef.workflow_id = workflow.id
formdef.roles = [role.id]
formdef.backoffice_submission_roles = [role.id]
formdef.workflow_roles = {'_receiver': role.id}
formdef.fields = [fields.StringField(id='1', type='string', data_source={'type': 'carddef:unknown'})]
formdef.store()
resp = app.get('/backoffice/settings/export')
resp.form['formdefs'] = True
resp.form['workflows'] = True
resp.form['roles'] = False
resp.form['categories'] = False
resp.form['datasources'] = False
resp.form['wscalls'] = False
resp = resp.form.submit('submit').follow()
resp = resp.click('Download Export')
zip_content = io.BytesIO(resp.body)
with zipfile.ZipFile(zip_content, 'a') as zipf:
filelist = zipf.namelist()
assert 'formdefs_xml/%s' % formdef.id in filelist
assert 'workflows_xml/%s' % workflow.id in filelist
assert 'roles_xml/%s' % role.id not in filelist
FormDef.wipe()
Workflow.wipe()
pub.role_class.wipe()
# create role beforehand, it should be matched by name
role = pub.role_class(name='qux')
role.id = '012345'
role.store()
resp = app.get('/backoffice/settings/import')
resp.form['file'] = Upload('export.wcs', zip_content.getvalue())
resp = resp.form.submit('submit')
assert FormDef.select()[0].roles == ['012345']
assert FormDef.select()[0].backoffice_submission_roles == ['012345']
assert FormDef.select()[0].workflow_roles == {'_receiver': '012345'}
assert len(FormDef.select()[0].fields) == 1
assert Workflow.select()[0].possible_status[0].items[0].by == ['012345']
# do not export roles when managed by idp
pub.cfg['sp'] = {'idp-manage-roles': True}
pub.write_cfg()
resp = app.get('/backoffice/settings/export')
resp = resp.form.submit('submit').follow()
resp = resp.click('Download Export')
zip_content = io.BytesIO(resp.body)
with zipfile.ZipFile(zip_content, 'a') as zipf:
filelist = zipf.namelist()
assert len([x for x in filelist if 'roles_xml/' in x]) == 0
# check a warning is displayed if there's some content already
resp = app.get('/backoffice/settings/import')
assert 'This site has existing' in resp.text
# check an error is displayed if such an import is then used and roles are
# missing.
FormDef.wipe()
Workflow.wipe()
pub.role_class.wipe()
resp = app.get('/backoffice/settings/import')
resp.form['file'] = Upload('export.wcs', zip_content.getvalue())
resp = resp.form.submit('submit')
assert 'Unknown referenced objects [Unknown roles: qux]' in resp
# unknown field block
Workflow.wipe()
formdef = FormDef()
formdef.name = 'foo'
formdef.fields = [fields.BlockField(id='1', type='block:unknown')]
formdef.store()
resp = app.get('/backoffice/settings/export')
resp = resp.form.submit('submit').follow()
resp = resp.click('Download Export')
zip_content = io.BytesIO(resp.body)
resp = app.get('/backoffice/settings/import')
resp.form['file'] = Upload('export.wcs', zip_content.getvalue())
resp = resp.form.submit('submit')
assert 'Unknown referenced objects [Unknown fields blocks: unknown]' in resp
def test_settings_themes(pub):
create_superuser(pub)
app = login(get_app(pub))
# create mock theme
os.mkdir(os.path.join(pub.app_dir, 'themes'))
os.mkdir(os.path.join(pub.app_dir, 'themes', 'test'))
with open(os.path.join(pub.app_dir, 'themes', 'test', 'desc.xml'), 'w') as fd:
fd.write(
'<?xml version="1.0"?>'
'<theme name="test" version="1.0">'
' <label>Test Theme</label>'
'</theme>'
)
resp = app.get('/backoffice/settings/themes')
assert 'biglist themes' in resp.text
assert 'Test Theme (1.0)' in resp.text
# just for the kick, there's no support for uploading file in webtest 1.3
resp = app.get('/backoffice/settings/themes')
resp.click('Install New Theme')
# select the theme
resp = app.get('/backoffice/settings/themes')
resp.forms[0]['theme'].value = 'test'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/settings/'
resp = app.get('/backoffice/settings/themes')
assert 'checked' in resp.text
assert get_current_theme()['name'] == 'test'
def test_settings_template(pub):
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/settings/template')
# change template
orig_value = resp.forms[0]['template'].value
assert 'foobar' not in orig_value
resp.forms[0]['template'] = orig_value + '<!-- foobar -->'
resp = resp.forms[0].submit('submit')
# restore default template
resp = app.get('/backoffice/settings/template')
assert 'foobar' in resp.forms[0]['template'].value
resp = resp.forms[0].submit('restore-default')
# check
resp = app.get('/backoffice/settings/template')
assert resp.forms[0]['template'].value == orig_value
def test_settings_user(pub):
user = create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/settings/users').follow().follow()
# add a field
resp.forms[3]['label'] = 'foobar'
resp = resp.forms[3].submit()
assert resp.location == 'http://example.net/backoffice/settings/users/fields/'
resp = resp.follow()
assert b'foobar' in pub.cfg['users']['formdef']
assert 'foobar' in resp.text
# set field as email
resp.forms['mapping']['field_email'] = '1'
resp = resp.forms['mapping'].submit()
assert resp.location == 'http://example.net/backoffice/settings/users/fields/'
resp = resp.follow()
assert pub.cfg['users']['field_email'] == '1'
# and unset it
resp.forms['mapping']['field_email'] = ''
resp = resp.forms['mapping'].submit()
assert resp.location == 'http://example.net/backoffice/settings/users/fields/'
resp = resp.follow()
assert pub.cfg['users']['field_email'] is None
# add a comment field
resp.forms[3]['label'] = 'barfoo'
resp.forms[3]['type'] = 'comment'
resp = resp.forms[3].submit()
assert resp.location == 'http://example.net/backoffice/settings/users/fields/'
resp = resp.follow()
assert b'barfoo' in pub.cfg['users']['formdef']
assert 'barfoo' in resp.text
# check fields are present in edit form
resp = app.get('/backoffice/users/%s/edit' % user.id)
assert 'barfoo' in resp.text
assert 'f1' in resp.form.fields
assert 'email' in resp.form.fields
# check the email field is not displayed if it's overridden by a custom
# field.
pub.cfg['users']['field_email'] = '1'
pub.write_cfg()
resp = app.get('/backoffice/users/%s/edit' % user.id)
assert 'f1' in resp.form.fields
assert 'email' not in resp.form.fields
# set a sidebar template
app = login(get_app(pub))
resp = app.get('/backoffice/settings/users').follow().follow()
resp.forms['template']['sidebar_template'] = 'hello {{ form_user_display_name }}'
resp = resp.forms['template'].submit().follow()
assert pub.cfg['users']['sidebar_template'] == 'hello {{ form_user_display_name }}'
resp.forms['template']['sidebar_template'] = '{% if True %}'
resp = resp.forms['template'].submit().follow()
assert pub.cfg['users']['sidebar_template'] == 'hello {{ form_user_display_name }}'
assert 'syntax error in Django template' in resp
# set a search result template
resp = app.get('/backoffice/settings/users/fields/')
assert 'search_result_template' not in pub.cfg['users']
assert resp.forms['search_result_template']['search_result_template'].value.replace('\n', '') == (
'{{ user_email|default:"" }}'
'{% if user_var_phone %} 📞 {{ user_var_phone }}{% endif %}'
'{% if user_var_mobile %} 📱 {{ user_var_mobile }}{% endif %}'
'{% if user_var_address or user_var_zipcode or user_var_city %} 📨{% endif %}'
'{% if user_var_address %} {{ user_var_address }}{% endif %}'
'{% if user_var_zipcode %} {{ user_var_zipcode }}{% endif %}'
'{% if user_var_city %} {{ user_var_city }}{% endif %}'
)
resp.forms['search_result_template']['search_result_template'] = '{{ user_email|default:"" }} Foo Bar'
resp = resp.forms['search_result_template'].submit().follow()
assert pub.cfg['users']['search_result_template'] == '{{ user_email|default:"" }} Foo Bar'
# disable users screen
if not pub.site_options.has_section('options'):
pub.site_options.add_section('options')
pub.site_options.set('options', 'settings-disabled-screens', 'users')
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd:
pub.site_options.write(fd)
resp = app.get('/backoffice/settings/')
resp = resp.click('Users', href='user-templates')
resp.forms['template']['sidebar_template'] = '{% if True %}'
resp = resp.forms['template'].submit()
assert 'syntax error in Django template' in resp
resp.forms['template']['sidebar_template'] = 'hello {{ form_user_display_name }}'
resp.forms['template']['search_result_template'] = '{{ form_user_display_name }}'
resp = resp.forms['template'].submit()
assert pub.cfg['users']['sidebar_template'] == 'hello {{ form_user_display_name }}'
assert pub.cfg['users']['search_result_template'] == '{{ form_user_display_name }}'
# restore config
pub.cfg['users']['field_email'] = None
pub.write_cfg()
def test_settings_emails(pub):
create_superuser(pub)
app = login(get_app(pub))
pub.cfg['debug'] = {'mail_redirection': 'foo@example.net'}
pub.write_cfg()
resp = app.get('/backoffice/settings/emails/')
resp = resp.click('General Options')
assert 'Warning: all emails are sent to &lt;foo@example.net&gt;' in resp.text
resp.form['from'] = 'test@localhost'
resp = resp.form.submit('submit')
pub.reload_cfg()
assert pub.cfg['emails']['from'] == 'test@localhost'
assert pub.cfg['emails']['well_known_domains']
assert pub.cfg['emails']['valid_known_domains']
pub.cfg['debug'] = {}
pub.write_cfg()
resp = app.get('/backoffice/settings/emails/')
resp = resp.click('General Options')
assert 'Warning: all emails are sent to &lt;foo@example.net&gt;' not in resp.text
resp = app.get('/backoffice/settings/emails/')
resp = resp.click('Approval of new account')
resp.forms[0]['email-new-account-approved_subject'] = 'bla'
resp.forms[0]['email-new-account-approved'] = 'bla bla bla'
resp = resp.forms[0].submit()
assert pub.cfg['emails']['email-new-account-approved_subject'] == 'bla'
assert pub.cfg['emails']['email-new-account-approved'] == 'bla bla bla'
# reset to default value
resp = app.get('/backoffice/settings/emails/')
resp = resp.click('Approval of new account')
resp.forms[0]['email-new-account-approved_subject'] = 'Your account has been approved'
resp = resp.forms[0].submit()
assert pub.cfg['emails']['email-new-account-approved_subject'] is None
# disable password authentication method
pub.cfg['identification'] = {'methods': []}
pub.write_cfg()
resp = app.get('/backoffice/settings/emails/')
assert 'Approval of new account' not in resp.text
def test_settings_texts(pub):
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/settings/texts/')
resp = resp.click('Text on top of the login page')
resp.forms[0]['text-top-of-login'] = 'Hello world'
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/backoffice/settings/texts/'
assert pub.cfg['texts']['text-top-of-login'] == 'Hello world'
resp = app.get('/backoffice/settings/texts/')
resp = resp.click('Text on top of the login page')
resp = resp.forms[0].submit('restore-default')
assert resp.location == 'http://example.net/backoffice/settings/texts/'
assert pub.cfg['texts']['text-top-of-login'] is None
# disable password authentication method
pub.cfg['identification'] = {'methods': []}
pub.write_cfg()
resp = app.get('/backoffice/settings/texts/')
assert 'Text on top of the login page' not in resp.text
@pytest.mark.skipif('lasso is None')
def test_settings_auth(pub):
pub.user_class.wipe() # makes sure there are no users
pub.cfg['identification'] = {}
pub.write_cfg()
app = get_app(pub)
resp = app.get('/backoffice/settings/')
assert 'identification/password/' not in resp.text
assert 'identification/idp/' not in resp.text
resp = resp.click('Identification')
assert resp.forms[0]['methods$elementidp'].checked is False
assert resp.forms[0]['methods$elementpassword'].checked is False
resp.forms[0]['methods$elementidp'].checked = True
resp = resp.forms[0].submit()
resp = resp.follow()
assert 'identification/idp/' in resp.text
assert pub.cfg['identification']['methods'] == ['idp']
resp = resp.click('Identification')
assert resp.forms[0]['methods$elementidp'].checked is True
assert resp.forms[0]['methods$elementpassword'].checked is False
resp.forms[0]['methods$elementidp'].checked = False
resp.forms[0]['methods$elementpassword'].checked = True
resp = resp.forms[0].submit()
resp = resp.follow()
assert 'identification/password/' in resp.text
assert pub.cfg['identification']['methods'] == ['password']
@pytest.mark.skipif('lasso is None')
def test_settings_idp(pub):
# create admin session
create_superuser(pub)
app = login(get_app(pub))
pub.cfg['identification'] = {'methods': ['idp']}
pub.write_cfg()
app.get('/saml/metadata', status=404)
resp = app.get('/backoffice/settings/')
resp = resp.click(href='identification/idp/')
resp = resp.click('Service Provider')
resp = resp.form.submit('generate_rsa').follow()
resp = resp.form.submit('submit')
resp = resp.follow()
resp2 = resp.click('Identities')
resp2 = resp2.form.submit('cancel').follow()
resp2 = resp.click('Identities')
resp2 = resp2.form.submit('submit')
resp_metadata = app.get('/saml/metadata', status=200)
assert resp_metadata.text.startswith('<?xml')
resp2 = resp.click('Identity Providers')
resp2 = resp2.click('New')
idp_metadata_filename = os.path.join(os.path.dirname(__file__), '..', 'idp_metadata.xml')
with open(idp_metadata_filename, 'rb') as fd:
resp2.form['metadata'] = Upload('idp_metadata.xml', fd.read())
resp2 = resp2.form.submit('submit')
resp = resp.click('Identity Providers')
assert 'http://authentic.example.net/' in resp.text
resp2 = resp.click(href='http-authentic.example.net-idp-saml2-metadata/', index=0)
assert 'ns0:EntityDescriptor' in resp2.text
resp = resp.click(href='http-authentic.example.net-idp-saml2-metadata/edit')
resp = resp.forms[0].submit('submit')
resp = resp.follow()
# test that login initiates a SSO
login_resp = app.get('/login/', status=302)
assert login_resp.location.startswith('http://authentic.example.net/idp/saml2/sso?SAMLRequest')
resp = resp.click(href='/backoffice/settings/identification/idp/idp/', index=0) # breadcrumb
resp = resp.click(href='http-authentic.example.net-idp-saml2-metadata/delete')
resp = resp.forms[0].submit() # confirm delete
assert len(pub.cfg['idp']) == 0
with mock.patch('wcs.qommon.misc.urlopen') as urlopen:
idp_metadata_filename = os.path.join(os.path.dirname(__file__), '..', 'idp_metadata.xml')
# pylint: disable=consider-using-with
urlopen.side_effect = lambda *args: open(idp_metadata_filename, 'rb')
resp = app.get('/backoffice/settings/identification/idp/idp/')
resp = resp.click('Create new from remote URL')
resp.form['metadata_url'] = 'http://authentic.example.net/idp/saml2/metadata'
resp = resp.form.submit('submit')
resp = resp.follow()
assert 'http://authentic.example.net/idp/saml2/metadata' in resp.text
assert urlopen.call_count == 1
resp = resp.click('View')
resp = resp.click('Update from remote URL')
assert urlopen.call_count == 2
def test_settings_auth_password(pub):
pub.role_class.wipe()
pub.user_class.wipe() # makes sure there are no users
pub.cfg['identification'] = {'methods': ['password']}
assert pub.cfg['identification']['methods'] == ['password']
pub.write_cfg()
app = get_app(pub)
resp = app.get('/backoffice/settings/identification/password/')
resp = resp.click('Identities')
resp = resp.forms[0].submit()
resp = app.get('/backoffice/settings/identification/password/')
resp = resp.click('Passwords')
resp = resp.forms[0].submit()
def test_settings_filetypes(pub):
create_superuser(pub)
app = login(get_app(pub))
resp = app.get('/backoffice/settings/filetypes/')
assert 'There are no file type defined at the moment.' in resp.text
resp.forms[0]['label'] = 'Text files'
resp.forms[0]['mimetypes'] = '.odt'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/settings/filetypes/'
resp = resp.follow()
assert pub.cfg['filetypes'][1]['label'] == 'Text files'
resp = resp.click('Text files')
assert resp.forms[0]['mimetypes'].value == 'application/vnd.oasis.opendocument.text'
resp.forms[0]['mimetypes'] = 'application/vnd.oasis.opendocument.text, .doc, .docx, .pdf'
resp = resp.forms[0].submit('submit')
assert resp.location == 'http://example.net/backoffice/settings/filetypes/'
resp = resp.follow()
assert 'application/msword (.' in resp.text
assert 'application/pdf' in pub.cfg['filetypes'][1]['mimetypes']
resp.forms[0]['label'] = 'HTML files'
resp.forms[0]['mimetypes'] = '.html'
resp = resp.forms[0].submit('submit')
resp = resp.follow()
resp = resp.click('HTML files') # go to form
resp = resp.forms[0].submit('cancel') # and cancel
assert resp.location == 'http://example.net/backoffice/settings/filetypes/'
resp = resp.follow()
assert 'HTML files' in resp.text
resp = resp.click('HTML files') # go to form
resp = resp.forms[0].submit('delete') # and delete
assert resp.location == 'http://example.net/backoffice/settings/filetypes/'
resp = resp.follow()
assert 'HTML files' not in resp.text
resp = app.get('/backoffice/settings/filetypes/')
resp = resp.forms[0].submit('submit')
assert 'This field is required.' in resp
def test_settings_filetypes_update(pub):
create_superuser(pub)
app = login(get_app(pub))
pub.cfg['filetypes'] = {
1: {'mimetypes': ['application/pdf', 'application/msword'], 'label': 'Text files'}
}
pub.write_cfg()
resp = app.get('/backoffice/settings/filetypes/')
assert 'Text files' in resp.text
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = [
fields.FileField(
id='1',
label='1st field',
type='file',
document_type={
'id': 1,
'mimetypes': ['application/pdf', 'application/msword'],
'label': 'Text files',
},
)
]
formdef.store()
assert FormDef.get(formdef.id).fields[0].document_type == {
'id': 1,
'mimetypes': ['application/pdf', 'application/msword'],
'label': 'Text files',
}
resp = resp.click('Text files')
resp.forms[0]['mimetypes'] = 'application/vnd.oasis.opendocument.text, .doc, .docx, .pdf'
resp = resp.forms[0].submit('submit')
assert 'application/pdf' in pub.cfg['filetypes'][1]['mimetypes']
assert FormDef.get(formdef.id).fields[0].document_type == {
'id': 1,
'mimetypes': [
'application/vnd.oasis.opendocument.text',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/pdf',
],
'label': 'Text files',
}
resp = app.get('/backoffice/settings/filetypes/')
resp = resp.click('Text files')
resp.forms[0]['mimetypes'] = ''
resp = resp.forms[0].submit('submit')
assert 'This field is required.' in resp
def test_settings_geolocation(pub):
create_superuser(pub)
app = login(get_app(pub))
assert pub.get_default_zoom_level() == '13'
resp = app.get('/backoffice/settings/')
resp = resp.click('Geolocation')
resp.form['default-position$latlng'].value = '1.234;-1.234'
resp = resp.form.submit('cancel').follow()
resp = resp.click('Geolocation')
assert 'value="1.234;-1.234' not in resp.text
resp.form['default-position$latlng'].value = '1.234;-1.234'
resp = resp.form.submit().follow()
resp = resp.click('Geolocation')
assert 'value="1.234;-1.234' in resp.text
pub.reload_cfg()
assert pub.cfg['misc']['default-position'] == '1.234;-1.234'
assert pub.cfg['misc']['default-zoom-level'] == '13'
resp = resp.click('Geolocation')
resp.form['default-zoom-level'] = '16'
resp = resp.form.submit().follow()
assert pub.cfg['misc']['default-zoom-level'] == '16'
def test_settings_permissions(pub):
create_superuser(pub)
pub.role_class.wipe()
role1 = pub.role_class(name='foobar1')
role1.store()
role2 = pub.role_class(name='foobar2')
role2.store()
role3 = pub.role_class(name='foobar3')
role3.store()
app = login(get_app(pub))
resp = app.get('/backoffice/settings/admin-permissions')
# assert all first checkboxes are checked
assert resp.forms[0]['permissions$c-0-0'].checked
assert resp.forms[0]['permissions$c-1-0'].checked
assert resp.forms[0]['permissions$c-2-0'].checked
role2.allows_backoffice_access = False
role2.store()
resp = app.get('/backoffice/settings/admin-permissions')
assert resp.forms[0]['permissions$c-0-0'].checked
assert not resp.forms[0]['permissions$c-1-0'].checked
assert resp.forms[0]['permissions$c-2-0'].checked
resp.forms[0]['permissions$c-0-0'].checked = False
resp.forms[0]['permissions$c-1-0'].checked = True
resp = resp.forms[0].submit()
assert pub.role_class.get(role1.id).allows_backoffice_access is False
assert pub.role_class.get(role2.id).allows_backoffice_access is True
# give some roles access to the forms workshop (2nd checkbox) and to the
# workflows workshop (4th)
resp = app.get('/backoffice/settings/admin-permissions')
resp.forms[0]['permissions$c-1-1'].checked = True
resp.forms[0]['permissions$c-2-1'].checked = True
resp.forms[0]['permissions$c-2-3'].checked = True
resp = resp.forms[0].submit()
pub.reload_cfg()
assert set(pub.cfg['admin-permissions']['forms']) == {role2.id, role3.id}
assert set(pub.cfg['admin-permissions']['workflows']) == {role3.id}
# remove accesses
resp = app.get('/backoffice/settings/admin-permissions')
resp.forms[0]['permissions$c-1-1'].checked = False
resp.forms[0]['permissions$c-2-1'].checked = False
resp.forms[0]['permissions$c-2-3'].checked = False
resp = resp.forms[0].submit()
pub.reload_cfg()
assert pub.cfg['admin-permissions']['forms'] == []
assert pub.cfg['admin-permissions']['workflows'] == []
def test_settings_theme_preview(pub):
create_superuser(pub)
FormDef.wipe()
formdef = FormDef()
formdef.name = 'form title'
formdef.fields = []
formdef.store()
app = login(get_app(pub))
assert 'alto/wcs.css' not in app.get('/').text
resp = app.get('/backoffice/settings/themes')
assert resp.form['theme'].value in ('default', 'django')
# visit theme preview
resp = resp.click(href='theme_preview/alto/')
assert 'alto/wcs.css' in resp.text
# get into a form, making sure we are kept in theme preview
resp = resp.click('form title')
assert 'alto/wcs.css' in resp.text
# verify submits are not allowed
resp = resp.form.submit('submit')
assert "The theme preview doesn&#39;t support this." in resp.text
def test_settings_theme_download_upload(pub):
create_superuser(pub)
# download existing theme
app = login(get_app(pub))
resp = app.get('/backoffice/settings/themes')
resp = resp.click('download', index=0)
assert resp.headers['content-type'] == 'application/zip'
zip_content = io.BytesIO(resp.body)
with zipfile.ZipFile(zip_content, 'a') as zipf:
filelist = zipf.namelist()
assert 'alto/icon.png' in filelist
assert 'alto/desc.xml' in filelist
assert 'alto/template.ezt' in filelist
assert 'alto/wcs.css' in filelist
# modify it
zipf.writestr('alto/foobar.txt', 'XXX')
# upload it
resp = app.get('/backoffice/settings/themes')
resp = resp.click('Install New Theme')
resp.form['file'] = Upload('alto-modified.zip', zip_content.getvalue())
resp = resp.form.submit()
assert os.path.exists(os.path.join(pub.app_dir, 'themes/alto/foobar.txt'))
assert app.get('/themes/alto/foobar.txt').text == 'XXX'
assert 'Directory listing denied' in app.get('/themes/alto/', status=200).text
assert app.get('/themes/alto/plop', status=404)
assert app.get('/themes/alto/../', status=404)
assert app.get('/themes/xxx/../', status=404)
def test_postgresql_settings(pub):
create_superuser(pub)
database = pub.cfg['postgresql']['database']
assert pub.cfg['postgresql'].get('port') is None
app = login(get_app(pub))
resp = app.get('/backoffice/settings/postgresql')
assert resp.form['database'].value == database
assert resp.form['port'].value == ''
resp = resp.form.submit()
assert pub.cfg['postgresql']['port'] is None
pub.cfg['postgresql']['port'] = 5432
pub.write_cfg()
resp = app.get('/backoffice/settings/postgresql')
assert resp.form['port'].value == '5432'
resp = resp.form.submit()
assert pub.cfg['postgresql']['port'] == 5432
resp = app.get('/backoffice/settings/postgresql')
resp.form['port'] = ''
resp = resp.form.submit()
assert pub.cfg['postgresql']['port'] is None
pub.cfg['postgresql']['port'] = '5432' # from an old convert-to-sql (before #10170)
pub.write_cfg()
resp = app.get('/backoffice/settings/postgresql')
assert resp.form['port'].value == '5432'
resp = resp.form.submit()
assert pub.cfg['postgresql']['port'] == 5432