trivial: insure two blank lines before top functions and classes

This commit is contained in:
Frédéric Péters 2020-01-18 20:33:44 +01:00
parent 863ce36874
commit d81959f81f
141 changed files with 1413 additions and 0 deletions

View File

@ -10,6 +10,7 @@ except:
from docutils.core import publish_cmdline, Publisher
def set_io(self, source_path=None, destination_path=None):
Publisher.set_io_orig(self, source_path, destination_path='/dev/null')

View File

@ -75,6 +75,7 @@ def data_tree(destdir, sourcedir):
dirs.remove(vcs_dirname)
return r
def get_version():
'''Use the VERSION, if absent generates a version with git describe, if not
tag exists, take 0.0- and add the length of the commit log.

View File

@ -5,6 +5,7 @@ import pytest
from utilities import EmailsMocking, SMSMocking, HttpRequestsMocking
def pytest_addoption(parser):
parser.addoption('--without-postgresql-tests', action='store_true',
help='disable tests requiring postgresql')

View File

@ -31,6 +31,7 @@ from robot.libraries.BuiltIn import BuiltIn
from Selenium2Library.locators import ElementFinder as BaseElementFinder
from Selenium2Library import utils
class ElementFinder(BaseElementFinder):
def __init__(self):
BaseElementFinder.__init__(self)
@ -48,6 +49,7 @@ class ElementFinder(BaseElementFinder):
return self._find_by_xpath(browser, criteria, tag, constraints)
return []
class WcsRobotFrameworkLibrary:
def __init__(self, port=10003):
self.port = port

File diff suppressed because it is too large Load Diff

View File

@ -38,10 +38,12 @@ from wcs.qommon.errors import AccessForbiddenError
from utilities import get_app, create_temporary_pub, clean_temporary_pub
def pytest_generate_tests(metafunc):
if 'pub' in metafunc.fixturenames:
metafunc.parametrize('pub', ['pickle', 'sql'], indirect=True)
@pytest.fixture
def pub(request, emails):
pub = create_temporary_pub(sql_mode=(request.param == 'sql'))
@ -59,6 +61,7 @@ coucou = 1234
return pub
def teardown_module(module):
clean_temporary_pub()
@ -103,39 +106,48 @@ def sign_uri(uri, user=None, format='json'):
hashlib.sha256).digest()))
return urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
def test_user_page_redirect(pub):
output = get_app(pub).get('/user')
assert output.headers.get('location') == 'http://example.net/myspace/'
def test_user_page_error(pub):
# check we get json as output for errors
output = get_app(pub).get('/api/user/', status=403)
assert output.json['err_desc'] == 'no user specified'
def test_user_page_error_when_json_and_no_user(pub):
output = get_app(pub).get('/api/user/?format=json', status=403)
assert output.json['err_desc'] == 'no user specified'
def test_get_user_from_api_query_string_error_missing_orig(pub):
output = get_app(pub).get('/api/user/?format=json&signature=xxx', status=403)
assert output.json['err_desc'] == 'missing/multiple orig field'
def test_get_user_from_api_query_string_error_invalid_orig(pub):
output = get_app(pub).get('/api/user/?format=json&orig=coin&signature=xxx', status=403)
assert output.json['err_desc'] == 'invalid orig'
def test_get_user_from_api_query_string_error_missing_algo(pub):
output = get_app(pub).get('/api/user/?format=json&orig=coucou&signature=xxx', status=403)
assert output.json['err_desc'] == 'missing/multiple algo field'
def test_get_user_from_api_query_string_error_invalid_algo(pub):
output = get_app(pub).get('/api/user/?format=json&orig=coucou&signature=xxx&algo=coin', status=403)
assert output.json['err_desc'] == 'invalid algo'
def test_get_user_from_api_query_string_error_invalid_signature(pub):
output = get_app(pub).get('/api/user/?format=json&orig=coucou&signature=xxx&algo=sha1', status=403)
assert output.json['err_desc'] == 'invalid signature'
def test_get_user_from_api_query_string_error_missing_timestamp(pub):
signature = urllib.quote(
base64.b64encode(
@ -145,6 +157,7 @@ def test_get_user_from_api_query_string_error_missing_timestamp(pub):
output = get_app(pub).get('/api/user/?format=json&orig=coucou&algo=sha1&signature=%s' % signature, status=403)
assert output.json['err_desc'] == 'missing/multiple timestamp field'
def test_get_user_from_api_query_string_error_missing_email(pub):
timestamp = datetime.datetime.utcnow().isoformat()[:19] + 'Z'
query = 'format=json&orig=coucou&algo=sha1&timestamp=' + timestamp
@ -156,6 +169,7 @@ def test_get_user_from_api_query_string_error_missing_email(pub):
output = get_app(pub).get('/api/user/?%s&signature=%s' % (query, signature), status=403)
assert output.json['err_desc'] == 'no user specified'
def test_get_user_from_api_query_string_error_unknown_nameid(pub):
timestamp = datetime.datetime.utcnow().isoformat()[:19] + 'Z'
query = 'format=json&orig=coucou&algo=sha1&NameID=xxx&timestamp=' + timestamp
@ -167,6 +181,7 @@ def test_get_user_from_api_query_string_error_unknown_nameid(pub):
output = get_app(pub).get('/api/user/?%s&signature=%s' % (query, signature), status=403)
assert output.json['err_desc'] == 'unknown NameID'
def test_get_user_from_api_query_string_error_missing_email_valid_endpoint(pub):
# check it's ok to sign an URL without specifiying an user if the endpoint
# works fine without user.
@ -182,6 +197,7 @@ def test_get_user_from_api_query_string_error_missing_email_valid_endpoint(pub):
output = get_app(pub).get('/json?%s&signature=%s' % (query, signature))
assert output.json == {'err': 0, 'data': []}
def test_get_user_from_api_query_string_error_unknown_nameid_valid_endpoint(pub):
# check the categories and forms endpoints accept an unknown NameID
timestamp = datetime.datetime.utcnow().isoformat()[:19] + 'Z'
@ -196,6 +212,7 @@ def test_get_user_from_api_query_string_error_unknown_nameid_valid_endpoint(pub)
output = get_app(pub).get('/json?%s&signature=%s' % (query, signature))
assert output.json == {'err': 0, 'data': []}
def test_get_user_from_api_query_string_error_success_sha1(pub, local_user):
timestamp = datetime.datetime.utcnow().isoformat()[:19] + 'Z'
query = 'format=json&orig=coucou&algo=sha1&email=' + urllib.quote(local_user.email) + '&timestamp=' + timestamp
@ -207,6 +224,7 @@ def test_get_user_from_api_query_string_error_success_sha1(pub, local_user):
output = get_app(pub).get('/api/user/?%s&signature=%s' % (query, signature))
assert output.json['user_display_name'] == u'Jean Darmette'
def test_get_user_from_api_query_string_error_invalid_signature_algo_mismatch(pub, local_user):
timestamp = datetime.datetime.utcnow().isoformat()[:19] + 'Z'
query = 'format=json&orig=coucou&algo=sha256&email=' + urllib.quote(local_user.email) + '&timestamp=' + timestamp
@ -218,6 +236,7 @@ def test_get_user_from_api_query_string_error_invalid_signature_algo_mismatch(pu
output = get_app(pub).get('/api/user/?%s&signature=%s' % (query, signature), status=403)
assert output.json['err_desc'] == 'invalid signature'
def test_get_user_from_api_query_string_error_success_sha256(pub, local_user):
timestamp = datetime.datetime.utcnow().isoformat()[:19] + 'Z'
query = 'format=json&orig=coucou&algo=sha256&email=' + urllib.quote(local_user.email) + '&timestamp=' + timestamp
@ -229,6 +248,7 @@ def test_get_user_from_api_query_string_error_success_sha256(pub, local_user):
output = get_app(pub).get('/api/user/?%s&signature=%s' % (query, signature))
assert output.json['user_display_name'] == u'Jean Darmette'
def test_sign_url(pub, local_user):
signed_url = sign_url(
'http://example.net/api/user/?format=json&orig=coucou&email=%s' % urllib.quote(local_user.email),
@ -248,6 +268,7 @@ def test_sign_url(pub, local_user):
url = signed_url[len('http://example.net'):]
output = get_app(pub).get(url, status=403)
def test_get_user(pub, local_user):
Role.wipe()
role = Role(name='Foo bar')
@ -307,6 +328,7 @@ def test_get_user_compat_endpoint(pub, local_user):
output = get_app(pub).get(url)
assert output.json['user_display_name'] == u'Jean Darmette'
def test_formdef_list(pub):
Role.wipe()
role = Role(name='Foo bar')
@ -342,6 +364,7 @@ def test_formdef_list(pub):
assert resp1.json['err'] == 0
assert len(resp1.json['data']) == 0
def test_limited_formdef_list(pub, local_user):
Role.wipe()
role = Role(name='Foo bar')
@ -413,6 +436,7 @@ def test_limited_formdef_list(pub, local_user):
resp = get_app(pub).get('/api/formdefs/')
assert resp.json['data'][0]['required_authentication_contexts'] == ['fedict']
def test_formdef_list_redirection(pub):
FormDef.wipe()
formdef = FormDef()
@ -429,6 +453,7 @@ def test_formdef_list_redirection(pub):
assert resp1.json['data'][0]['redirection'] == True
assert 'count' not in resp1.json['data'][0]
def test_backoffice_submission_formdef_list(pub, local_user):
Role.wipe()
role = Role(name='Foo bar')
@ -493,6 +518,7 @@ def test_backoffice_submission_formdef_list(pub, local_user):
assert resp.json['err'] == 0
assert len(resp.json['data']) == 0
def test_formdef_schema(pub):
Workflow.wipe()
workflow = Workflow(name='test')
@ -601,6 +627,7 @@ def test_formdef_schema(pub):
get_app(pub).get('/api/formdefs/xxx/schema', status=404)
def test_post_invalid_json(pub, local_user):
resp = get_app(pub).post('/api/formdefs/test/submit',
params='not a json payload',
@ -609,6 +636,7 @@ def test_post_invalid_json(pub, local_user):
assert resp.json['err'] == 1
assert resp.json['err_class'] == 'Invalid request'
def test_formdef_submit(pub, local_user):
Role.wipe()
role = Role(name='test')
@ -689,6 +717,7 @@ def test_formdef_submit(pub, local_user):
data_class.wipe()
def test_formdef_submit_only_one(pub, local_user):
Role.wipe()
role = Role(name='test')
@ -726,6 +755,7 @@ def test_formdef_submit_only_one(pub, local_user):
assert data_class.get(resp.json['data']['id']).user_id == str(local_user.id)
assert data_class.count() == 2
def test_formdef_submit_with_varname(pub, local_user):
NamedDataSource.wipe()
data_source = NamedDataSource(name='foobar')
@ -920,6 +950,7 @@ def test_formdef_submit_from_wscall(pub, local_user):
new_formdata = formdef.data_class().get(resp.json['data']['id'])
assert new_formdata.data.get('5') is None
def test_categories(pub):
FormDef.wipe()
Category.wipe()
@ -962,6 +993,7 @@ def test_categories(pub):
resp = get_app(pub).get('/api/categories/')
assert resp.json['data'][0]['description'] == category.description
def test_categories_private(pub, local_user):
FormDef.wipe()
Category.wipe()
@ -1001,6 +1033,7 @@ def test_categories_private(pub, local_user):
resp = get_app(pub).get(sign_uri('http://example.net/api/categories/', local_user))
assert len(resp.json['data']) == 1
def test_categories_formdefs(pub, local_user):
FormDef.wipe()
Category.wipe()
@ -1080,6 +1113,7 @@ def test_categories_formdefs(pub, local_user):
assert resp.json['err'] == 0
assert len(resp.json['data']) == 1
def test_categories_full(pub):
test_categories(pub)
resp = get_app(pub).get('/api/categories/?full=on')
@ -1087,6 +1121,7 @@ def test_categories_full(pub):
assert resp.json['data'][0]['forms'][0]['title'] == 'test'
assert resp.json['data'][0]['forms'][1]['title'] == 'test 2'
def test_formdata(pub, local_user):
NamedDataSource.wipe()
data_source = NamedDataSource(name='foobar')
@ -1187,6 +1222,7 @@ def test_formdata(pub, local_user):
resp2 = get_app(pub).get(sign_uri('/test/%s/' % formdata.id,
user=local_user), status=403)
def test_formdata_backoffice_fields(pub, local_user):
test_formdata(pub, local_user)
workflow = Workflow.get(2)
@ -1205,6 +1241,7 @@ def test_formdata_backoffice_fields(pub, local_user):
resp = get_app(pub).get(sign_uri('/api/forms/test/%s/' % formdata.id, user=local_user))
assert resp.json['workflow']['fields']['backoffice_blah'] == 'Hello world'
def test_formdata_edit(pub, local_user):
test_formdata(pub, local_user)
formdef = FormDef.select()[0]
@ -1256,6 +1293,7 @@ def test_formdata_edit(pub, local_user):
assert formdef.data_class().select()[0].data['0'] == 'bar2@localhost'
assert formdef.data_class().select()[0].status == 'wf-rejected'
def test_formdata_with_workflow_data(pub, local_user):
Role.wipe()
role = Role(name='test')
@ -1298,6 +1336,7 @@ def test_formdata_with_workflow_data(pub, local_user):
assert base64.decodestring(force_bytes(resp.json['workflow']['data']['blah']['content'])) == b'test'
assert base64.decodestring(force_bytes(resp.json['workflow']['data']['blah2']['content'])) == b'test'
def test_user_by_nameid(pub, local_user):
resp = get_app(pub).get(sign_uri('/api/users/xyz/', user=local_user),
status=404)
@ -1306,6 +1345,7 @@ def test_user_by_nameid(pub, local_user):
resp = get_app(pub).get(sign_uri('/api/users/xyz/', user=local_user))
assert str(resp.json['id']) == str(local_user.id)
def test_user_roles(pub, local_user):
local_user.name_identifiers = ['xyz']
local_user.store()
@ -1317,6 +1357,7 @@ def test_user_roles(pub, local_user):
assert len(resp.json['user_roles']) == 1
assert resp.json['user_roles'][0]['name'] == 'Foo bar'
def test_user_forms(pub, local_user):
Workflow.wipe()
workflow = Workflow.get_default_workflow()
@ -1435,6 +1476,7 @@ def test_user_forms(pub, local_user):
assert resp2.json['data'][0] == resp.json['data'][1]
assert resp2.json['data'][1] == resp.json['data'][0]
def test_user_forms_limit_offset(pub, local_user):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
@ -1480,6 +1522,7 @@ def test_user_forms_limit_offset(pub, local_user):
assert len(resp.json['data']) == 10
assert [x['form_number_raw'] for x in resp.json['data']] == [str(x) for x in range(50, 40, -1)]
def test_user_forms_from_agent(pub, local_user):
Role.wipe()
role = Role(name='Foo bar')
@ -1532,6 +1575,7 @@ def test_user_forms_from_agent(pub, local_user):
agent_user.store()
get_app(pub).get(sign_uri('/api/users/%s/forms' % local_user.id, user=agent_user), status=403)
def test_user_drafts(pub, local_user):
FormDef.wipe()
formdef = FormDef()
@ -1716,6 +1760,7 @@ def test_api_list_formdata(pub, local_user):
get_app(pub).get(sign_uri('/api/forms/test/list?filter=all&offset=plop', user=local_user), status=400)
get_app(pub).get(sign_uri('/api/forms/test/list?filter=all&limit=plop', user=local_user), status=400)
def test_api_anonymized_formdata(pub, local_user, admin_user):
Role.wipe()
role = Role(name='test')
@ -1820,6 +1865,7 @@ def test_api_anonymized_formdata(pub, local_user, admin_user):
assert 'NameID' in resp.json['evolution'][1]['who']
assert 'name' in resp.json['evolution'][1]['who']
def test_api_geojson_formdata(pub, local_user):
Role.wipe()
role = Role(name='test')
@ -1905,6 +1951,7 @@ def test_api_geojson_formdata(pub, local_user):
formdef.store()
resp = get_app(pub).get(sign_uri('/api/forms/test/geojson', user=local_user), status=404)
def test_api_global_geojson(pub, local_user):
Role.wipe()
role = Role(name='test')
@ -1959,6 +2006,7 @@ def test_api_global_geojson(pub, local_user):
assert 'features' in resp.json
assert len(resp.json['features']) == 20
def test_api_global_listing(pub, local_user):
if not pub.is_using_postgresql():
resp = get_app(pub).get(sign_uri('/api/forms/geojson', user=local_user), status=404)
@ -2027,6 +2075,7 @@ def test_api_global_listing(pub, local_user):
get_app(pub).get(sign_uri('/api/forms/?status=done&limit=plop', user=local_user), status=400)
get_app(pub).get(sign_uri('/api/forms/?status=done&offset=plop', user=local_user), status=400)
def test_api_global_listing_ignored_roles(pub, local_user):
test_api_global_listing(pub, local_user)
@ -2148,6 +2197,7 @@ def ics_data(local_user):
formdata.jump_status('finished')
formdata.store()
def test_api_ics_formdata(pub, local_user, ics_data):
role = Role.select()[0]
@ -2203,6 +2253,7 @@ def test_api_ics_formdata(pub, local_user, ics_data):
assert resp.text.count('DTSTART') == 10
assert resp.text.count('DTEND') == 10
def test_api_ics_formdata_http_auth(pub, local_user, ics_data):
role = Role.select()[0]
@ -2233,6 +2284,7 @@ def test_api_ics_formdata_http_auth(pub, local_user, ics_data):
app.authorization = ('Basic', ('user', 'password2'))
resp = app.get('/api/forms/test/ics/foobar?email=%s' % local_user.email, status=403)
def test_roles(pub, local_user):
Role.wipe()
role = Role(name='Hello World')
@ -2257,6 +2309,7 @@ def test_roles(pub, local_user):
assert resp.json['data'][0]['emails_to_members'] == False
assert resp.json['data'][0]['details'] == 'kouign amann'
def test_users(pub, local_user):
resp = get_app(pub).get('/api/users/', status=403)
@ -2292,6 +2345,7 @@ def test_users(pub, local_user):
resp = get_app(pub).get(sign_uri('/api/users/?q=foobar'))
assert len(resp.json['data']) == 0
def test_users_unaccent(pub, local_user):
local_user.name = 'Jean Sénisme'
local_user.store()
@ -2307,6 +2361,7 @@ def test_users_unaccent(pub, local_user):
resp = get_app(pub).get(sign_uri('/api/users/?q=blah'))
assert len(resp.json['data']) == 0
def test_workflow_trigger(pub, local_user):
workflow = Workflow(name='test')
st1 = workflow.add_status('Status1', 'st1')
@ -2393,6 +2448,7 @@ def test_workflow_trigger_with_condition(pub, local_user):
resp = get_app(pub).post(sign_uri(formdata.get_url() + 'jump/trigger/XXX'))
assert resp.json == {'err': 0, 'url': None}
def test_workflow_trigger_jump_once(pub, local_user):
workflow = Workflow(name='test')
st1 = workflow.add_status('Status1', 'st1')
@ -2514,6 +2570,7 @@ def test_workflow_global_webservice_trigger(pub, local_user):
{'test': 'BAR'}, status=200)
assert formdef.data_class().get(formdata.id).workflow_data == {'plop': {'test': 'BAR'}}
def test_tracking_code(pub):
FormDef.wipe()
formdef = FormDef()
@ -2550,6 +2607,7 @@ def test_tracking_code(pub):
formdata.remove_self()
resp = get_app(pub).get(sign_url('/api/code/%s?orig=coucou' % code.id, '1234'), status=404)
def test_validate_expression(pub):
resp = get_app(pub).get('/api/validate-expression?expression=hello')
assert resp.json == {'klass': None, 'msg': ''}
@ -2570,6 +2628,7 @@ def test_validate_expression(pub):
assert resp.json['klass'] == 'error'
assert resp.json['msg'].startswith('syntax error in Django template: Could not parse the remainder')
def test_validate_condition(pub):
resp = get_app(pub).get('/api/validate-condition?type=python&value_python=hello')
assert resp.json == {'klass': None, 'msg': ''}
@ -2593,6 +2652,7 @@ def test_validate_condition(pub):
assert resp.json['klass'] == 'error'
assert resp.json['msg'] == 'unknown condition type'
@pytest.fixture(params=['sql', 'pickle'])
def no_request_pub(request):
pub = create_temporary_pub(sql_mode=bool(request.param == 'sql'))
@ -2605,11 +2665,13 @@ api.example.com = 1234
''')
return pub
def test_get_secret_and_orig(no_request_pub):
secret, orig = get_secret_and_orig('https://api.example.com/endpoint/')
assert secret == '1234'
assert orig == 'example.net'
def test_reverse_geocoding(pub):
with mock.patch('wcs.qommon.misc.urlopen') as urlopen:
urlopen.side_effect = lambda *args: StringIO(json.dumps({'address': 'xxx'}))
@ -2717,6 +2779,7 @@ def test_geocoding(pub):
resp = get_app(pub).get('/api/geocoding?q=test')
assert urlopen.call_args[0][0] == 'http://reverse.example.net/?param=value&format=json&q=test&accept-language=en'
def test_cards(pub, local_user):
Role.wipe()
role = Role(name='test')

View File

@ -24,15 +24,18 @@ def pub():
return pub
@pytest.fixture
def pub_2auth(pub):
pub.cfg['identification'] = {'methods': ['password', 'idp']}
pub.write_cfg()
return pub
def teardown_module(module):
clean_temporary_pub()
def test_login_logout(pub):
resp_initial = get_app(pub).get('/')
resp = login(get_app(pub), username='foo', password='foo').get('/')
@ -40,6 +43,7 @@ def test_login_logout(pub):
resp = resp.follow()
assert resp.text == resp_initial.text
def test_register_account(pub):
resp = get_app(pub).get('/').click('Login').follow()
assert not 'register' in resp.text
@ -54,6 +58,7 @@ def test_register_account(pub):
assert PasswordAccount.count() == 2
assert pub.user_class.count() == 2
def test_login_2auth(pub_2auth):
resp = get_app(pub_2auth).get('/').click('Login').follow()
resp.form['method'] = 'Username / password'
@ -68,6 +73,7 @@ def test_login_2auth(pub_2auth):
resp = resp.form.submit().follow()
assert 'SSO support is not yet configured' in resp.text
def test_register_2auth(pub_2auth):
pub_2auth.cfg['identities'] = {'creation': 'self'}
pub_2auth.write_cfg()

View File

@ -59,6 +59,7 @@ def pytest_generate_tests(metafunc):
if 'pub' in metafunc.fixturenames:
metafunc.parametrize('pub', ['pickle', 'sql', 'pickle-templates'], indirect=True)
@pytest.fixture
def pub(request, emails):
pub = create_temporary_pub(
@ -80,6 +81,7 @@ coucou = 1234
return pub
def create_user(pub, is_admin=False):
if pub.user_class.select(lambda x: x.name == 'admin'):
user1 = pub.user_class.select(lambda x: x.name == 'admin')[0]
@ -106,8 +108,10 @@ def create_user(pub, is_admin=False):
return user1
def create_superuser(pub): return create_user(pub, is_admin=True)
def create_environment(pub, set_receiver=True):
pub.session_manager.session_class.wipe()
Workflow.wipe()
@ -178,14 +182,17 @@ def create_environment(pub, set_receiver=True):
formdata.jump_status('new')
formdata.store()
def teardown_module(module):
clean_temporary_pub()
def test_backoffice_unlogged(pub):
create_superuser(pub)
resp = get_app(pub).get('/backoffice/', status=302)
assert resp.location == 'http://example.net/login/?next=http%3A%2F%2Fexample.net%2Fbackoffice%2F'
def test_backoffice_home(pub):
create_superuser(pub)
app = login(get_app(pub))
@ -194,6 +201,7 @@ def test_backoffice_home(pub):
assert 'Forms Workshop' in resp.text
assert 'Workflows Workshop' in resp.text
def test_backoffice_role_user(pub):
create_user(pub)
app = login(get_app(pub))
@ -224,6 +232,7 @@ def test_backoffice_role_user(pub):
assert not 'Forms Workshop' in resp.text
assert 'Workflows Workshop' in resp.text
def test_backoffice_forms(pub):
create_superuser(pub)
create_environment(pub, set_receiver=False)
@ -284,6 +293,7 @@ def test_backoffice_forms(pub):
assert 'Forms in your care' in resp.text
assert '9 open on 50' in resp.text
def test_backoffice_listing(pub):
create_superuser(pub)
create_environment(pub)
@ -383,6 +393,7 @@ def test_backoffice_listing(pub):
resp = resp.forms[0].submit()
assert resp.text.count('data-link') == 9
def test_backoffice_listing_pagination(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
@ -423,6 +434,7 @@ def test_backoffice_listing_pagination(pub):
resp = resp.follow()
assert resp.form['offset'].value == '0'
def test_backoffice_listing_order(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
@ -475,6 +487,7 @@ def test_backoffice_listing_order(pub):
ids = [x.strip('/') for x in re.findall(r'data-link="(.*?)"', resp.text)]
assert ids == list(reversed(last_update_time_order))
def test_backoffice_listing_anonymised(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
@ -493,6 +506,7 @@ def test_backoffice_listing_anonymised(pub):
resp = app.get('/backoffice/management/form-title/?limit=500')
assert resp.text.count('data-link') == 9
def test_backoffice_legacy_urls(pub):
create_superuser(pub)
create_environment(pub)
@ -507,6 +521,7 @@ def test_backoffice_legacy_urls(pub):
assert resp.location == 'http://example.net/backoffice/management/form-title/listing/foo?bla'
resp = app.get('/backoffice/not-form-title/', status=404)
def test_backoffice_columns(pub):
create_superuser(pub)
create_environment(pub)
@ -521,6 +536,7 @@ def test_backoffice_columns(pub):
assert resp.text.count('data-link') == 17 # 17 rows
assert resp.text.count('FOO BAR') == 0 # no field 1 column
def test_backoffice_channel_column(pub):
if not pub.site_options.has_section('variables'):
pub.site_options.add_section('variables')
@ -540,6 +556,7 @@ def test_backoffice_channel_column(pub):
assert resp.text.count('data-link') == 17 # 17 rows
assert resp.text.count('<td>Web</td>') == 17
def test_backoffice_submission_agent_column(pub):
user = create_user(pub)
create_environment(pub)
@ -578,6 +595,7 @@ def test_backoffice_submission_agent_column(pub):
assert len(resp.text.splitlines()) == 18 # 17 + header line
assert resp.text.count(',agent,') == 17
def test_backoffice_image_column(pub):
create_superuser(pub)
create_environment(pub)
@ -596,6 +614,7 @@ def test_backoffice_image_column(pub):
resp = app.get('/backoffice/management/form-title/')
assert 'download?f=4&thumbnail=1' not in resp.text
def test_backoffice_filter(pub):
create_superuser(pub)
create_environment(pub)
@ -639,6 +658,7 @@ def test_backoffice_filter(pub):
resp = resp.forms[0].submit()
assert resp.text.count('<td>baz</td>') == 0
def test_backoffice_default_filter(pub):
create_superuser(pub)
create_environment(pub)
@ -664,6 +684,7 @@ def test_backoffice_default_filter(pub):
resp = app.get('/backoffice/management/form-title/')
assert 'filter-4-value' in resp.form.fields
def test_backoffice_bool_filter(pub):
create_superuser(pub)
create_environment(pub)
@ -694,6 +715,7 @@ def test_backoffice_bool_filter(pub):
assert resp.text.count('<td>Yes</td>') == 0
assert resp.text.count('<td>No</td>') > 0
def test_backoffice_item_filter(pub):
create_superuser(pub)
create_environment(pub)
@ -766,6 +788,7 @@ def test_backoffice_item_filter(pub):
else:
assert [x['id'] for x in resp2.json['data']] == [u'â', u'b', u'd']
def test_backoffice_item_double_filter(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
@ -835,6 +858,7 @@ def test_backoffice_item_double_filter(pub):
assert [x[0] for x in resp.form['filter-4-value'].options] == ['', 'a', 'b']
assert [x[0] for x in resp.form['filter-5-value'].options] == ['', 'A', 'B', 'C']
def test_backoffice_bofield_item_filter(pub):
create_superuser(pub)
create_environment(pub)
@ -966,6 +990,7 @@ def test_backoffice_items_filter(pub):
assert resp.text.count(u'<td>b, d</td>') == 0
assert resp.text.count('data-link') == 0 # no rows
def test_backoffice_csv(pub):
create_superuser(pub)
create_environment(pub)
@ -1026,6 +1051,7 @@ def test_backoffice_csv(pub):
resp_csv = resp.click('Export as CSV File')
assert 'Created' not in resp_csv.text.splitlines()[0]
def test_backoffice_export_long_listings(pub):
create_superuser(pub)
create_environment(pub)
@ -1069,6 +1095,7 @@ def test_backoffice_export_long_listings(pub):
# check error handling
app.get('/afterjobs/whatever', status=404)
def test_backoffice_csv_export_channel(pub):
if not pub.site_options.has_section('variables'):
pub.site_options.add_section('variables')
@ -1091,6 +1118,7 @@ def test_backoffice_csv_export_channel(pub):
assert resp_csv.text.splitlines()[0].split(',')[1] == 'Channel'
assert resp_csv.text.splitlines()[1].split(',')[1] == 'Web'
def test_backoffice_csv_export_anonymised(pub):
fd = open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w')
pub.site_options.write(fd)
@ -1110,6 +1138,7 @@ def test_backoffice_csv_export_anonymised(pub):
assert resp_csv.text.splitlines()[0].split(',')[-1] == 'Anonymised'
assert resp_csv.text.splitlines()[1].split(',')[-1] == 'No'
def test_backoffice_ods(pub):
create_superuser(pub)
create_environment(pub)
@ -1195,6 +1224,7 @@ def test_backoffice_ods(pub):
assert row.findall('.//{%s}table-cell' % ods.NS['table'])[
string_column].find('{%s}p' % ods.NS['text']).text == 'plop\nplop'
@pytest.mark.skipif('xlwt is None')
def test_backoffice_xls(pub):
create_superuser(pub)
@ -1214,6 +1244,7 @@ def test_backoffice_xls(pub):
resp = resp.click('Excel Export')
assert resp.headers['content-type'].startswith('application/vnd.ms-excel')
def test_backoffice_statistics(pub):
create_superuser(pub)
create_environment(pub)
@ -1235,6 +1266,7 @@ def test_backoffice_statistics(pub):
assert '<h2>Filters</h2>' in resp.text
assert 'End: 2013-01-01' in resp.text
def test_backoffice_multi_actions(pub):
create_superuser(pub)
create_environment(pub)
@ -1344,6 +1376,7 @@ def test_backoffice_multi_actions(pub):
else:
assert formdata.status != 'wf-accepted'
def test_backoffice_statistics_status_filter(pub):
create_superuser(pub)
create_environment(pub)
@ -1382,6 +1415,7 @@ def test_backoffice_statistics_status_filter(pub):
resp = resp.forms[0].submit()
assert 'Total number of records: 50' in resp.text
def test_backoffice_statistics_status_select(pub):
create_superuser(pub)
create_environment(pub)
@ -1430,6 +1464,7 @@ def test_backoffice_statistics_status_select(pub):
resp = resp.click('Statistics')
assert 'filter-2-value' in resp.form.fields
def test_backoffice_map(pub):
user = create_user(pub)
create_environment(pub)
@ -1466,6 +1501,7 @@ def test_backoffice_map(pub):
resp = resp.click('Plot on a Map')
assert 'tile.example.net/' in resp.text
def test_backoffice_geojson(pub):
user = create_user(pub)
create_environment(pub)
@ -1527,6 +1563,7 @@ def test_backoffice_handling(pub):
assert FormDef.get_by_urlname('form-title').data_class().get(number31.id).status == 'wf-accepted'
assert 'HELLO WORLD' in resp.text
def test_backoffice_handling_global_action(pub):
create_user(pub)
create_environment(pub)
@ -1563,6 +1600,7 @@ def test_backoffice_handling_global_action(pub):
assert 'HELLO WORLD GLOBAL ACTION' in resp.text
assert formdef.data_class().get(formdata.id).status == 'wf-finished'
def test_backoffice_global_remove_action(pub):
create_user(pub)
create_environment(pub)
@ -1596,6 +1634,7 @@ def test_backoffice_global_remove_action(pub):
assert resp.request.url == 'http://example.net/backoffice/management/test-global-remove/'
assert 'The form has been deleted.' in resp.text
def test_backoffice_submission_context(pub):
user = create_user(pub)
create_environment(pub)
@ -1632,6 +1671,7 @@ def test_backoffice_submission_context(pub):
assert 'http://www.example.com/summary' in resp.text
assert 'by %s' % user.get_display_name() in resp.text
def test_backoffice_geolocation_info(pub):
user = create_user(pub)
create_environment(pub)
@ -1660,6 +1700,7 @@ def test_backoffice_geolocation_info(pub):
assert 'data-init-lng="2.32"' in resp.text
assert 'data-init-lat="48.83' in resp.text
def test_backoffice_info_text(pub):
create_user(pub)
create_environment(pub)
@ -1752,6 +1793,7 @@ def test_backoffice_info_text(pub):
resp = app.get('/backoffice/management/form-title/%s/' % number31.id)
assert not 'backoffice-description' in resp.text
def test_backoffice_handling_post_dispatch(pub):
# check a formdata that has been dispatched to another role is accessible
# by an user with that role.
@ -1801,6 +1843,7 @@ def test_backoffice_handling_post_dispatch(pub):
assert FormDef.get_by_urlname('form-title').data_class().get(number31.id).status == 'wf-accepted'
assert 'HELLO WORLD' in resp.text
def test_global_statisticspub(pub):
create_superuser(pub)
create_environment(pub)
@ -1814,6 +1857,7 @@ def test_global_statisticspub(pub):
resp = resp.forms[0].submit()
assert 'Total count: 20' in resp.text
def test_backoffice_submission(pub):
user = create_user(pub)
create_environment(pub)
@ -1958,6 +2002,7 @@ def test_backoffice_submission_with_tracking_code(pub):
resp = app.get(formdata_location)
assert not formdata.tracking_code in resp.text
def test_backoffice_submission_welco(pub, welco_url):
user = create_user(pub)
create_environment(pub)
@ -1992,6 +2037,7 @@ def test_backoffice_submission_welco(pub, welco_url):
# check agent name is displayed next to pending submission
assert '(%s)' % user.display_name in resp.text
def test_backoffice_submission_initiated_from_welco(pub, welco_url):
user = create_user(pub)
create_environment(pub)
@ -2046,6 +2092,7 @@ def test_backoffice_submission_initiated_from_welco(pub, welco_url):
assert pq('#steps li.current .label').text() == '1st PAGE'
assert 'Field on 1st page' in resp.text # and in fields
def test_backoffice_submission_with_return_url(pub):
user = create_user(pub)
create_environment(pub)
@ -2082,6 +2129,7 @@ def test_backoffice_submission_with_return_url(pub):
resp = resp.form.submit('submit') # -> to submit
assert resp.location == 'https://example.org'
def test_backoffice_parallel_submission(pub):
user = create_user(pub)
create_environment(pub)
@ -2152,6 +2200,7 @@ def test_backoffice_parallel_submission(pub):
resp4 = resp4.follow()
assert 'This form has already been submitted.' in resp4.text
def test_backoffice_submission_dispatch(pub):
user = create_user(pub)
create_environment(pub)
@ -2215,6 +2264,7 @@ def test_backoffice_submission_dispatch(pub):
# right role
assert resp.location.startswith('http://example.net/backoffice/management/form-title/')
def test_backoffice_submission_tracking_code(pub):
user = create_user(pub)
create_environment(pub)
@ -2254,6 +2304,7 @@ def test_backoffice_submission_tracking_code(pub):
assert 'Check values then click submit.' in resp.text
assert 'test submission' in resp.text
def test_backoffice_submission_drafts(pub):
user = create_user(pub)
create_environment(pub)
@ -2307,6 +2358,7 @@ def test_backoffice_submission_drafts(pub):
# check it kept the same id
assert resp.location == 'http://example.net/backoffice/management/form-title/%s/' % formdata_no
def test_backoffice_submission_remove_drafts(pub):
user = create_user(pub)
create_environment(pub)
@ -2363,6 +2415,7 @@ def test_backoffice_submission_remove_drafts(pub):
resp = app.get('/backoffice/submission/form-title/remove/%s' % formdata.id,
status=403)
def test_backoffice_submission_live_condition(pub):
user = create_user(pub)
create_environment(pub)
@ -2405,6 +2458,7 @@ def test_backoffice_submission_live_condition(pub):
assert '<span class="label">Bar</span>' in resp.text
assert '<span class="label">Foo</span>' not in resp.text
def test_backoffice_submission_conditional_jump_based_on_bo_field(pub):
user = create_superuser(pub)
Workflow.wipe()
@ -2468,6 +2522,7 @@ def test_backoffice_submission_conditional_jump_based_on_bo_field(pub):
assert formdef.data_class().count() == 1
assert formdef.data_class().select()[0].status == 'wf-st1'
def test_backoffice_submission_sections(pub):
user = create_user(pub)
create_environment(pub)
@ -2504,6 +2559,7 @@ def test_backoffice_submission_sections(pub):
assert 'Running submission' in resp.text
assert '>#%s' % formdata.id in resp.text
def test_backoffice_submission_prefill_user(pub):
user = create_user(pub)
create_environment(pub)
@ -2550,6 +2606,7 @@ def test_backoffice_submission_prefill_user(pub):
# and check it was not prefilled
assert resp.form['f1'].value == ''
def test_backoffice_submission_prefill_user_via_formula(pub):
user = create_user(pub)
create_environment(pub)
@ -2596,6 +2653,7 @@ def test_backoffice_submission_prefill_user_via_formula(pub):
# and check it was not prefilled
assert resp.form['f1'].value == ''
def test_backoffice_submission_prefill_user_multiple_pages(pub):
user = create_user(pub)
create_environment(pub)
@ -2685,6 +2743,7 @@ def test_backoffice_submission_prefill_user_multiple_pages(pub):
assert formdef.data_class().count() == 1
assert formdef.data_class().select()[0].user_id is None
def test_backoffice_submission_multiple_page_restore_on_validation(pub):
user = create_user(pub)
create_environment(pub)
@ -2723,6 +2782,7 @@ def test_backoffice_submission_multiple_page_restore_on_validation(pub):
resp = resp.follow()
assert 'Check values then click submit.' in resp.text
def test_backoffice_submission_substitution_vars(pub):
user = create_user(pub)
create_environment(pub)
@ -2774,6 +2834,7 @@ def test_backoffice_submission_substitution_vars(pub):
resp = resp.form.submit('submit')
assert 'dj-PLOP-an-bar-go' in resp.text
def test_backoffice_submission_manual_channel(pub):
user = create_user(pub)
create_environment(pub)
@ -2812,6 +2873,7 @@ def test_backoffice_submission_manual_channel(pub):
assert data_class.get(formdata_no).backoffice_submission is True
assert data_class.get(formdata_no).submission_channel == 'mail'
def test_backoffice_submission_no_manual_channel_with_welco(pub, welco_url):
user = create_user(pub)
create_environment(pub)
@ -2824,6 +2886,7 @@ def test_backoffice_submission_no_manual_channel_with_welco(pub, welco_url):
resp = app.get('/backoffice/submission/%s/' % formdef.url_name)
assert 'submission_channel' not in resp.form.fields
def test_backoffice_submission_with_nameid_and_channel(pub, local_user):
user = create_user(pub)
create_environment(pub)
@ -2862,6 +2925,7 @@ def test_backoffice_submission_with_nameid_and_channel(pub, local_user):
assert formdata.submission_channel == 'mail'
assert formdata.status == 'wf-new'
def test_backoffice_wscall_failure_display(http_requests, pub):
user = create_user(pub)
create_environment(pub)
@ -2912,6 +2976,7 @@ def test_backoffice_wscall_failure_display(http_requests, pub):
assert (' with the number %s.' % number31.get_display_id()) in resp.text
assert not 'Error during webservice call' in resp.text
def test_backoffice_wscall_error_email(http_requests, pub, emails):
pub.cfg['debug'] = {'error_email': 'errors@localhost.invalid'}
pub.write_cfg()
@ -2966,6 +3031,7 @@ def test_backoffice_wscall_error_email(http_requests, pub, emails):
assert '/form-title/%s/' % number31.id in error_email['payload']
assert error_email['msg']['References']
def test_backoffice_wscall_attachment(http_requests, pub):
create_user(pub)
create_environment(pub)
@ -3033,6 +3099,7 @@ def test_backoffice_wscall_attachment(http_requests, pub):
resp = resp.follow()
assert resp.text == '<?xml version="1.0"><foo/>'
def test_backoffice_wfedit(pub):
user = create_user(pub)
create_environment(pub)
@ -3077,6 +3144,7 @@ def test_backoffice_wfedit(pub):
assert form_class().get(number31.id).data['2'] == 'bar'
number31.store()
def test_backoffice_wfedit_submission(pub):
user = create_user(pub)
create_environment(pub)
@ -3127,6 +3195,7 @@ def test_backoffice_wfedit_submission(pub):
number31.store()
assert formdata_count == form_class.count()
def test_backoffice_wfedit_and_backoffice_fields(pub):
user = create_user(pub)
create_environment(pub)
@ -3169,6 +3238,7 @@ def test_backoffice_wfedit_and_backoffice_fields(pub):
resp = resp.follow()
assert form_class().get(number31.id).data['bo1'] == 'plop'
def test_backoffice_wfedit_and_data_source_with_user_info(pub):
user = create_user(pub)
create_environment(pub)
@ -3220,6 +3290,7 @@ def test_backoffice_wfedit_and_data_source_with_user_info(pub):
assert urlopen.call_count == 2
resp = resp.follow()
def test_global_listing(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
@ -3338,6 +3409,7 @@ def test_global_listing(pub):
assert resp.text[resp.text.index('<tbody'):].count('<tr') == 0
assert not 'form-title' in resp.text
def test_global_listing_user_label(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
@ -3377,6 +3449,7 @@ def test_global_listing_user_label(pub):
resp = resp.click('Global View')
assert '<td class="cell-user">blah xxx</td>' in resp.text
def test_management_views_with_no_formdefs(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
@ -3398,6 +3471,7 @@ def test_management_views_with_no_formdefs(pub):
resp = app.get('/backoffice/management/listing')
assert 'This site is currently empty.' in resp.text
def test_category_in_global_listing(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
@ -3437,6 +3511,7 @@ def test_category_in_global_listing(pub):
assert 'management/other-form/' in resp.text
assert not 'management/form-title/' in resp.text
def test_datetime_in_global_listing(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
@ -3477,6 +3552,7 @@ def test_datetime_in_global_listing(pub):
resp = resp.forms['listing-settings'].submit()
assert resp.text[resp.text.index('<tbody'):].count('<tr') == 37
def test_global_listing_anonymised(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
@ -3498,6 +3574,7 @@ def test_global_listing_anonymised(pub):
resp = app.get('/backoffice/management/listing?limit=500&status=open')
assert resp.text[resp.text.index('<tbody'):].count('<tr') == 17
def test_global_listing_geojson(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
@ -3532,6 +3609,7 @@ def test_global_listing_geojson(pub):
resp = app.get('/backoffice/management/geojson?q=cc')
assert len(resp.json['features']) == 8
def test_global_map(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
@ -3558,6 +3636,7 @@ def test_global_map(pub):
resp = app.get('/backoffice/management/map?q=test')
assert re.findall(r'data-geojson-url="(.*?)"', resp.text) == ['http://example.net/backoffice/management/geojson?q=test']
def test_formdata_lookup(pub):
create_user(pub)
create_environment(pub, set_receiver=False)
@ -3620,6 +3699,7 @@ def test_formdata_lookup(pub):
resp = resp.follow()
assert 'No such tracking code or identifier.' in resp.text
def test_backoffice_sidebar_user_context(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
@ -3684,6 +3764,7 @@ def test_backoffice_sidebar_user_context(pub):
assert '>Misc<' in partial_resp.text
assert partial_resp.text.index('>Misc<') < partial_resp.text.index('>cat1<')
def test_count_open(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
@ -3735,6 +3816,7 @@ def test_count_open(pub):
resp = login(get_app(pub)).get('/backoffice/management/count?callback=toto')
assert "20" in resp.text
def test_count_backoffice_drafts(pub):
user = create_user(pub)
create_environment(pub)
@ -3769,6 +3851,7 @@ def test_count_backoffice_drafts(pub):
resp = login(get_app(pub)).get('/backoffice/submission/count?mode=existing')
assert resp.json['count'] == 2
def test_menu_json(pub):
user = create_user(pub)
create_environment(pub)
@ -3782,6 +3865,7 @@ def test_menu_json(pub):
assert resp.text == 'foo(%s);' % menu_json_str
assert resp.headers['content-type'] == 'application/javascript'
def test_per_user_view(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
@ -3842,6 +3926,7 @@ def test_per_user_view(pub):
resp = app.get('/backoffice/management/users/%s/' % user.id)
assert resp.text.count('<li') == (count_li - 2)
def test_per_user_view_tracking_code(pub, emails, sms_mocking):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
@ -3887,6 +3972,7 @@ def test_per_user_view_tracking_code(pub, emails, sms_mocking):
assert sms_mocking.sms[-1]['destinations'] == ['0123456789']
assert form_class.get(number31.id).tracking_code in sms_mocking.sms[-1]['text']
def test_backoffice_resume_folded(pub):
user = create_user(pub)
create_environment(pub)
@ -3902,6 +3988,7 @@ def test_backoffice_resume_folded(pub):
resp = resp.follow()
assert '<div class="section foldable folded" id="summary">' in resp.text
def test_backoffice_backoffice_submission_in_listings(pub):
create_superuser(pub)
create_environment(pub)
@ -3918,6 +4005,7 @@ def test_backoffice_backoffice_submission_in_listings(pub):
resp = app.get('/backoffice/management/form-title/')
assert 'backoffice-submission' in resp.text
def test_backoffice_backoffice_submission_in_global_listing(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
@ -3938,6 +4026,7 @@ def test_backoffice_backoffice_submission_in_global_listing(pub):
resp = app.get('/backoffice/management/listing?limit=100')
assert 'backoffice-submission' in resp.text
def test_backoffice_advisory_lock(pub):
create_superuser(pub)
create_environment(pub)
@ -4008,6 +4097,7 @@ def test_backoffice_advisory_lock(pub):
assert not 'advisory-lock' in app2.get('/backoffice/management/form-title/')
assert 'advisory-lock' in app.get('/backoffice/management/form-title/')
def test_backoffice_advisory_lock_related_formdatas(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
@ -4078,6 +4168,7 @@ def test_backoffice_advisory_lock_related_formdatas(pub):
session = pub.session_manager.session_class.select(lambda x: x.user == user.id)[0]
assert 'formdata-other-form-%d' % other_formdata.id in session.visiting_objects.keys()
def test_backoffice_resubmit(pub):
user = create_user(pub)
create_environment(pub)
@ -4140,6 +4231,7 @@ def test_backoffice_resubmit(pub):
assert 'Original form' in resp.text
assert formdata.get_url(backoffice=True) in resp.text
def test_backoffice_workflow_display_form(pub):
user = create_user(pub)
create_environment(pub)
@ -4199,6 +4291,7 @@ def test_backoffice_workflow_display_form(pub):
assert formdef.data_class().get(formdata.id).workflow_data == {
'blah_var_str': 'blah', 'blah_var_radio': 'c', 'blah_var_radio_raw': 'c'}
def test_backoffice_workflow_form_with_conditions(pub):
user = create_user(pub)
create_environment(pub)
@ -4313,6 +4406,7 @@ def test_backoffice_workflow_form_with_conditions(pub):
assert formdef.data_class().get(formdata.id).workflow_data == {'blah_var_str': 'xxx2', 'blah_var_str2': None}
def test_backoffice_workflow_form_with_live_data_source(pub):
user = create_user(pub)
create_environment(pub)
@ -4368,6 +4462,7 @@ def test_backoffice_workflow_form_with_live_data_source(pub):
live_resp = app.post(live_url + '?modified_field_id=1', params=resp.form.submit_fields())
assert live_resp.json['result']['2']['items'] == [{u'text': u'hello', u'id': u'C'}, {u'text': u'world', u'id': u'D'}]
def test_backoffice_criticality_in_formdef_listing(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
@ -4412,6 +4507,7 @@ def test_backoffice_criticality_in_formdef_listing(pub):
assert resp.text.index(formdata1_str) < resp.text.index(formdata3_str)
assert resp.text.index(formdata1_str) > resp.text.index(formdata4_str)
def test_backoffice_criticality_in_global_listing(pub):
if not pub.is_using_postgresql():
pytest.skip('this requires SQL')
@ -4457,6 +4553,7 @@ def test_backoffice_criticality_in_global_listing(pub):
assert resp.text.index(formdata1_str) < resp.text.index(formdata3_str)
assert resp.text.index(formdata1_str) > resp.text.index(formdata4_str)
def test_backoffice_criticality_formdata_view(pub):
user = create_user(pub)
create_environment(pub)
@ -4496,6 +4593,7 @@ class IHateUnicode(object):
def __repr__(self):
return 'ok'
@pytest.fixture
def local_user():
get_publisher().user_class.wipe()
@ -4506,6 +4604,7 @@ def local_user():
user.store()
return user
def test_inspect_page(pub, local_user):
create_user(pub)
create_environment(pub)
@ -4667,6 +4766,7 @@ def test_inspect_page(pub, local_user):
assert 'syntax error' in resp.text
assert 'Invalid block tag' in resp.text
def test_workflow_jump_previous(pub):
user = create_user(pub)
create_environment(pub)
@ -4776,6 +4876,7 @@ def test_workflow_jump_previous(pub):
formdata.jump_status('_previous') # pop ()
assert formdata.status == 'wf-%s' % st1.id
def test_workflow_jump_previous_on_submit(pub):
user = create_user(pub)
create_environment(pub)
@ -4835,6 +4936,7 @@ def test_workflow_jump_previous_on_submit(pub):
assert formdef.data_class().get(formdata.id).status == 'wf-north'
assert not formdef.data_class().get(formdata.id).workflow_data['_markers_stack']
def test_workflow_jump_previous_auto(pub):
user = create_user(pub)
create_environment(pub)
@ -4888,6 +4990,7 @@ def test_workflow_jump_previous_auto(pub):
assert formdata.status == 'wf-south'
assert formdata.workflow_data['_markers_stack'] == [{'status_id': 'north'}]
def test_backoffice_fields(pub):
user = create_user(pub)
create_environment(pub)
@ -4938,6 +5041,7 @@ def test_backoffice_fields(pub):
assert 'Backoffice Data' in resp.text
assert 'Not set' in resp.text
def test_backoffice_logged_errors(pub):
Workflow.wipe()
workflow = Workflow.get_default_workflow()
@ -5027,6 +5131,7 @@ def test_backoffice_logged_errors(pub):
resp = resp2.click('Failed to evaluate condition')
assert not 'href="http://example.net/backoffice/management/test/' in resp.text
def test_backoffice_formdata_named_wscall(http_requests, pub):
user = create_user(pub)
create_environment(pub)
@ -5083,6 +5188,7 @@ def test_backoffice_formdata_named_wscall(http_requests, pub):
resp = app.get('/backoffice/submission/test/')
assert resp.html.find('div', {'data-field-id': '7'}).text.strip() == 'dja-bar-ngo'
def test_backoffice_session_var(pub):
open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w').write('''[options]
query_string_allowed_vars = foo,bar
@ -5118,6 +5224,7 @@ query_string_allowed_vars = foo,bar
resp = resp.follow()
assert resp.html.find('div', {'data-field-id': '7'}).text.strip() == 'django'
def test_backoffice_display_message(pub):
user = create_user(pub)
create_environment(pub)
@ -5186,6 +5293,7 @@ def test_backoffice_display_message(pub):
assert 'message-to-all' in resp.text
assert resp.text.index('message-to-all') > resp.text.index('message-to-receiver')
def test_backoffice_forms_condition_on_button(pub):
create_superuser(pub)
create_environment(pub, set_receiver=True)
@ -5248,6 +5356,7 @@ def test_backoffice_forms_condition_on_button(pub):
resp = resp.follow()
assert '8 open on 50' in resp.text # only the accepted ones
def test_workflow_inspect_page(pub):
create_superuser(pub)
create_environment(pub, set_receiver=True)
@ -5273,6 +5382,7 @@ def test_workflow_inspect_page(pub):
resp = app.get('/backoffice/workflows/%s/inspect' % workflow.id)
assert '23 hours' in resp.text
def test_workflow_comment_required(pub):
user = create_user(pub)
create_environment(pub)
@ -5322,6 +5432,7 @@ def test_workflow_comment_required(pub):
assert 'widget-with-error' not in resp.text
assert 'HELLO WORLD 2' in resp.text
def test_carddata_management(pub, studio):
CardDef.wipe()
user = create_user(pub)
@ -5373,6 +5484,7 @@ def test_carddata_management(pub, studio):
resp = resp.click('foo')
assert resp.text.count('<tr') == 2 # header + row of data
def test_studio_card_item_link(pub, studio):
user = create_user(pub)
CardDef.wipe()

View File

@ -6,10 +6,12 @@ from wcs.fields import StringField
from utilities import create_temporary_pub, clean_temporary_pub
def pytest_generate_tests(metafunc):
if 'pub' in metafunc.fixturenames:
metafunc.parametrize('pub', ['pickle', 'sql'], indirect=True)
@pytest.fixture
def pub(request):
pub = create_temporary_pub(sql_mode=(request.param == 'sql'))
@ -19,6 +21,7 @@ def pub(request):
pub.write_cfg()
return pub
def teardown_module(module):
clean_temporary_pub()
@ -42,6 +45,7 @@ def test_basics(pub):
assert carddata_class.get(carddata.id).data['1'] == 'hello world'
assert carddata_class.get(carddata.id).status == 'wf-recorded'
def test_xml_export_import(pub):
carddef = CardDef()
carddef.name = 'foo'

View File

@ -12,6 +12,7 @@ from wcs.categories import Category
from utilities import create_temporary_pub
def setup_module(module):
cleanup()
@ -19,6 +20,7 @@ def setup_module(module):
pub = create_temporary_pub()
def teardown_module(module):
shutil.rmtree(pub.APP_DIR)

View File

@ -25,14 +25,17 @@ from wcs.sql import get_connection_and_cursor, cleanup_connection
from utilities import create_temporary_pub, clean_temporary_pub
@pytest.fixture
def pub():
return create_temporary_pub()
def pytest_generate_tests(metafunc):
if 'two_pubs' in metafunc.fixturenames:
metafunc.parametrize('two_pubs', ['pickle', 'sql'], indirect=True)
@pytest.fixture
def two_pubs(request):
pub = create_temporary_pub(sql_mode=(request.param == 'sql'))
@ -40,9 +43,11 @@ def two_pubs(request):
pub.write_cfg()
return pub
def teardown_module(module):
clean_temporary_pub()
def test_loading():
ctl = wcs.qommon.ctl.Ctl(cmd_prefixes=['wcs.ctl'])
ctl.load_all_commands(ignore_errors=False)
@ -51,6 +56,7 @@ def test_loading():
for cmd in ctl.get_commands().values():
cmd()
def test_collectstatic(pub):
CmdCollectStatic.collectstatic(pub)
assert os.path.exists(os.path.join(pub.app_dir, 'collectstatic', 'css', 'wcs.css'))
@ -60,12 +66,15 @@ def test_collectstatic(pub):
CmdCollectStatic.collectstatic(pub, clear=True, link=True)
assert os.path.islink(os.path.join(pub.app_dir, 'collectstatic', 'css', 'wcs.css'))
def test_migrate(two_pubs):
CmdMigrate().handle()
def test_migrate_schemas(two_pubs):
CmdMigrateSchemas().handle()
def test_wipe_formdata(pub):
form_1 = FormDef()
form_1.name = 'example'
@ -120,6 +129,7 @@ def test_wipe_formdata(pub):
assert form_1.data_class().count() == 0
assert form_2.data_class().count() == 0
def test_trigger_jumps(pub):
Workflow.wipe()
workflow = Workflow(name='test')
@ -330,6 +340,7 @@ def test_delete_tenant_without_sql():
clean_temporary_pub()
def test_rebuild_indexes(two_pubs):
form = FormDef()
form.name = 'example'
@ -346,6 +357,7 @@ def test_rebuild_indexes(two_pubs):
rebuild_vhost_indexes(two_pubs, destroy=True)
assert os.listdir(os.path.join(two_pubs.app_dir, 'formdefs-url_name')) == ['example']
def test_runscript(pub):
with pytest.raises(CommandError):
call_command('runscript')
@ -363,6 +375,7 @@ open(os.path.join(get_publisher().app_dir, 'runscript.test'), 'w').close()
call_command('runscript', '--all-tenants', os.path.join(pub.app_dir, 'test2.py'))
assert os.path.exists(os.path.join(pub.app_dir, 'runscript.test'))
def test_import_site():
with pytest.raises(CommandError):
call_command('import_site')

View File

@ -22,6 +22,7 @@ import mock
from test_widgets import MockHtmlForm, mock_form_submission
from utilities import create_temporary_pub
def setup_module(module):
cleanup()
@ -53,6 +54,7 @@ def requests_pub(request):
pub._set_request(req)
return req
def test_item_field_python_datasource(requests_pub):
req = get_request()
req.environ['REQUEST_METHOD'] = 'POST'
@ -80,6 +82,7 @@ def test_item_field_python_datasource(requests_pub):
mock_form_submission(req, widget)
assert widget.parse() == '1'
def test_python_datasource():
plain_list = [('1', 'foo'), ('2', 'bar')]
datasource = {'type': 'formula', 'value': repr(plain_list)}
@ -127,6 +130,7 @@ def test_python_datasource():
('foo', 'Foo', 'foo', {'id': 'foo', 'text': 'Foo'}),
('bar', 'Bar', 'bar', {'id': 'bar', 'text': 'Bar', 'disabled': True})]
def test_python_datasource_with_evalutils():
plain_list = [
{'id': 'foo', 'text': 'Foo', 'value': '2017-01-01'},
@ -135,6 +139,7 @@ def test_python_datasource_with_evalutils():
assert data_sources.get_items(datasource) == [
('foo', 'Foo', 'foo', {'id': 'foo', 'text': 'Foo', 'value': '2017-01-01'})]
def test_json_datasource(http_requests):
req = get_request()
get_request().datasources_cache = {}
@ -274,6 +279,7 @@ def test_json_datasource(http_requests):
assert data_sources.get_items(datasource) == []
assert data_sources.get_structured_items(datasource) == []
def test_json_datasource_bad_url(http_requests, caplog):
datasource = {'type': 'json', 'value': 'http://remote.example.net/404'}
assert data_sources.get_items(datasource) == []
@ -293,6 +299,7 @@ def test_json_datasource_bad_url(http_requests, caplog):
assert 'Error loading JSON data source' in caplog.records[-1].message
assert 'error' in caplog.records[-1].message
def test_json_datasource_bad_url_scheme(caplog):
datasource = {'type': 'json', 'value': ''}
assert data_sources.get_items(datasource) == []
@ -308,6 +315,7 @@ def test_json_datasource_bad_url_scheme(caplog):
assert 'Error loading JSON data source' in caplog.records[-1].message
assert 'invalid scheme in URL' in caplog.records[-1].message
def test_item_field_named_python_datasource():
NamedDataSource.wipe()
data_source = NamedDataSource(name='foobar')
@ -326,6 +334,7 @@ def test_item_field_named_python_datasource():
assert widget is not None
assert widget.options == [('1', 'un', '1'), ('2', 'deux', '2')]
def test_register_data_source_function():
def xxx():
return [('1', 'foo'), ('2', 'bar')]
@ -338,6 +347,7 @@ def test_register_data_source_function():
assert data_sources.get_structured_items(datasource) == [
{'id': '1', 'text': 'foo'}, {'id': '2', 'text': 'bar'}]
def test_data_source_substitution_variables():
NamedDataSource.wipe()
data_source = NamedDataSource(name='foobar')
@ -348,12 +358,14 @@ def test_data_source_substitution_variables():
assert context.get('data_source').foobar == [
{'id': 'un', 'text': 'un'}, {'id': 'deux', 'text': 'deux'}]
def test_data_source_slug_name():
NamedDataSource.wipe()
data_source = NamedDataSource(name='foo bar')
data_source.store()
assert data_source.slug == 'foo_bar'
def test_optional_item_field_with_data_source():
NamedDataSource.wipe()
data_source = NamedDataSource(name='foobar')
@ -451,6 +463,7 @@ def test_data_source_signed(no_request_pub):
unsigned_url = urlopen.call_args[0][0]
assert unsigned_url == 'https://no-secret.example.com/json'
def test_named_datasource_json_cache(requests_pub):
NamedDataSource.wipe()
datasource = NamedDataSource(name='foobar')
@ -485,6 +498,7 @@ def test_named_datasource_json_cache(requests_pub):
{'id': '1', 'text': 'foo'}, {'id': '2', 'text': 'bar'}]
assert urlopen.call_count == 3
def test_named_datasource_in_formdef():
from wcs.formdef import FormDef
datasource = NamedDataSource(name='foobar')

View File

@ -10,12 +10,15 @@ from wcs.scripts import ScriptsSubstitutionProxy
from utilities import get_app, create_temporary_pub, clean_temporary_pub
def setup_module(module):
cleanup()
def teardown_module(module):
clean_temporary_pub()
@pytest.fixture
def pub(request):
pub = create_temporary_pub()
@ -23,6 +26,7 @@ def pub(request):
pub.write_cfg()
return pub
def test_simple_qualifier():
template = Template()
template.parse('<p>[foo]</p>')
@ -30,6 +34,7 @@ def test_simple_qualifier():
template.generate(output, {'foo': 'bar'})
assert output.getvalue() == '<p>bar</p>'
def test_simple_qualifier_missing_variable():
template = Template()
template.parse('<p>[foo]</p>')
@ -37,6 +42,7 @@ def test_simple_qualifier_missing_variable():
template.generate(output, {})
assert output.getvalue() == '<p>[foo]</p>'
def test_if_any():
template = Template()
template.parse('<p>[if-any foo]bar[end]</p>')
@ -56,6 +62,7 @@ def test_if_any():
template.generate(output, {'foo': False})
assert output.getvalue() == '<p>bar</p>'
def test_if_any_else():
template = Template()
template.parse('<p>[if-any foo]bar[else]baz[end]</p>')
@ -68,6 +75,7 @@ def test_if_any_else():
template.generate(output, {})
assert output.getvalue() == '<p>baz</p>'
def test_is():
template = Template()
template.parse('<p>[is foo "bar"]bar[end]</p>')
@ -87,6 +95,7 @@ def test_is():
template.generate(output, {'foo': 'bar'})
assert output.getvalue() == '<p>bar</p>'
def test_callable_qualifier():
template = Template()
template.parse('<p>[foo]</p>')
@ -94,6 +103,7 @@ def test_callable_qualifier():
template.generate(output, {'foo': lambda x: x.write('bar')})
assert output.getvalue() == '<p>bar</p>'
def test_date_qualifier(pub):
template = Template()
template.parse('<p>[foo]</p>')
@ -107,6 +117,7 @@ def test_date_qualifier(pub):
template.generate(output, {'foo': datetime.date(2019, 1, 2)})
assert output.getvalue() == '<p>02/01/2019</p>'
def test_datetime_qualifier(pub):
template = Template()
template.parse('<p>[foo]</p>')
@ -120,6 +131,7 @@ def test_datetime_qualifier(pub):
template.generate(output, {'foo': datetime.datetime(2019, 1, 2, 14, 4)})
assert output.getvalue() == '<p>02/01/2019 14:04</p>'
def test_unclosed_block():
template = Template()
with pytest.raises(UnclosedBlocksError):
@ -129,6 +141,7 @@ def test_unclosed_block():
except UnclosedBlocksError as e:
assert e.column == 19 and e.line == 0
def test_unmatched_end():
template = Template()
with pytest.raises(UnmatchedEndError):
@ -138,6 +151,7 @@ def test_unmatched_end():
except UnmatchedEndError as e:
assert e.column == 15 and e.line == 0
def test_unmatched_else():
template = Template()
with pytest.raises(UnmatchedElseError):
@ -147,6 +161,7 @@ def test_unmatched_else():
except UnmatchedElseError as e:
assert e.column == 3 and e.line == 0
def test_missing_is_arg():
template = Template()
with pytest.raises(ArgCountSyntaxError):
@ -156,6 +171,7 @@ def test_missing_is_arg():
except ArgCountSyntaxError as e:
assert e.column == 5 and e.line == 1
def test_array_index():
template = Template()
template.parse('<p>[foo.0]</p>')
@ -169,6 +185,7 @@ def test_array_index():
template.generate(output, {'foo': ['bar']})
assert output.getvalue() == '<p>[foo.bar]</p>'
def test_array_subindex():
template = Template()
template.parse('<p>[foo.0.1]</p>')
@ -176,6 +193,7 @@ def test_array_subindex():
template.generate(output, {'foo': [['bar', 'baz']]})
assert output.getvalue() == '<p>baz</p>'
def test_dict_index():
template = Template()
template.parse('<p>[foo.a]</p>')
@ -189,6 +207,7 @@ def test_dict_index():
template.generate(output, {'foo': {'a': 'bar'}})
assert output.getvalue() == '<p>[foo.b]</p>'
def test_ezt_script(pub):
os.mkdir(os.path.join(pub.app_dir, 'scripts'))
fd = open(os.path.join(pub.app_dir, 'scripts', 'hello_world.py'), 'w')
@ -209,6 +228,7 @@ def test_ezt_script(pub):
template.generate(output, vars)
assert output.getvalue() == '<p>Hello fred</p>'
def test_re_parse():
assert _re_parse.split('[a]') == ['', 'a', None, '']
assert _re_parse.split('[a] [b]') == \

View File

@ -16,6 +16,7 @@ from wcs.formdef import FormDef
from utilities import create_temporary_pub, MockSubstitutionVariables
def setup_module(module):
cleanup()
global pub
@ -24,19 +25,23 @@ def setup_module(module):
pub._set_request(req)
req.session = sessions.Session(id=1)
def teardown_module(module):
global pub
shutil.rmtree(pub.APP_DIR)
def test_fill_admin_form():
for klass in fields.field_classes:
form = Form(use_tokens=False)
klass().fill_admin_form(form)
def test_get_admin_attributes():
for klass in fields.field_classes:
klass().get_admin_attributes()
def test_add_to_form():
for klass in fields.field_classes:
form = Form(use_tokens=False)
@ -46,6 +51,7 @@ def test_add_to_form():
else:
klass(label='foo').add_to_form(form)
def test_string():
# sample string
assert fields.StringField().get_view_value('foo') == 'foo'
@ -74,6 +80,7 @@ def test_string():
assert str(fields.StringField().get_rst_view_value(url)) == url
assert fields.StringField().get_csv_value(url) == [url]
def test_text():
assert fields.TextField().get_view_short_value('foo'*10) == ('foo'*10)[:25] + ' (...)'
assert fields.TextField().get_view_value('foo') == '<p>foo</p>'
@ -92,15 +99,18 @@ def test_text():
assert 'cols="12"' in str(form.render())
assert 'rows="12"' in str(form.render())
def test_email():
assert fields.EmailField().get_view_value('foo@localhost') == \
'<a href="mailto:foo@localhost">foo@localhost</a>'
assert fields.EmailField().get_rst_view_value('foo@localhost') == 'foo@localhost'
def test_bool():
assert fields.BoolField().get_view_value(True) == 'Yes'
assert fields.BoolField().get_view_value(False) == 'No'
def test_bool_stats():
formdef = FormDef()
formdef.url_name = 'title'
@ -114,6 +124,7 @@ def test_bool_stats():
stats = formdef.fields[0].stats(formdatas)
assert re.findall('Yes.*75.*No.*25', str(stats))
def test_items():
assert fields.ItemsField(items=['a', 'b', 'c']).get_view_value(['a', 'b']) == 'a, b'
assert fields.ItemsField(items=['a', 'b', 'c']).get_csv_value(['a', 'b']) == ['a', 'b', '']
@ -129,13 +140,16 @@ def test_items():
assert field.get_options() == [('1', 'foo', '1'), ('2', 'bar', '2')]
assert field.get_options() == [('1', 'foo', '1'), ('2', 'bar', '2')] # twice for cached behaviour
def test_password():
assert fields.PasswordField().get_view_value('xxx') == ''*8
def test_file():
upload = Upload('/foo/bar', content_type='text/plain')
assert fields.FileField().get_csv_value(upload) == ['/foo/bar']
def test_page():
formdef = FormDef()
formdef.fields = []
@ -148,9 +162,11 @@ def test_page():
assert page.is_visible({'1': 'bar'}, formdef) is True
assert page.is_visible({'1': 'baz'}, formdef) is False
def test_table():
assert 'prefill' not in fields.TableField().get_admin_attributes()
def test_title():
field = fields.TitleField(label='Foobar')
form = Form(use_tokens=False)
@ -195,6 +211,7 @@ def test_title():
assert '&lt;i&gt;Foobar&amp;eacute;&lt;/i&gt;' in str(form.render())
assert field.unhtmled_label == 'Foobaré'
def test_subtitle():
field = fields.SubtitleField(label='Foobar')
form = Form(use_tokens=False)
@ -239,6 +256,7 @@ def test_subtitle():
assert '&lt;i&gt;Foobar&amp;eacute;&lt;/i&gt;' in str(form.render())
assert field.unhtmled_label == 'Foobaré'
def test_comment():
field = fields.CommentField(label='Foobar')
form = Form(use_tokens=False)
@ -285,6 +303,7 @@ def test_comment():
field = fields.CommentField(label='<p>Foobar&eacute;</p>')
assert field.unhtmled_label == 'Foobaré'
def test_map():
assert fields.MapField().get_json_value('42.2;10.2') == {'lat': 42.2, 'lon': 10.2}
assert fields.MapField().get_json_value('-42.2;10.2') == {'lat': -42.2, 'lon': 10.2}
@ -292,6 +311,7 @@ def test_map():
assert fields.MapField().get_json_value('') == None
assert fields.MapField().get_json_value('foobar') == None
def test_item_render():
items_kwargs = []
items_kwargs.append({'items': ['aa', 'ab', 'ac']})
@ -357,6 +377,7 @@ def test_item_render():
assert str(form.render()).count('<option value="" data-hint="Bla bla bla">Bla bla bla</option>') == 1 # ---
assert str(form.render()).count('<option') == 1
def test_item_render_as_autocomplete():
field = fields.ItemField(
id='1',
@ -368,6 +389,7 @@ def test_item_render_as_autocomplete():
assert str(form.render()).count('<option') == 3
assert 'data-autocomplete' in str(form.render())
def test_item_render_as_radio():
items_kwargs = []
items_kwargs.append({'items': ['aa', 'ab', 'ac']})
@ -429,6 +451,7 @@ def test_item_render_as_radio():
field.add_to_form(form)
assert str(form.render()).count('"radio"') == 1
def test_item_radio_lengths():
field = fields.ItemField(id='1', label='Foobar', display_mode='radio',
items=['aa', 'ab', 'ac'])
@ -458,6 +481,7 @@ def test_item_radio_lengths():
form.render()
assert str(form.widgets[-1].render()).count('<br') == 3
def test_items_render():
items_kwargs = []
items_kwargs.append({'items': ['aa', 'ab', 'ac']})
@ -474,11 +498,13 @@ def test_items_render():
assert '>ab<' in str(form.render())
assert '>ac<' in str(form.render())
def test_ranked_items():
field = fields.RankedItemsField(id='1', label='Foobar', items=['aa', 'ab', 'ac'])
assert len(field.get_csv_heading()) == 3
assert field.get_csv_value({'aa': 2, 'ab': 1, 'ac': 3}) == ['ab', 'aa', 'ac']
def test_table_rows():
field = fields.TableRowsField(id='1', label='Foobar', columns=['aa', 'ab', 'ac'], total_row=False)
html_table = str(field.get_view_value([['A', 'B', 'C'], ['D', 'E', 'F']]))

File diff suppressed because it is too large Load Diff

View File

@ -28,10 +28,12 @@ from utilities import create_temporary_pub, clean_temporary_pub
from test_api import local_user
def pytest_generate_tests(metafunc):
if 'pub' in metafunc.fixturenames:
metafunc.parametrize('pub', ['pickle', 'sql'], indirect=True)
@pytest.fixture
def pub(request):
pub = create_temporary_pub(sql_mode=(request.param == 'sql'))
@ -72,6 +74,7 @@ def test_basic(pub):
assert substvars.get('form_slug') == 'foobar'
assert substvars.get('category_name') == 'test category'
def test_saved(pub):
formdef.data_class().wipe()
formdata = formdef.data_class()()
@ -83,6 +86,7 @@ def test_saved(pub):
assert substvars.get('form_url_backoffice').endswith('/backoffice/management/foobar/1/')
assert substvars.get('form_status_url').endswith('/foobar/1/status')
def test_auto_display_id(pub):
formdef.data_class().wipe()
formdata = formdef.data_class()()
@ -91,6 +95,7 @@ def test_auto_display_id(pub):
assert substvars.get('form_number') == '%s-%s' % (formdef.id, formdata.id)
assert substvars.get('form_number_raw') == str(formdata.id)
def test_manual_display_id(pub):
formdef.data_class().wipe()
formdata = formdef.data_class()()
@ -100,6 +105,7 @@ def test_manual_display_id(pub):
assert substvars.get('form_number') == 'bar'
assert substvars.get('form_number_raw') == str(formdata.id)
def test_submission_context(pub):
formdef.data_class().wipe()
formdata = formdef.data_class()()
@ -120,6 +126,7 @@ def test_submission_context(pub):
assert substvars.get('form_submission_channel') is None
assert substvars.get('form_submission_channel_label') == 'Web'
def test_just_created(pub):
formdef.data_class().wipe()
formdata = formdef.data_class()()
@ -133,6 +140,7 @@ def test_just_created(pub):
assert substvars.get('form_receipt_datetime')
assert substvars.get('form_evolution')
def test_field(pub):
formdef.data_class().wipe()
formdef.fields = [fields.StringField(id='0', label='string')]
@ -146,6 +154,7 @@ def test_field(pub):
assert substvars.get('form_f0') == 'test'
assert substvars.get('form_field_string') == 'test'
def test_field_varname(pub):
formdef.data_class().wipe()
formdef.fields = [fields.StringField(id='0', label='string', varname='foo')]
@ -156,6 +165,7 @@ def test_field_varname(pub):
assert substvars.get('form_f0') == 'test'
assert substvars.get('form_var_foo') == 'test'
def test_file_field(pub):
formdef.data_class().wipe()
formdef.fields = [fields.FileField(id='0', label='file', varname='foo')]
@ -182,6 +192,7 @@ def test_file_field(pub):
assert substvars['form_var_foo_raw'] is None
assert substvars['form_var_foo_url'] is None
def test_get_submitter(pub):
formdef.data_class().wipe()
formdef.fields = [fields.StringField(id='0', label='email', varname='foo',
@ -203,6 +214,7 @@ def test_get_submitter(pub):
formdata.data = {}
assert formdef.get_submitter_email(formdata) == 'bar@localhost'
def test_get_last_update_time(pub):
formdef.data_class().wipe()
formdef.store()
@ -226,6 +238,7 @@ def test_get_last_update_time(pub):
formdata.evolution = None
assert formdata.last_update_time == formdata.receipt_time
def test_password_field(pub):
formdef.data_class().wipe()
formdef.fields = [fields.PasswordField(id='0', label='pwd')]
@ -237,6 +250,7 @@ def test_password_field(pub):
formdata2 = formdata.get(formdata.id)
assert formdata2.data == {'0': {'cleartext': 'foo'}}
def test_date_field(pub):
formdef.data_class().wipe()
formdef.fields = [fields.DateField(id='0', label='date')]
@ -254,6 +268,7 @@ def test_date_field(pub):
assert formdata2.get_substitution_variables()['form_field_date'] == '12/05/2015'
pub.cfg['language'] = {'language': 'en'}
def test_clean_drafts(pub):
formdef = FormDef()
formdef.name = 'foo'
@ -279,6 +294,7 @@ def test_clean_drafts(pub):
assert formdef.data_class().count() == 1
assert formdef.data_class().select()[0].id == d_id1
def test_criticality_levels(pub):
workflow = Workflow(name='criticality')
workflow.criticality_levels = [
@ -347,6 +363,7 @@ def test_criticality_levels(pub):
assert d.get_static_substitution_variables().get('form_criticality_label') == 'green'
assert d.get_substitution_variables().get('form_criticality_label') == 'green'
def test_field_item_substvars(pub):
ds = {
'type': 'formula',
@ -366,6 +383,7 @@ def test_field_item_substvars(pub):
assert variables.get('form_var_xxx') == 'un'
assert variables.get('form_var_xxx_raw') == '1'
def test_get_json_export_dict_evolution(pub, local_user):
Workflow.wipe()
workflow = Workflow(name='test')
@ -439,6 +457,7 @@ def test_get_json_export_dict_evolution(pub, local_user):
assert 'who' not in export['evolution'][0]
assert 'parts' not in export['evolution'][1]
def test_field_bool_substvars(pub):
formdef = FormDef()
formdef.name = 'foobar'
@ -457,6 +476,7 @@ def test_field_bool_substvars(pub):
assert variables.get('form_var_xxx') == 'True'
assert variables.get('form_var_xxx_raw') is True
def test_backoffice_field_varname(pub):
wf = Workflow(name='bo fields')
wf.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(wf)
@ -476,6 +496,7 @@ def test_backoffice_field_varname(pub):
substvars = formdata.get_substitution_variables()
assert substvars.get('form_var_backoffice_blah') == 'test'
def test_workflow_data_file_url(pub):
upload = PicklableUpload('test.txt', 'text/plain', 'ascii')
upload.receive([b'first line', b'second line'])
@ -492,6 +513,7 @@ def test_workflow_data_file_url(pub):
substvars = formdata.get_substitution_variables()
assert substvars['foo_var_file_url']
def test_evolution_get_status(pub):
Workflow.wipe()
workflow = Workflow(name='test')
@ -536,6 +558,7 @@ def test_evolution_get_status(pub):
assert [x.get_status().id for x in d.evolution] == ['1', '1', '1', '2', '2']
@pytest.fixture
def variable_test_data(pub):
pub.user_class.wipe()
@ -602,6 +625,7 @@ def variable_test_data(pub):
pub.substitutions.feed(formdata)
return LazyFormData(formdata)
def test_lazy_formdata(pub, variable_test_data):
formdata = FormDef.select()[0].data_class().select()[0]
lazy_formdata = LazyFormData(formdata)
@ -727,6 +751,7 @@ def test_lazy_formdata(pub, variable_test_data):
lazy_formdata = LazyFormData(formdata)
assert lazy_formdata.tracking_code == tracking_code.id
def test_lazy_formdata_queryset(pub, variable_test_data):
lazy_formdata = variable_test_data
data_class = lazy_formdata._formdef.data_class()
@ -786,6 +811,7 @@ def test_lazy_formdata_queryset(pub, variable_test_data):
manager['drafts']
assert manager._cached_resultset is None
def test_lazy_formdata_queryset_distance(pub, variable_test_data):
lazy_formdata = variable_test_data
formdef = lazy_formdata._formdef
@ -825,6 +851,7 @@ def test_lazy_formdata_queryset_distance(pub, variable_test_data):
assert bool(nearby) is False
assert len(nearby) == 0
def test_lazy_variables(pub, variable_test_data):
formdata = FormDef.select()[0].data_class().select()[0]
for mode in (None, 'lazy'):
@ -841,6 +868,7 @@ def test_lazy_variables(pub, variable_test_data):
assert context['form_var_foo_foo_baz_baz'] == 'other'
assert context['form_var_pwd_cleartext'] == 'a'
def test_lazy_variables_missing(pub, variable_test_data):
formdef = FormDef.select()[0]
formdata = formdef.data_class()()
@ -858,6 +886,7 @@ def test_lazy_variables_missing(pub, variable_test_data):
with pytest.raises(KeyError):
assert context['form_var_foo_foo_xxx'] == 'bar'
def test_lazy_map_variable(pub, variable_test_data):
formdef = FormDef.select()[0]
formdata = formdef.data_class().select()[0]
@ -896,6 +925,7 @@ def test_lazy_map_variable(pub, variable_test_data):
assert WorkflowStatusItem.compute('{{ form_var_map|distance:"1;2"|floatformat }}', raises=True) == ''
assert WorkflowStatusItem.compute('{{ "1;2"|distance:form_var_map|floatformat }}', raises=True) == ''
def test_lazy_conditions(pub, variable_test_data):
condition = Condition({'type': 'django', 'value': 'form_var_foo_foo == "bar"'})
assert condition.evaluate() is True
@ -992,6 +1022,7 @@ def test_lazy_conditions(pub, variable_test_data):
condition = Condition({'type': 'django', 'value': 'not form_var_datefield == form_var_barbarbar'})
assert condition.evaluate() is True
def test_has_role_templatetag(pub, variable_test_data):
condition = Condition({'type': 'django', 'value': 'form_user|has_role:"foobar"'})
assert condition.evaluate() is False
@ -1018,6 +1049,7 @@ def test_has_role_templatetag(pub, variable_test_data):
condition = Condition({'type': 'django', 'value': 'xxx|has_role:"foobar"'})
assert condition.evaluate() is False
def test_lazy_now_and_today(pub, variable_test_data):
for condition_value in (
'now > "1970-01-01"',
@ -1040,6 +1072,7 @@ def test_lazy_now_and_today(pub, variable_test_data):
condition = Condition({'type': 'django', 'value': condition_value.replace('now', 'today')})
assert condition.evaluate() is True
def test_lazy_date_templatetags(pub, variable_test_data):
for condition_value in (
'"2017-10-10"|date == "2017-10-10"',
@ -1112,6 +1145,7 @@ def test_lazy_date_templatetags(pub, variable_test_data):
condition = Condition({'type': 'django', 'value': 'today == now|date'})
assert condition.evaluate() is True
def test_lazy_date_with_maths(pub, variable_test_data):
# form_var_datefield : 2018-07-31
# form_var_datefield2 : 2018-08-31
@ -1195,6 +1229,7 @@ def test_lazy_date_with_maths(pub, variable_test_data):
condition = Condition({'type': 'django', 'value': condition_value.replace('today', 'now')})
assert condition.evaluate() is True
def test_lazy_templates(pub, variable_test_data):
context = pub.substitutions.get_context_variables(mode='lazy')
tmpl = Template('{{form_var_foo_foo}}')
@ -1215,6 +1250,7 @@ def test_lazy_templates(pub, variable_test_data):
tmpl = Template('{% if form_user_email == "bar@localhost" %}HELLO{% endif %}')
assert tmpl.render(context) == 'HELLO'
def test_lazy_ezt_templates(pub, variable_test_data):
context = pub.substitutions.get_context_variables(mode='lazy')
tmpl = Template('[form_var_foo_foo]')
@ -1223,6 +1259,7 @@ def test_lazy_ezt_templates(pub, variable_test_data):
tmpl = Template('[is form_var_foo_foo "bar"]HELLO[else]BYE[end]')
assert tmpl.render(context) == 'HELLO'
def test_lazy_formdata_fields(pub):
formdef = FormDef()
formdef.name = 'foobar'
@ -1250,6 +1287,7 @@ def test_lazy_formdata_fields(pub):
tmpl = Template('{% if form_var_item != "Foo" %}HELLO{% endif %}')
assert tmpl.render(context) == ''
def test_date_conditions_python(pub, variable_test_data):
for pycondition in (
'utils.age_in_days(form_var_datefield, form_var_datefield2) == 31',
@ -1278,6 +1316,7 @@ def test_date_conditions_python(pub, variable_test_data):
condition = Condition({'type': 'python', 'value': pycondition})
assert condition.evaluate() is True
def test_date_conditions_django(pub, variable_test_data):
for condition_value in ( # hope date is > 2018
# age_in_days
@ -1391,6 +1430,7 @@ def test_date_conditions_django(pub, variable_test_data):
condition = Condition({'type': 'django', 'value': condition_value})
assert condition.evaluate() is True
def test_form_digest_date(pub):
formdef = FormDef()
formdef.name = 'foobar'
@ -1440,6 +1480,7 @@ def test_form_digest_date(pub):
formdata.store()
assert formdef.data_class().get(formdata.id).digest == 'plop plop'
def test_lazy_formdata_decimal_filter(pub):
formdef = FormDef()
formdef.name = 'foobar'
@ -1468,6 +1509,7 @@ def test_lazy_formdata_decimal_filter(pub):
tmpl = Template('{{ 4.12|decimal:form_var_arg }}')
assert tmpl.render(context) == '4.120'
def test_decimal_conditions_django(pub, variable_test_data):
for condition_value in (
'form_var_foo_foo|decimal == 0',
@ -1486,6 +1528,7 @@ def test_decimal_conditions_django(pub, variable_test_data):
condition = Condition({'type': 'django', 'value': condition_value})
assert condition.evaluate() is True
def test_lazy_formdata_mathematics_filters(pub):
formdef = FormDef()
formdef.name = 'foobar'
@ -1517,6 +1560,7 @@ def test_lazy_formdata_mathematics_filters(pub):
tmpl = Template('{{ form_var_term1|divide:form_var_term2 }}')
assert tmpl.render(context) == '0.75'
def test_mathematic_conditions_django(pub, variable_test_data):
for true_condition_value in (
# reminder
@ -1559,6 +1603,7 @@ def test_mathematic_conditions_django(pub, variable_test_data):
condition = Condition({'type': 'django', 'value': false_condition_value})
assert condition.evaluate() is False
def test_lazy_formdata_ceil_filter(pub):
formdef = FormDef()
formdef.name = 'foobar'
@ -1580,6 +1625,7 @@ def test_lazy_formdata_ceil_filter(pub):
tmpl = Template('{{ form_var_value|abs }}')
assert tmpl.render(context) == '3.14'
def test_rounding_and_abs_conditions_django(pub, variable_test_data):
for true_condition_value in (
# reminder
@ -1611,6 +1657,7 @@ def test_rounding_and_abs_conditions_django(pub, variable_test_data):
condition = Condition({'type': 'django', 'value': false_condition_value})
assert condition.evaluate() is False
def test_formdata_user_field(pub, variable_test_data):
local_user = variable_test_data._formdata.user
@ -1636,6 +1683,7 @@ def test_formdata_user_field(pub, variable_test_data):
condition = Condition({'type': 'django', 'value': 'form_user_var_test'})
assert condition.evaluate() is False
def test_string_filters(pub, variable_test_data):
tmpl = Template('{% with form_var_foo_foo|split:"a" as x %}{{x.0}}{% endwith %}', raises=True)
for mode in (None, 'lazy'):
@ -1652,6 +1700,7 @@ def test_string_filters(pub, variable_test_data):
context = pub.substitutions.get_context_variables(mode=mode)
assert tmpl.render(context) == ''
def test_user_label(pub):
from wcs.admin.settings import UserFieldsFormDef
user_formdef = UserFieldsFormDef(pub)

View File

@ -23,10 +23,12 @@ from wcs.fields import StringField, FileField, DateField, ItemField, PageField
from utilities import create_temporary_pub, clean_temporary_pub
def pytest_generate_tests(metafunc):
if 'pub' in metafunc.fixturenames:
metafunc.parametrize('pub', ['pickle', 'sql'], indirect=True)
@pytest.fixture
def pub(request):
pub = create_temporary_pub(sql_mode=(request.param == 'sql'))
@ -37,6 +39,7 @@ def pub(request):
return pub
def teardown_module(module):
clean_temporary_pub()
@ -92,6 +95,7 @@ def test_is_disabled_expiration_datetime(pub):
datetime.datetime.now() + datetime.timedelta(hours=1)).timetuple()[:5]
assert not formdef.is_disabled()
def test_title_change(pub):
formdef = FormDef()
formdef.name = 'foo'
@ -113,6 +117,7 @@ def test_title_change(pub):
assert FormDef.get(formdef.id).name == 'baz'
assert FormDef.get(formdef.id).internal_identifier == 'bar' # didn't change
def test_substitution_variables(pub):
formdef = FormDef()
formdef.name = 'foo'
@ -138,6 +143,7 @@ def test_substitution_variables(pub):
assert formdef.get_substitution_variables()['form_option_bar'] == 'Bar'
assert formdef.get_substitution_variables()['form_option_bar_raw'] == 'bar'
def test_urls(pub):
FormDef.wipe()
formdef = FormDef()
@ -150,6 +156,7 @@ def test_urls(pub):
assert formdef.get_url() == 'https://example.net/foo/'
assert formdef.get_url(backoffice=True) == 'https://example.net/backoffice/management/foo/'
def test_schema_with_date_variable(pub):
FormDef.wipe()
formdef = FormDef()
@ -166,6 +173,7 @@ def test_schema_with_date_variable(pub):
formdef.workflow_options = {'foo': datetime.datetime(2016, 4, 2).timetuple()}
assert json.loads(formdef.export_to_json())['options']['foo'].startswith('2016-04-02')
def test_substitution_variables_object(pub):
formdef = FormDef()
formdef.name = 'foo'
@ -188,6 +196,7 @@ def test_substitution_variables_object(pub):
assert substs.formdef is formdef
def test_file_field_migration(pub):
pub.cfg['filetypes'] = {1:
{'mimetypes': [
@ -217,6 +226,7 @@ def test_file_field_migration(pub):
assert formdef.fields[1].document_type['label'] == 'Image files'
assert formdef.fields[0].document_type['label'] == 'Image files, Documents'
def test_internal_identifier_migration(pub):
FormDef.wipe()
formdef = FormDef()
@ -233,6 +243,7 @@ def test_internal_identifier_migration(pub):
formdef = FormDef.get(formdef.id)
assert formdef.internal_identifier == 'foo'
def test_page_field_migration(pub):
FormDef.wipe()
formdef = FormDef()
@ -392,6 +403,7 @@ def test_unused_file_removal_job(pub):
# 1 attachment
assert len(glob.glob(os.path.join(pub.app_dir, 'unused-files/attachments/*/*'))) == 1
def test_get_formdefs_of_all_kinds(pub):
from wcs.admin.settings import UserFieldsFormDef
from wcs.carddef import CardDef
@ -442,6 +454,7 @@ def test_get_formdefs_of_all_kinds(pub):
('carddef', CardDef),
]
def test_pickle_2to3_conversion(pub):
if six.PY2:
pytest.skip('only relevant for Python 3')

View File

@ -27,35 +27,41 @@ def setup_module(module):
def teardown_module(module):
shutil.rmtree(pub.APP_DIR)
def export_to_indented_xml(formdef, include_id=False):
formdef_xml = ET.fromstring(ET.tostring(formdef.export_to_xml(include_id=include_id)))
indent(formdef_xml)
return formdef_xml
def assert_compare_formdef(formdef1, formdef2, include_id=False):
assert ET.tostring(export_to_indented_xml(formdef1, include_id=include_id)) == \
ET.tostring(export_to_indented_xml(formdef2, include_id=include_id))
assert formdef1.export_to_json(include_id=include_id, indent=2) == \
formdef2.export_to_json(include_id=include_id, indent=2)
def assert_xml_import_export_works(formdef, include_id=False):
formdef_xml = formdef.export_to_xml(include_id=include_id)
formdef2 = FormDef.import_from_xml_tree(formdef_xml, include_id=include_id)
assert_compare_formdef(formdef, formdef2, include_id=include_id)
return formdef2
def assert_json_import_export_works(formdef, include_id=False):
formdef2 = FormDef.import_from_json(
StringIO(formdef.export_to_json(include_id=include_id)), include_id=include_id)
assert_compare_formdef(formdef, formdef2, include_id=include_id)
return formdef2
def test_empty():
formdef = FormDef()
formdef.name = 'empty'
assert_xml_import_export_works(formdef)
assert_json_import_export_works(formdef)
def test_text_attributes():
formdef = FormDef()
formdef.name = 'Foo'
@ -65,6 +71,7 @@ def test_text_attributes():
f2 = assert_json_import_export_works(formdef)
assert f2.url_name == formdef.url_name
def test_empty_description_tag():
formdef = FormDef()
formdef.name = 'empty'
@ -75,6 +82,7 @@ def test_empty_description_tag():
formdef2 = FormDef.import_from_xml_tree(ET.fromstring(export))
assert not formdef2.description
def test_boolean_attributes():
formdef = FormDef()
formdef.name = 'Foo'
@ -88,6 +96,7 @@ def test_boolean_attributes():
assert f2.enable_tracking_codes == formdef.enable_tracking_codes
assert f2.confirmation == formdef.confirmation
def test_a_field():
formdef = FormDef()
formdef.name = 'Foo'
@ -99,6 +108,7 @@ def test_a_field():
f2 = assert_json_import_export_works(formdef)
assert len(f2.fields) == len(formdef.fields)
def test_more_fields():
formdef = FormDef()
formdef.name = 'Blah'
@ -121,6 +131,7 @@ def test_more_fields():
assert f2.fields[3].minimum_date == formdef.fields[3].minimum_date
assert f2.fields[4].items == formdef.fields[4].items
def test_item_radio():
formdef = FormDef()
formdef.name = 'Blah'
@ -153,6 +164,7 @@ def test_item_radio():
fd2 = FormDef.import_from_xml_tree(formdef_xml, include_id=True)
assert fd2.fields[0].display_mode == 'list'
def test_include_id():
formdef = FormDef()
formdef.name = 'Blah'
@ -176,6 +188,7 @@ def test_include_id():
assert f2.fields[0].id == formdef.fields[0].id
assert f2.fields[4].id == formdef.fields[4].id
def test_modification_time():
formdef = FormDef()
formdef.name = 'empty'
@ -184,6 +197,7 @@ def test_modification_time():
f2 = assert_json_import_export_works(formdef)
assert tuple(f2.last_modification_time)[:6] == tuple(formdef.last_modification_time)[:6]
def test_workflow_options():
formdef = FormDef()
formdef.name = 'workflow options'
@ -194,6 +208,7 @@ def test_workflow_options():
fd2 = assert_json_import_export_works(formdef)
assert fd2.workflow_options == formdef.workflow_options
def test_workflow_options_with_no_values():
formdef = FormDef()
formdef.name = 'foo'
@ -204,6 +219,7 @@ def test_workflow_options_with_no_values():
fd2 = assert_json_import_export_works(formdef)
assert fd2.workflow_options == formdef.workflow_options
def test_workflow_options_with_file():
from quixote.http_request import Upload
from wcs.qommon.form import UploadedFile
@ -225,6 +241,7 @@ def test_workflow_options_with_file():
assert formdef.workflow_options['foo'].filename == fd2.workflow_options['foo'].filename
assert formdef.workflow_options['foo'].get_content() == fd2.workflow_options['foo'].get_content()
def test_workflow_options_with_date():
formdef = FormDef()
formdef.name = 'foo'
@ -267,6 +284,7 @@ def test_workflow_reference():
assert FormDef.import_from_xml_tree(formdef_xml_with_id, include_id=False).workflow_id == '2'
assert FormDef.import_from_xml_tree(formdef_xml_with_id, include_id=True).workflow_id is None
def test_category_reference():
Category.wipe()
FormDef.wipe()
@ -315,6 +333,7 @@ def test_file_field():
assert_json_import_export_works(formdef, include_id=True)
assert_json_import_export_works(formdef)
def test_invalid_field_type():
formdef = FormDef()
formdef.name = 'foo'
@ -323,6 +342,7 @@ def test_invalid_field_type():
with pytest.raises(FormdefImportError):
FormDef.import_from_xml(BytesIO(export), include_id=True)
def test_unknown_data_source():
formdef = FormDef()
formdef.name = 'foo'
@ -338,6 +358,7 @@ def test_unknown_data_source():
with pytest.raises(FormdefImportError):
FormDef.import_from_xml(BytesIO(export))
def test_duplicated_field_ids():
formdef = FormDef()
formdef.name = 'foo'
@ -358,6 +379,7 @@ def test_duplicated_field_ids():
assert formdef2.fields[1].id == '2'
assert formdef2.fields[2].id == '3'
def test_wrong_max_field_id():
formdef = FormDef()
formdef.name = 'foo'
@ -370,6 +392,7 @@ def test_wrong_max_field_id():
formdef2 = FormDef.import_from_xml(BytesIO(export), include_id=True)
assert formdef2.max_field_id == 2
def test_page_condition():
formdef = FormDef()
formdef.name = 'foo'
@ -389,6 +412,7 @@ def test_page_condition():
fd2 = FormDef.import_from_xml_tree(formdef_xml, include_id=True)
assert fd2.fields[0].condition == formdef.fields[0].condition
def test_page_post_conditions():
formdef = FormDef()
formdef.name = 'foo'
@ -420,6 +444,7 @@ def test_page_post_conditions():
assert fd2.fields[0].post_conditions[0]['condition'] == {'type': 'python', 'value': 'blah'}
assert fd2.fields[0].post_conditions[0]['error_message'] == ''
def test_workflow_roles():
Role.wipe()
role = Role(name='blah')
@ -451,6 +476,7 @@ def test_workflow_roles():
fd2 = FormDef.import_from_xml_tree(xml_export, include_id=True)
assert fd2.workflow_roles.get('_receiver') is None
def test_geolocations():
formdef = FormDef()
formdef.name = 'foo'
@ -461,6 +487,7 @@ def test_geolocations():
fd3 = assert_json_import_export_works(formdef)
assert fd3.geolocations == formdef.geolocations
def test_user_roles():
Role.wipe()
@ -487,6 +514,7 @@ def test_user_roles():
fd2 = FormDef.import_from_xml_tree(formdef_xml_no_id, include_id=False)
assert fd2.roles == ['logged-users']
def test_backoffice_submission_roles():
Role.wipe()
@ -500,6 +528,7 @@ def test_backoffice_submission_roles():
fd2 = assert_xml_import_export_works(formdef, include_id=True)
assert fd2.backoffice_submission_roles == formdef.backoffice_submission_roles
def test_required_authentication_contexts():
formdef = FormDef()
formdef.name = 'foo'
@ -508,6 +537,7 @@ def test_required_authentication_contexts():
fd2 = assert_xml_import_export_works(formdef, include_id=True)
assert fd2.required_authentication_contexts == formdef.required_authentication_contexts
def test_field_condition():
formdef = FormDef()
formdef.name = 'Foo'
@ -519,6 +549,7 @@ def test_field_condition():
assert len(f2.fields) == len(formdef.fields)
assert f2.fields[0].condition == {'type': 'django', 'value': '1'}
def test_field_validation():
formdef = FormDef()
formdef.name = 'Foo'
@ -554,6 +585,7 @@ def test_field_validation():
assert len(f2.fields) == len(formdef.fields)
assert f2.fields[0].validation == {'type': 'regex', 'value': '\\d'}
def test_digest_template():
formdef = FormDef()
formdef.name = 'Foo'

View File

@ -213,6 +213,7 @@ HOBO_JSON = {
'timestamp': '1431420355.31'
}
def setup_module(module):
global pub, hobo_cmd, alt_tempdir
pub = create_temporary_pub()
@ -221,10 +222,12 @@ def setup_module(module):
hobo_cmd.all_services = HOBO_JSON
alt_tempdir = tempfile.mkdtemp()
def teardown_module(module):
clean_temporary_pub()
shutil.rmtree(alt_tempdir)
def test_configure_site_options():
service = [x for x in HOBO_JSON.get('services', []) if x.get('service-id') == 'wcs'][0]
hobo_cmd.configure_site_options(service, pub)
@ -241,6 +244,7 @@ def test_configure_site_options():
self_domain = urlparse.urlsplit(service.get('base_url')).netloc
assert pub.get_site_option(self_domain, 'wscall-secrets') != '0'
def test_update_configuration():
service = [x for x in HOBO_JSON.get('services', []) if x.get('service-id') == 'wcs'][0]
hobo_cmd.update_configuration(service, pub)
@ -248,6 +252,7 @@ def test_update_configuration():
assert pub.cfg['emails']['footer'] == 'Hello world.'
assert pub.cfg['emails']['from'] == 'noreply@example.net'
def test_update_themes():
pub.cfg['branding'] = {'theme': 'default'}
service = [x for x in HOBO_JSON.get('services', []) if x.get('service-id') == 'wcs'][0]
@ -275,6 +280,7 @@ def test_update_themes():
assert os.readlink(os.path.join(pub.app_dir, 'theme')) == \
os.path.join(hobo_cmd.THEMES_DIRECTORY, 'foobar')
def test_update_profile():
profile = HOBO_JSON.get('profile')
@ -338,6 +344,7 @@ def test_update_profile():
else:
assert attribute_mapping[attribute_name] == field_id
def test_configure_authentication_methods(http_requests):
pub.cfg['idp'] = {}
service = [x for x in HOBO_JSON.get('services', []) if x.get('service-id') == 'wcs'][0]
@ -351,6 +358,7 @@ def test_configure_authentication_methods(http_requests):
assert pub.cfg['sp']['idp-manage-roles']
assert pub.get_site_option('idp_account_url', 'variables').endswith('/accounts/')
def test_deploy():
cleanup()
WcsPublisher.APP_DIR = alt_tempdir
@ -381,6 +389,7 @@ def test_deploy():
pub_cfg = pickle.load(open(os.path.join(alt_tempdir, 'wcs.example.net', 'config.pck'), 'rb'))
assert pub_cfg['language'] == {'language': 'fr'}
def test_configure_postgresql():
cleanup()
WcsPublisher.APP_DIR = alt_tempdir

View File

@ -16,6 +16,7 @@ def pytest_generate_tests(metafunc):
if 'pub' in metafunc.fixturenames:
metafunc.parametrize('pub', ['pickle', 'sql'], indirect=True)
@pytest.fixture
def pub(request):
pub = create_temporary_pub(sql_mode=(request.param == 'sql'))
@ -160,6 +161,7 @@ def test_process_notification_role(pub):
assert Role.select()[0].emails == ['petite-enfance@example.com']
assert Role.select()[0].emails_to_members is True
def test_process_notification_internal_role(pub):
Role.wipe()
@ -186,6 +188,7 @@ def test_process_notification_internal_role(pub):
role = Role.select()[0]
assert role.is_internal()
def test_process_notification_role_description(pub):
User = pub.user_class
@ -437,6 +440,7 @@ PROFILE = {
]
}
def test_process_notification_user_provision(pub):
User = pub.user_class
@ -619,9 +623,11 @@ def test_process_notification_user_provision(pub):
else: # empty value : empty field
assert User.select()[0].form_data['_birthdate'] is None
def notify_of_exception(exc_info, context):
raise Exception(exc_info)
def test_process_notification_user_with_errors(pub):
User = pub.user_class
@ -683,6 +689,7 @@ def test_process_notification_user_with_errors(pub):
assert e.value.args[0][0] == KeyError
assert e.value.args[0][1].args == ('user without uuid',)
def test_process_notification_role_with_errors(pub):
User = pub.user_class
User.wipe()

View File

@ -33,12 +33,15 @@ from django.core.cache import cache
from utilities import get_app, create_temporary_pub, clean_temporary_pub
def setup_module(module):
cleanup()
def teardown_module(module):
clean_temporary_pub()
def test_parse_file_size():
assert FileSizeWidget.parse_file_size('17') == 17
assert FileSizeWidget.parse_file_size('17o') == 17
@ -52,21 +55,25 @@ def test_parse_file_size():
assert FileSizeWidget.parse_file_size('17 K') == 17*10**3
assert FileSizeWidget.parse_file_size(' 17 K ') == 17*10**3
def test_parse_invalid_file_size():
for test_value in ('17i', 'hello', '0.4K', '2G'):
with pytest.raises(ValueError):
FileSizeWidget.parse_file_size(test_value)
def test_humantime():
for x in range(3, 100000, 13):
assert humanduration2seconds(seconds2humanduration(x)) == x
def test_parse_mimetypes():
assert FileTypesDirectory.parse_mimetypes('application/pdf') == ['application/pdf']
assert FileTypesDirectory.parse_mimetypes('.pdf') == ['application/pdf']
assert set(FileTypesDirectory.parse_mimetypes('.pdf, .odt')) == set([
'application/pdf', 'application/vnd.oasis.opendocument.text'])
def test_format_mimetypes():
assert FileTypesDirectory.format_mimetypes(['application/pdf']) == \
'application/pdf (.pdf)'
@ -83,34 +90,41 @@ def test_format_mimetypes():
'application/vnd.openxmlformats-officedocument.wordprocessingml.document (.docx)'\
'...'
def test_simplify_unchanged():
assert simplify('test') == 'test'
assert simplify('another-test') == 'another-test'
assert simplify('another_test', '_') == 'another_test'
def test_simplify_space():
assert simplify('test again') == 'test-again'
assert simplify(' test again ') == 'test-again'
assert simplify('test again', '_') == 'test_again'
assert simplify(' test again ', '_') == 'test_again'
def test_simplify_apostrophes():
assert simplify('test\'again') == 'test-again'
assert simplify('test\'\'\'again') == 'test-again'
def test_simplify_accented():
assert simplify(u'cliché') == 'cliche'
if six.PY2:
assert simplify(u'cliché'.encode('iso-8859-1')) == 'cliche'
def test_simplify_remove():
assert simplify('this is: (a) "test"') == 'this-is-a-test'
assert simplify('a test; again?') == 'a-test-again'
def test_simplify_mix():
assert simplify(u' this is: (a) "cliché" ') == 'this-is-a-cliche'
assert simplify(u' À "cliché"; again? ') == 'a-cliche-again'
def test_json_str_decoder():
json_str = json.dumps({
'lst': [{'a': 'b'}, 1, 2],
@ -125,6 +139,7 @@ def test_json_str_decoder():
assert type(json_loads(json_str)['bla']) is str
assert json_loads(json_str)['bla'] == force_str(u'éléphant')
def test_format_time():
assert format_time(None, '%(month_name)s') == '?'
assert format_time(1500000000, '%(month_name)s') == 'July'
@ -136,6 +151,7 @@ def test_format_time():
assert format_time(time.localtime(1500000000,), '%(month)s') == '7'
assert format_time(time.localtime(1500000000,), '%(weekday_name)s') == 'Friday'
def test_parse_isotime():
assert 1420107019 == parse_isotime('2015-01-01T10:10:19Z')
assert 1420107019 == parse_isotime('2015-01-01T10:10:19+00:00Z')
@ -144,6 +160,7 @@ def test_parse_isotime():
with pytest.raises(ValueError):
parse_isotime('2015-01-0110:10:19Z')
def test_script_substitution_variable():
pub = create_temporary_pub()
pub.substitutions.feed(pub)
@ -173,11 +190,13 @@ def test_script_substitution_variable():
fd.close()
assert variables['script'].hello_world() == 'http://example.net'
def test_default_charset():
pub = create_temporary_pub()
resp = get_app(pub).get('/')
assert 'utf-8' in resp.headers['Content-Type']
def test_age_in_years():
create_temporary_pub()
assert evalutils.age_in_years('2000-01-01', '2016-05-26') == 16
@ -220,6 +239,7 @@ def test_age_in_seconds():
assert evalutils.age_in_seconds(time.struct_time((2000, 1, 1, 0, 0, 0, 0, 0, 0)),
'2000-01-01 01:00') == 3600
def test_date_format():
pub = create_temporary_pub()
pub.cfg['language'] = {}
@ -242,6 +262,7 @@ def test_date_format():
finally:
os.environ = orig_environ
def test_get_as_datetime():
pub = create_temporary_pub()
datetime_value = datetime.datetime(2017, 4, 25, 12, 0)
@ -251,6 +272,7 @@ def test_get_as_datetime():
assert get_as_datetime('2017-04-25T12:00:00') == datetime_value
assert get_as_datetime('25/04/2017 12:00') == datetime_value
def test_pagination():
pub = create_temporary_pub()
req = HTTPRequest(None, {'SERVER_NAME': 'example.net', 'SCRIPT_NAME': ''})
@ -278,6 +300,7 @@ def test_pagination():
assert get_texts(pagination_links(100, 20, 500)) == [
'1', '&#8230;', '3', '4', '5', '6', '7', '8', '9', '&#8230;', '25', '(101-120/500)', 'Per page: ', '10', '20', '50', '100']
def test_email_signature_plain(emails):
pub = create_temporary_pub()
pub.cfg['emails'] = {'footer': 'Footer\nText'}
@ -286,6 +309,7 @@ def test_email_signature_plain(emails):
assert not emails.emails['test']['msg'].is_multipart()
assert b'Footer\nText' in emails.emails['test']['msg'].get_payload(decode=True)
def test_email_from(emails):
pub = create_temporary_pub()
send_email('test', mail_body='Hello', email_rcpt='test@localhost', want_html=False)
@ -306,6 +330,7 @@ def test_email_from(emails):
assert emails.emails['test']['from'] == 'foo@localhost'
assert emails.emails['test']['msg']['From'] in ('=?utf-8?q?HELLO?= <foo@localhost>', 'HELLO <foo@localhost>')
@pytest.mark.skipif('docutils is None')
def test_email_signature_rst(emails):
pub = create_temporary_pub()
@ -319,6 +344,7 @@ def test_email_signature_rst(emails):
assert b'Footer\nText' in emails.emails['test']['msg'].get_payload()[0].get_payload(decode=True)
assert b'>Footer<' in emails.emails['test']['msg'].get_payload()[1].get_payload(decode=True)
@pytest.mark.skipif('docutils is None')
def test_email_signature_rst_pipes(emails):
pub = create_temporary_pub()
@ -332,6 +358,7 @@ def test_email_signature_rst_pipes(emails):
assert b'Footer\nText' in emails.emails['test']['msg'].get_payload()[0].get_payload(decode=True)
assert b'>Footer<' in emails.emails['test']['msg'].get_payload()[1].get_payload(decode=True)
def test_email_plain_with_attachments(emails):
pub = create_temporary_pub()
@ -392,6 +419,7 @@ def test_email_plain_with_attachments(emails):
assert emails.count() == 5
@pytest.mark.skipif('docutils is None')
def test_email_plain_and_html_with_attachments(emails):
pub = create_temporary_pub()
@ -410,10 +438,12 @@ def test_email_plain_and_html_with_attachments(emails):
assert emails.emails['test']['msg'].get_payload()[0].get_payload()[1].get_content_type() == 'text/html'
assert emails.emails['test']['msg'].get_payload()[1].get_content_type() == 'image/jpeg'
def test_cache():
cache.set('hello', 'world')
assert cache.get('hello') == 'world'
def test_normalize_geolocation():
assert normalize_geolocation({'lat': 10.0, 'lon': 0.0}) == {'lat': 10.0, 'lon': 0.0}
assert normalize_geolocation({'lat': -10.0, 'lon': 0.0}) == {'lat': -10.0, 'lon': 0.0}
@ -433,6 +463,7 @@ def test_normalize_geolocation():
assert normalize_geolocation({'lat': 0.0, 'lon': 400.0}) == {'lat': 0.0, 'lon': 40.0}
assert normalize_geolocation({'lat': 0.0, 'lon': -400.0}) == {'lat': 0.0, 'lon': -40.0}
@pytest.mark.skipif('docutils is None')
def test_email_with_enumeration(emails):
pub = create_temporary_pub()
@ -460,6 +491,7 @@ M. Francis Kuntz
assert b'arabic simple' in html
assert b'M. Francis Kuntz' in html
@pytest.mark.skipif('docutils is None')
def test_email_with_unexpected_transition(emails):
pub = create_temporary_pub()
@ -486,6 +518,7 @@ bye,
assert text.count(b'\n ?????????\n') == 1
assert html.count(b'<dd>?????????</dd>') == 1
def test_dict_from_prefix():
d = evalutils.dict_from_prefix('var1', {})
assert d == {}
@ -499,6 +532,7 @@ def test_dict_from_prefix():
d = evalutils.dict_from_prefix('v', {'k1':'v1', 'k2':'v2'})
assert d == {}
def test_objects_repr():
workflow = Workflow(name='wf')
st1 = workflow.add_status('Status1', 'st1')

View File

@ -10,6 +10,7 @@ from wcs import fields
from utilities import create_temporary_pub
def setup_module(module):
cleanup()
@ -20,6 +21,7 @@ def setup_module(module):
req = HTTPRequest(None, {'SCRIPT_NAME': '/', 'SERVER_NAME': 'example.net'})
pub._set_request(req)
@pytest.fixture
def user(request):
pub.user_class.wipe()
@ -29,6 +31,7 @@ def user(request):
get_request()._user = user
return user
def teardown_module(module):
shutil.rmtree(pub.APP_DIR)
@ -38,11 +41,13 @@ def test_prefill_string():
field.prefill = {'type': 'string', 'value': 'test'}
assert field.get_prefill_value() == ('test', False)
def test_prefill_user(user):
field = fields.Field()
field.prefill = {'type': 'user', 'value': 'email'}
assert field.get_prefill_value(user=get_request().user) == ('test@example.net', False)
def test_prefill_user_attribute(user):
from wcs.admin.settings import UserFieldsFormDef
formdef = UserFieldsFormDef(pub)
@ -57,6 +62,7 @@ def test_prefill_user_attribute(user):
user.store()
assert field.get_prefill_value(user=get_request().user) == ('Plop', False)
def test_prefill_verified_user_attribute(user):
from wcs.admin.settings import UserFieldsFormDef
formdef = UserFieldsFormDef(pub)
@ -72,22 +78,26 @@ def test_prefill_verified_user_attribute(user):
user.store()
assert field.get_prefill_value(user=get_request().user) == ('Plop', True)
def test_prefill_formula():
field = fields.Field()
field.prefill = {'type': 'formula', 'value': 'str(2+5)'}
assert field.get_prefill_value() == ('7', False)
def test_prefill_formula_with_error():
field = fields.Field()
field.prefill = {'type': 'formula', 'value': 'foobar'}
assert field.get_prefill_value() == (None, False)
def test_prefill_formula_substitution_variable():
pub.substitutions.get_context_variables = lambda: {'test': 'value'}
field = fields.Field()
field.prefill = {'type': 'formula', 'value': 'test'}
assert field.get_prefill_value() == ('value', False)
def test_prefill_formula_date_value():
pub.substitutions.get_context_variables = lambda: {}
field = fields.Field()
@ -98,6 +108,7 @@ def test_prefill_formula_date_value():
field.prefill = {'type': 'formula', 'value': 'utils.add_days("2016-01-01", 10)'}
assert field.get_prefill_value() == ('2016-01-11', False)
def test_prefill_formula_today_value():
pub.substitutions.get_context_variables = pub.get_substitution_variables
field = fields.Field()
@ -105,6 +116,7 @@ def test_prefill_formula_today_value():
today = datetime.date.today().strftime('%Y-%m-%d')
assert field.get_prefill_value() == (today, False)
def test_prefill_formula_time_value():
pub.substitutions.get_context_variables = lambda: {}
field = fields.Field()

View File

@ -24,6 +24,7 @@ from wcs.qommon.cron import CronJob
from utilities import create_temporary_pub
def setup_module(module):
cleanup()
global pub
@ -31,15 +32,18 @@ def setup_module(module):
pub.cfg['language'] = {'language': 'en'}
pub.write_cfg()
def teardown_module(module):
shutil.rmtree(pub.APP_DIR)
def get_request():
return HTTPRequest(None, {
'SERVER_NAME': 'www.example.net',
'SCRIPT_NAME': '',
})
def test_plaintext_error():
req = get_request()
pub._set_request(req)
@ -62,6 +66,7 @@ def test_plaintext_error():
assert re.findall('File.*?line.*?in test_plaintext_error', s)
assert not re.findall('^>.*\d+.*s = pub._generate_plaintext_error', s, re.MULTILINE)
def test_finish_failed_request():
pub.USE_LONG_TRACES = False
try:
@ -100,6 +105,7 @@ def test_finish_failed_request():
assert 'Traceback (most recent call last)' in str(body)
assert '<div class="error-page">' in str(body)
def test_finish_interrupted_request():
req = HTTPRequest(StringIO(''), {
'SERVER_NAME': 'example.net',
@ -132,6 +138,7 @@ def test_finish_interrupted_request():
})
response = pub.process_request(req)
def test_get_tenants():
pub = create_temporary_pub()
open(os.path.join(pub.APP_DIR, 'xxx'), 'w').close()
@ -141,15 +148,18 @@ def test_get_tenants():
assert not 'xxx' in tenants
assert not 'plop.invalid' in tenants
def test_register_cronjobs():
assert not pub.cronjobs
pub.register_cronjobs()
assert 'apply_global_action_timeouts' in [x.function.__name__ for x in pub.cronjobs]
assert 'clean_sessions' in [x.function.__name__ for x in pub.cronjobs]
def test_get_default_position():
assert pub.get_default_position() == '50.84;4.36'
def test_import_config_zip():
pub = create_temporary_pub()
pub.cfg['sp'] = {'what': 'ever'}
@ -183,6 +193,7 @@ def test_import_config_zip():
assert not isinstance(pub.cfg['language'], unicode)
assert not isinstance(pub.cfg['whatever2'][-1]['c'], unicode)
def test_cron_command():
pub = create_temporary_pub()
with mock.patch('wcs.qommon.management.commands.cron.cron_worker') as cron_worker:

View File

@ -12,10 +12,12 @@ from wcs.qommon.ident.password_accounts import PasswordAccount
from utilities import get_app, create_temporary_pub, clean_temporary_pub
def pytest_generate_tests(metafunc):
if 'pub' in metafunc.fixturenames:
metafunc.parametrize('pub', ['pickle', 'sql'], indirect=True)
@pytest.fixture
def pub(request):
pub = create_temporary_pub(sql_mode=(request.param == 'sql'))
@ -29,9 +31,11 @@ def pub(request):
return pub
def teardown_module(module):
clean_temporary_pub()
def test_no_user_registration(pub):
# makes sure the page is not published unless configured
app = get_app(pub)
@ -42,11 +46,13 @@ def test_no_user_registration(pub):
pub.cfg['identities'] = {'creation': 'self'}
pub.write_cfg()
def test_link_on_login_page(pub):
app = get_app(pub)
page = app.get('/login/')
assert '/register/' in page.text
def test_no_password(pub):
app = get_app(pub)
page = app.get('/register/')
@ -54,6 +60,7 @@ def test_no_password(pub):
assert 'username' in register_form.fields
assert 'password' not in register_form.fields
def test_user_registration_mismatch(pub):
pub.cfg['passwords'] = {'generate': False}
pub.write_cfg()
@ -66,6 +73,7 @@ def test_user_registration_mismatch(pub):
resp = register_form.submit()
assert 'Passwords do not match' in resp.text
def do_user_registration(pub, username='foo', password='bar'):
initial_user_count = pub.user_class.count()
initial_account_count = PasswordAccount.count()
@ -89,6 +97,7 @@ def do_user_registration(pub, username='foo', password='bar'):
user2 = PasswordAccount.get_with_credentials(username, password)
assert user.id == user2.id
def test_user_registration(pub):
pub.user_class.wipe()
PasswordAccount.wipe()
@ -99,6 +108,7 @@ def test_user_registration(pub):
account = PasswordAccount.get('foo')
assert account.password == 'bar' # check it's in clear text
def test_user_password_hashing(pub):
pub.user_class.wipe()
PasswordAccount.wipe()
@ -109,6 +119,7 @@ def test_user_password_hashing(pub):
account = PasswordAccount.get('foo')
assert account.password == hashlib.sha256(b'bar').hexdigest()
def test_user_password_accents(pub):
pub.user_class.wipe()
PasswordAccount.wipe()
@ -120,6 +131,7 @@ def test_user_password_accents(pub):
account = PasswordAccount.get('foo')
assert account.password == password
def test_admin_notification(pub, emails):
pub.cfg['identities'] = {'creation': 'self', 'notify-on-register': True}
pub.write_cfg()
@ -137,6 +149,7 @@ def test_admin_notification(pub, emails):
assert emails.get('New Registration')
assert emails.get('New Registration').get('email_rcpt') == ['admin@localhost']
def test_user_notification(pub, emails):
pub.cfg['identities'] = {'creation': 'self', 'notify-on-register': False,
'email-as-username': True}
@ -158,6 +171,7 @@ def test_user_notification(pub, emails):
assert emails.get('Welcome to example.net').get('to') == 'foo@localhost'
assert account.password in emails.get('Welcome to example.net').get('payload')
def test_user_login(pub):
pub.cfg['identities'] = {'creation': 'self', 'notify-on-register': False}
pub.user_class.wipe()
@ -182,6 +196,7 @@ def test_user_login(pub):
resp = resp.forms[0].submit()
assert resp.location == 'http://example.net/'
def test_forgotten(pub, emails):
pub.cfg['identities'] = {'creation': 'self', 'notify-on-register': False}
pub.user_class.wipe()

View File

@ -7,20 +7,24 @@ from utilities import create_temporary_pub, clean_temporary_pub
from wcs.qommon.storage import StorableObject
from wcs.roles import Role, get_user_roles
def setup_module(module):
pub = create_temporary_pub()
pub.cfg['language'] = {'language': 'en'}
pub.cfg['misc'] = {'charset': 'utf-8'}
def teardown_module(module):
clean_temporary_pub()
def test_slug():
Role.wipe()
role = Role(name='Hello world')
role.store()
assert role.slug == 'hello-world'
def test_duplicated_name():
Role.wipe()
role = Role(name='Hello world')
@ -30,6 +34,7 @@ def test_duplicated_name():
role.store()
assert role.slug == 'hello-world-1'
def test_migrate():
Role.wipe()
role = Role(name='Hello world')
@ -40,6 +45,7 @@ def test_migrate():
assert pickle.load(open(role.get_object_filename(), 'rb')).slug is None
assert Role.get(role.id).slug == 'hello-world'
def test_get_user_roles():
Role.wipe()
Role(name='f1').store()

View File

@ -77,6 +77,7 @@ def test_public_site_anonymous_access():
assert 'href="category1/test-formdef-1/"' in output
assert 'href="category1/test-formdef-2/"' in output
def test_private_site_anonymous_access():
FormDef.wipe()
create_formdef()
@ -86,6 +87,7 @@ def test_private_site_anonymous_access():
with pytest.raises(wcs.forms.root.errors.AccessUnauthorizedError):
output = indexhtml()
def test_semi_private_site_anonymous_access():
FormDef.wipe()
create_formdef()
@ -95,6 +97,7 @@ def test_semi_private_site_anonymous_access():
assert 'href="category1/test-formdef-1/"' not in output
assert 'href="category1/test-formdef-2/"' in output
def test_private_site_authorized_access():
FormDef.wipe()
create_formdef()
@ -105,6 +108,7 @@ def test_private_site_authorized_access():
assert 'href="category1/test-formdef-1/"' in output
assert 'href="category1/test-formdef-2/"' in output
def test_private_site_unauthorized_access():
FormDef.wipe()
create_formdef()
@ -114,6 +118,7 @@ def test_private_site_unauthorized_access():
with pytest.raises(wcs.forms.root.errors.AccessUnauthorizedError):
output = indexhtml(user2)
def test_private_site_semi_authorized_access():
FormDef.wipe()
create_formdef()
@ -125,6 +130,7 @@ def test_private_site_semi_authorized_access():
assert 'href="category1/test-formdef-1/"' in output
assert 'href="category1/test-formdef-2/"' not in output
def test_advertized_site_anonymous_access():
FormDef.wipe()
create_formdef()
@ -137,6 +143,7 @@ def test_advertized_site_anonymous_access():
assert 'href="category1/test-formdef-2/"' not in output
assert 'authentication required' in output # locales ?
def test_advertized_site_user_access():
FormDef.wipe()
create_formdef()
@ -149,6 +156,7 @@ def test_advertized_site_user_access():
assert 'href="category1/test-formdef-2/"' not in output
assert 'authentication required' in output # locales ?
def test_static_directories():
assert get_app(pub).get('/static/css/wcs.css')
assert get_app(pub).get('/static/images/feed-icon-10x10.png')
@ -160,6 +168,7 @@ def test_static_directories():
assert 'Directory listing denied' in get_app(pub).get('/static/css/').text
assert get_app(pub).get('/static/xxx', status=404)
def test_jquery_debug_mode():
FormDef.wipe()
create_formdef()

View File

@ -9,14 +9,17 @@ from wcs.qommon.saml2utils import Metadata
from utilities import create_temporary_pub
def setup_module(module):
cleanup()
global pub
pub = create_temporary_pub()
def teardown_module(module):
shutil.rmtree(pub.APP_DIR)
def test_metadata_generation():
pkey, _ = x509utils.generate_rsa_keypair()
meta = Metadata(publisher=pub,

View File

@ -43,6 +43,7 @@ def pytest_generate_tests(metafunc):
if 'pub' in metafunc.fixturenames:
metafunc.parametrize('pub', ['pickle', 'sql'], indirect=True)
@pytest.fixture
def pub(request):
pub = create_temporary_pub(sql_mode=(request.param == 'sql'))
@ -99,6 +100,7 @@ def setup_idps(pub, idp_number=1):
def teardown_module(module):
clean_temporary_pub()
def test_login(pub):
req = HTTPRequest(None, {
'SERVER_NAME': 'example.net',
@ -111,6 +113,7 @@ def test_login(pub):
assert req.response.headers['location'].startswith('http://sso.example.net/saml2/sso?SAMLRequest')
assert 'rsa-sha256' in req.response.headers['location']
def get_authn_response_msg(pub, ni_format=lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT):
idp_metadata_filepath = os.path.join(pub.app_dir,
'idp-http-sso.example.net-saml2-metadata-metadata.xml')
@ -174,6 +177,7 @@ def get_authn_response_msg(pub, ni_format=lasso.SAML2_NAME_IDENTIFIER_FORMAT_PER
login.buildAuthnResponseMsg()
return login.msgBody
def get_assertion_consumer_request(pub, ni_format=lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT):
req = HTTPRequest(None, {
'SERVER_NAME': 'example.net',
@ -187,6 +191,7 @@ def get_assertion_consumer_request(pub, ni_format=lasso.SAML2_NAME_IDENTIFIER_FO
req.form['SAMLResponse'] = get_authn_response_msg(pub, ni_format=ni_format)
return req
def test_saml_metadata(pub):
req = HTTPRequest(None, {'SERVER_NAME': 'example.net', 'SCRIPT_NAME': '', })
pub._set_request(req)
@ -196,6 +201,7 @@ def test_saml_metadata(pub):
assert '<EntityDescriptor' in body
assert req.response.content_type == 'text/xml'
def test_saml_public_key(pub):
req = HTTPRequest(None, {'SERVER_NAME': 'example.net', 'SCRIPT_NAME': '', })
pub._set_request(req)
@ -205,6 +211,7 @@ def test_saml_public_key(pub):
assert body.startswith('-----BEGIN PUBLIC KEY-----')
assert req.response.content_type == 'application/octet-stream'
def test_assertion_consumer(pub):
req = get_assertion_consumer_request(pub)
saml2 = Saml2Directory()
@ -214,6 +221,7 @@ def test_assertion_consumer(pub):
assert req.response.headers['location'] == 'http://example.net'
assert req.session.user is not None
def test_assertion_consumer_unspecified(pub):
req = get_assertion_consumer_request(pub, ni_format=lasso.SAML2_NAME_IDENTIFIER_FORMAT_UNSPECIFIED)
saml2 = Saml2Directory()
@ -223,6 +231,7 @@ def test_assertion_consumer_unspecified(pub):
assert req.response.headers['location'] == 'http://example.net'
assert req.session.user is not None
def test_assertion_consumer_existing_federation(pub, caplog):
# setup an hobo profile
from wcs.ctl.check_hobos import CmdCheckHobos
@ -281,6 +290,7 @@ def test_assertion_consumer_existing_federation(pub, caplog):
assert req.session.saml_authn_context == lasso.SAML2_AUTHN_CONTEXT_PASSWORD
assert req.session.message is None
def test_assertion_consumer_redirect_after_url(pub):
req = get_assertion_consumer_request(pub)
req.form['RelayState'] = '/foobar/?test=ok'
@ -290,6 +300,7 @@ def test_assertion_consumer_redirect_after_url(pub):
assert req.response.status_code == 303
assert req.response.headers['location'] == 'http://example.net/foobar/?test=ok'
def test_assertion_consumer_full_url_redirect_after_url(pub):
req = get_assertion_consumer_request(pub)
req.form['RelayState'] = 'http://example.org/foobar/?test=ok'
@ -299,6 +310,7 @@ def test_assertion_consumer_full_url_redirect_after_url(pub):
assert req.response.status_code == 303
assert req.response.headers['location'] == 'http://example.org/foobar/?test=ok'
def test_saml_login_page(pub):
resp = get_app(pub).get('/login/')
assert resp.status_int == 302
@ -307,6 +319,7 @@ def test_saml_login_page(pub):
request.initFromQuery(urlparse.urlparse(resp.location).query)
assert request.forceAuthn is False
def test_saml_login_page_force_authn(pub):
resp = get_app(pub).get('/login/?forceAuthn=true')
assert resp.status_int == 302
@ -315,6 +328,7 @@ def test_saml_login_page_force_authn(pub):
request.initFromQuery(urlparse.urlparse(resp.location).query)
assert request.forceAuthn is True
def test_saml_login_page_several_idp(pub):
setup_idps(pub, idp_number=4)
# even if there are multiple IdP, /login/ will initiate SSO with the first
@ -325,6 +339,7 @@ def test_saml_login_page_several_idp(pub):
assert resp.status_int == 302
assert resp.location.startswith('http://%s/saml2/sso?SAMLRequest=' % first_idp_domain)
def test_saml_backoffice_redirect(pub):
resp = get_app(pub).get('/backoffice/')
assert resp.status_int == 302
@ -338,6 +353,7 @@ def test_saml_backoffice_redirect(pub):
request.initFromQuery(urlparse.urlparse(resp.location).query)
assert ':next_url>http://example.net/backoffice/<' in request.getOriginalXmlnode()
def test_saml_register(pub):
get_app(pub).get('/register/', status=404)
pub.cfg['saml_identities'] = {'identity-creation': 'self'}
@ -364,6 +380,7 @@ def test_saml_register(pub):
resp = get_app(pub).get('/register/')
assert resp.location == 'http://sso.example.net/registration?next_url=http%3A%2F%2Fexample.net%2Fregister%2F'
def test_saml_logout(pub):
req = get_assertion_consumer_request(pub)
saml2 = Saml2Directory()
@ -374,6 +391,7 @@ def test_saml_logout(pub):
assert 'rsa-sha256' in req.response.headers['location']
assert req.session.user is None
def test_saml_idp_logout(pub):
req = get_assertion_consumer_request(pub)
saml2 = Saml2Directory()

View File

@ -12,6 +12,7 @@ from wcs import fields
from utilities import create_temporary_pub, clean_temporary_pub, get_app, login
def setup_module():
clean_temporary_pub()
@ -24,6 +25,7 @@ def pytest_generate_tests(metafunc):
if 'pub' in metafunc.fixturenames:
metafunc.parametrize('pub', ['pickle', 'sql'], indirect=True)
@pytest.fixture(scope='function')
def pub(request):
pub = create_temporary_pub(sql_mode=(request.param == 'sql'))
@ -35,6 +37,7 @@ def pub(request):
pub.write_cfg()
return pub
@pytest.fixture
def http_request(pub):
req = HTTPRequest(None, {})
@ -73,6 +76,7 @@ session_max_age: 1
time.sleep(0.6)
assert 'Logout' not in app.get('/')
def test_session_expire(pub, user, app):
login(app, username='foo', password='foo')
assert 'Logout' in app.get('/')
@ -84,6 +88,7 @@ def test_session_expire(pub, user, app):
session.store()
assert 'Logout' not in app.get('/')
def test_sessions_visiting_objects(pub, http_request):
# check it starts with nothing
assert len(pub.get_visited_objects()) == 0
@ -149,6 +154,7 @@ def test_sessions_visiting_objects(pub, http_request):
assert set([x[0] for x in pub.get_object_visitors('formdata-foobar-2')]) == set(['FOO', 'BAR'])
assert set([x[0] for x in pub.get_object_visitors('formdata-foobar-1')]) == set([])
def test_session_do_not_reuse_id(pub, user, app):
pub.session_manager.session_class.wipe()
login(app, username='foo', password='foo')
@ -162,6 +168,7 @@ def test_session_do_not_reuse_id(pub, user, app):
assert resp.status_int == 302
assert pub.session_manager.session_class.count() == 2
def test_session_substitution_variables(pub, user, app):
pub.session_manager.session_class.wipe()
resp = app.get('/')
@ -182,6 +189,7 @@ def test_session_substitution_variables(pub, user, app):
resp = app.get('/foobar/')
assert 'Hello %s' % session_id in resp.text
def test_session_substitution_variables_1st_page_condition(pub, user, app):
pub.session_manager.session_class.wipe()
resp = app.get('/')

View File

@ -35,6 +35,7 @@ try:
except ImportError:
pass
def setup_module(module):
global pub, formdef
@ -55,9 +56,11 @@ def setup_module(module):
]
formdef.store()
def teardown_module(module):
clean_temporary_pub()
@postgresql
def test_sql_table_name_invalid_chars():
test_formdef = FormDef()
@ -68,15 +71,18 @@ def test_sql_table_name_invalid_chars():
data_class = test_formdef.data_class(mode='sql')
assert data_class.count() == 0
@postgresql
def test_sql_data_class():
data_class = formdef.data_class(mode='sql')
@postgresql
def test_sql_count():
data_class = formdef.data_class(mode='sql')
assert data_class.count() == 0
@postgresql
def test_sql_store():
data_class = formdef.data_class(mode='sql')
@ -86,6 +92,7 @@ def test_sql_store():
formdata.store()
assert formdata.id
@postgresql
def test_sql_get():
data_class = formdef.data_class(mode='sql')
@ -99,6 +106,7 @@ def test_sql_get():
assert formdata.user_id == '5'
assert formdata.status == 'wf-0'
@postgresql
def test_sql_store_channel():
data_class = formdef.data_class(mode='sql')
@ -114,17 +122,20 @@ def test_sql_store_channel():
formdata.store()
assert data_class.get(formdata.id).submission_channel is None
@postgresql
def test_sql_get_missing():
data_class = formdef.data_class(mode='sql')
with pytest.raises(KeyError):
data_class.get(123456)
@postgresql
def test_sql_get_missing_ignore_errors():
data_class = formdef.data_class(mode='sql')
assert data_class.get(123456, ignore_errors=True) is None
def check_sql_field(no, value):
data_class = formdef.data_class(mode='sql')
formdata = data_class()
@ -135,40 +146,48 @@ def check_sql_field(no, value):
formdata = data_class.get(id)
assert formdata.data.get(no) == value
@postgresql
def test_sql_field_string():
check_sql_field('0', 'hello world')
check_sql_field('0', 'élo world')
check_sql_field('0', None)
@postgresql
def test_sql_field_email():
check_sql_field('1', 'fred@example.com')
@postgresql
def test_sql_field_text():
check_sql_field('2', 'long text')
check_sql_field('2', 'long tèxt')
@postgresql
def test_sql_field_bool():
check_sql_field('3', False)
check_sql_field('3', True)
@postgresql
def test_sql_field_item():
check_sql_field('4', 'apricot')
@postgresql
def test_sql_field_date():
check_sql_field('5', datetime.date.today().timetuple())
@postgresql
def test_sql_field_items():
check_sql_field('6', ['apricot'])
check_sql_field('6', ['apricot', 'pear'])
check_sql_field('6', ['pomme', 'poire', 'pêche'])
@postgresql
def test_sql_geoloc():
test_formdef = FormDef()
@ -194,6 +213,7 @@ def test_sql_geoloc():
formdata2 = data_class.get(formdata.id)
assert formdata2.geolocations == formdata.geolocations
@postgresql
def test_sql_multi_geoloc():
test_formdef = FormDef()
@ -222,6 +242,7 @@ def test_sql_multi_geoloc():
formdata2 = data_class.get(formdata.id)
assert formdata2.geolocations == {'base': {'lat': 12, 'lon': 21}}
@postgresql
def test_sql_change():
data_class = formdef.data_class(mode='sql')
@ -238,6 +259,7 @@ def test_sql_change():
formdata = data_class.get(id)
assert formdata.data.get('0') == 'test2'
@postgresql
def test_sql_remove():
data_class = formdef.data_class(mode='sql')
@ -253,6 +275,7 @@ def test_sql_remove():
with pytest.raises(KeyError):
data_class.get(id)
@postgresql
def test_sql_wipe():
data_class = formdef.data_class(mode='sql')
@ -263,6 +286,7 @@ def test_sql_wipe():
data_class.wipe()
assert data_class.count() == 0
@postgresql
def test_sql_evolution():
data_class = formdef.data_class(mode='sql')
@ -285,6 +309,7 @@ def test_sql_evolution():
assert len(formdata.evolution) == 2
assert formdata.evolution[-1].comment == 'hello world'
@postgresql
def test_sql_evolution_change():
data_class = formdef.data_class(mode='sql')
@ -314,6 +339,7 @@ def test_sql_evolution_change():
assert len(formdata.evolution) == 2
assert formdata.evolution[-1].comment == 'foobar'
@postgresql
def test_sql_multiple_evolutions():
data_class = formdef.data_class(mode='sql')
@ -336,6 +362,7 @@ def test_sql_multiple_evolutions():
data_class.load_all_evolutions(values)
assert [x._evolution for x in values]
@postgresql
def test_sql_get_ids_with_indexed_value():
data_class = formdef.data_class(mode='sql')
@ -358,6 +385,7 @@ def test_sql_get_ids_with_indexed_value():
ids = data_class.get_ids_with_indexed_value('user_id', '2')
assert set(ids) == set([id2, id3])
@postgresql
def test_sql_get_ids_from_query():
data_class = formdef.data_class(mode='sql')
@ -418,6 +446,7 @@ def test_sql_get_ids_with_indexed_value_dict():
ids = data_class.get_ids_with_indexed_value('workflow_roles', '2')
assert set(ids) == set([id2, id3])
@postgresql
def test_create_user():
sql.SqlUser.wipe()
@ -426,6 +455,7 @@ def test_create_user():
user.name = 'Pierre'
user.store()
@postgresql
def test_get_user():
sql.SqlUser.wipe()
@ -436,6 +466,7 @@ def test_get_user():
assert sql.SqlUser.get(user.id) is not None
@postgresql
def test_get_missing_user():
sql.SqlUser.wipe()
@ -443,12 +474,14 @@ def test_get_missing_user():
with pytest.raises(KeyError):
sql.SqlUser.get(12345)
@postgresql
def test_get_missing_user_ignore_errors():
sql.SqlUser.wipe()
assert sql.SqlUser.get(12345, ignore_errors=True) is None
@postgresql
def test_user_formdef():
sql.SqlUser.wipe()
@ -468,6 +501,7 @@ def test_user_formdef():
del pub.cfg['users']['formdef']
pub.write_cfg()
@postgresql
def test_get_users_with_role():
sql.SqlUser.wipe()
@ -484,6 +518,7 @@ def test_get_users_with_role():
assert len(sql.SqlUser.get_users_with_role(1)) == 1
@postgresql
def test_get_users_with_name_identifier():
sql.SqlUser.wipe()
@ -501,6 +536,7 @@ def test_get_users_with_name_identifier():
assert len(sql.SqlUser.get_users_with_name_identifier('foo')) == 1
assert sql.SqlUser.get_users_with_name_identifier('foo')[0].name == 'Pierre'
@postgresql
def test_get_users_fts():
sql.SqlUser.wipe()
@ -518,6 +554,7 @@ def test_get_users_fts():
assert len(sql.SqlUser.get_ids_from_query('pierre')) == 1
assert sql.SqlUser.get(sql.SqlUser.get_ids_from_query('pierre')[0]).id == user_id
@postgresql
def test_get_users_formdef_fts():
sql.SqlUser.wipe()
@ -542,6 +579,7 @@ def test_get_users_formdef_fts():
del pub.cfg['users']['formdef']
pub.write_cfg()
@postgresql
def test_urlname_change():
global formef
@ -570,6 +608,7 @@ def test_urlname_change():
assert data_class.count() == 1
@postgresql
def test_sql_table_add_and_remove_fields():
test_formdef = FormDef()
@ -623,6 +662,7 @@ def test_sql_table_add_and_remove_fields():
data_class = test_formdef.data_class(mode='sql')
data_class.select()
@postgresql
def test_sql_table_wipe_and_drop():
test_formdef = FormDef()
@ -648,6 +688,7 @@ def test_sql_table_wipe_and_drop():
conn, cur = sql.get_connection_and_cursor()
assert table_exists(cur, test_formdef.table_name)
@postgresql
def test_sql_indexes():
test_formdef = FormDef()
@ -667,6 +708,7 @@ def test_sql_indexes():
conn.commit()
cur.close()
@postgresql
def test_sql_table_select():
test_formdef = FormDef()
@ -695,6 +737,7 @@ def test_sql_table_select():
assert len(data_class.select([st.NotContains('id', [24, 25, 86])])) == 48
assert len(data_class.select([st.NotContains('id', [])])) == 50
@postgresql
def test_sql_table_select_iterator():
test_formdef = FormDef()
@ -723,6 +766,7 @@ def test_sql_table_select_iterator():
assert len(list(data_class.select([st.Less('id', 25), st.GreaterOrEqual('id', 10), lambda x:
x.id >= 15], iterator=True))) == 10
@postgresql
def test_sql_table_select_datetime():
test_formdef = FormDef()
@ -772,6 +816,7 @@ def test_select_limit_offset():
assert [x.id for x in data_class.select(func_clause, order_by='id', offset=10, iterator=iterator)] == list(range(11, 51))
assert len([x.id for x in data_class.select(lambda x: x.id > 10, limit=10, iterator=iterator)]) == 10
@postgresql
def test_select_criteria_intersects():
data_class = formdef.data_class(mode='sql')
@ -835,6 +880,7 @@ def test_select_criteria_or_and():
assert [x.id for x in data_class.select([st.And([
st.Less('id', 10), st.Greater('id', 5)])], order_by='id')] == list(range(6, 10))
@postgresql
def test_select_criteria_null():
test_formdef = FormDef()
@ -855,6 +901,7 @@ def test_select_criteria_null():
assert len(data_class.select([st.Null('submission_channel')])) == 33
assert len(data_class.select([st.NotNull('submission_channel')])) == 17
@postgresql
def test_sql_table_select_bool():
test_formdef = FormDef()
@ -901,6 +948,7 @@ def test_sql_criteria_ilike():
assert [x.id for x in data_class.select([st.ILike('f3', 'bar')], order_by='id')] == list(range(21, 51))
assert [x.id for x in data_class.select([st.ILike('f3', 'BAR')], order_by='id')] == list(range(21, 51))
@postgresql
def test_sql_criteria_fts():
test_formdef = FormDef()
@ -959,23 +1007,27 @@ def test_sql_criteria_fts():
assert data_class.count([st.FtsMatch(user.name)]) == 1
assert data_class.count([st.FtsMatch('Frederic')]) == 1
def table_exists(cur, table_name):
cur.execute('''SELECT COUNT(*) FROM information_schema.tables
WHERE table_name = %s''', (table_name,))
return bool(cur.fetchone()[0] == 1)
def column_exists_in_table(cur, table_name, column_name):
cur.execute('''SELECT COUNT(*) FROM information_schema.columns
WHERE table_name = %s
AND column_name = %s''', (table_name, column_name))
return bool(cur.fetchone()[0] == 1)
def index_exists(cur, index_name):
cur.execute('''SELECT COUNT(*) FROM pg_indexes
WHERE schemaname = 'public'
AND indexname = %s''', (index_name,))
return bool(cur.fetchone()[0] == 1)
@postgresql
def test_sql_level():
conn, cur = sql.get_connection_and_cursor()
@ -996,11 +1048,13 @@ def test_sql_level():
conn.commit()
cur.close()
def migration_level(cur):
cur.execute('SELECT value FROM wcs_meta WHERE key = %s', ('sql_level',))
row = cur.fetchone()
return int(row[0])
@postgresql
def test_migration_1_tracking_code():
conn, cur = sql.get_connection_and_cursor()
@ -1013,6 +1067,7 @@ def test_migration_1_tracking_code():
conn.commit()
cur.close()
@postgresql
def test_migration_2_formdef_id_in_views():
conn, cur = sql.get_connection_and_cursor()
@ -1056,6 +1111,7 @@ def test_migration_2_formdef_id_in_views():
conn.commit()
cur.close()
@postgresql
def test_migration_6_actions_roles():
conn, cur = sql.get_connection_and_cursor()
@ -1081,6 +1137,7 @@ def test_migration_6_actions_roles():
conn.commit()
cur.close()
@postgresql
def test_migration_10_submission_channel():
conn, cur = sql.get_connection_and_cursor()
@ -1106,6 +1163,7 @@ def test_migration_10_submission_channel():
conn.commit()
cur.close()
@postgresql
def test_migration_12_users_fts():
conn, cur = sql.get_connection_and_cursor()
@ -1140,6 +1198,7 @@ def test_migration_12_users_fts():
conn.commit()
cur.close()
@postgresql
def test_migration_21_users_ascii_name():
conn, cur = sql.get_connection_and_cursor()
@ -1174,6 +1233,7 @@ def test_migration_21_users_ascii_name():
conn.commit()
cur.close()
@postgresql
def test_migration_24_evolution_index():
formdef = FormDef()
@ -1200,6 +1260,7 @@ def test_migration_24_evolution_index():
conn.commit()
cur.close()
def drop_formdef_tables():
conn, cur = sql.get_connection_and_cursor()
cur.execute('''SELECT table_name FROM information_schema.tables''')
@ -1262,6 +1323,7 @@ def test_is_at_endpoint():
cur.execute('''SELECT COUNT(*) FROM wcs_all_forms WHERE is_at_endpoint = true''')
assert bool(cur.fetchone()[0] == 2)
@postgresql
def test_views_fts():
drop_formdef_tables()
@ -1289,6 +1351,7 @@ def test_views_fts():
cur.execute('''SELECT COUNT(*) FROM wcs_all_forms WHERE fts @@ plainto_tsquery(%s)''', ('bar',))
assert bool(cur.fetchone()[0] == 1)
@postgresql
def test_select_any_formdata():
drop_formdef_tables()
@ -1350,6 +1413,7 @@ def test_select_any_formdata():
objects2 = sql.AnyFormData.select(order_by='receipt_time', limit=10, offset=20)
assert [(x.formdef_id, x.id) for x in objects2] == [(x.formdef_id, x.id) for x in objects][20:30]
@postgresql
def test_load_all_evolutions_on_any_formdata():
drop_formdef_tables()
@ -1425,6 +1489,7 @@ def test_geoloc_in_global_view():
assert int(objects2[0].geolocations['base']['lat']) == formdata.geolocations['base']['lat']
assert int(objects2[0].geolocations['base']['lon']) == formdata.geolocations['base']['lon']
@postgresql
def test_actions_roles():
drop_formdef_tables()
@ -1484,6 +1549,7 @@ def test_actions_roles():
assert total_count == 1
assert formdatas[0].id == formdata_id
@postgresql
def test_last_update_time():
drop_formdef_tables()
@ -1533,6 +1599,7 @@ def test_last_update_time():
cur.execute('''SELECT id FROM wcs_all_forms WHERE last_update_time = '2015-01-04 00:00' ''')
assert bool(cur.fetchone()[0] == formdata2.id)
@postgresql
def test_view_formdef_name():
drop_formdef_tables()
@ -1567,6 +1634,7 @@ def test_view_formdef_name():
cur.execute('''SELECT formdef_id FROM wcs_all_forms WHERE formdef_name = 'test formdef name 2' ''')
assert bool(str(cur.fetchone()[0]) == str(formdef2.id))
@postgresql
def test_view_user_name():
drop_formdef_tables()
@ -1599,6 +1667,7 @@ def test_view_user_name():
cur.execute('''SELECT user_name FROM wcs_all_forms WHERE id = %s ''', (formdata2.id,))
assert bool(cur.fetchone()[0] == user.name)
@postgresql
def test_select_formdata_after_formdef_removal():
drop_formdef_tables()
@ -1626,6 +1695,7 @@ def test_select_formdata_after_formdef_removal():
objects = sql.AnyFormData.select()
assert len(objects) == 1
@postgresql
def test_views_submission_info():
drop_formdef_tables()
@ -1655,6 +1725,7 @@ def test_views_submission_info():
cur.execute('''SELECT COUNT(*) FROM wcs_all_forms WHERE submission_channel = %s''', ('mail',))
assert bool(cur.fetchone()[0] == 1)
@postgresql
def test_get_formdef_new_id():
test1_formdef = FormDef()
@ -1672,6 +1743,7 @@ def test_get_formdef_new_id():
assert test1_id != test2_formdef.id
assert test1_table_name != test2_formdef.table_name
@postgresql
def test_criticality_levels():
drop_formdef_tables()
@ -1726,6 +1798,7 @@ def test_criticality_levels():
assert objects[-1].get_criticality_level_object().name == 'green'
assert objects[-2].get_criticality_level_object().name == 'green'
@postgresql
def test_view_performances():
pytest.skip('takes too much time')
@ -1867,6 +1940,7 @@ def test_migration_30_anonymize_evo_who():
conn.commit()
cur.close()
@postgresql
def test_migration_31_user_label():
conn, cur = sql.get_connection_and_cursor()

View File

@ -14,6 +14,7 @@ import wcs.qommon.storage as st
from utilities import create_temporary_pub
def setup_module(module):
cleanup()
global pub
@ -33,6 +34,7 @@ class Foobar(StorableObject):
unique_value = None
dict_value = None
def test_store():
test = Foobar()
test.value = 'value'
@ -40,14 +42,17 @@ def test_store():
test.store()
assert test.id == '1'
def test_get():
test = Foobar.get(1)
assert test.value == 'value'
def test_get_on_index():
test = Foobar.get_on_index('unique-value', 'unique_value')
assert test.value == 'value'
def test_remove_self():
test = Foobar.get(1)
test.remove_self()
@ -56,6 +61,7 @@ def test_remove_self():
test = Foobar.get(1, ignore_errors=True)
assert test is None
def test_get_on_index_changes():
test = Foobar()
test.value = 'value'
@ -72,6 +78,7 @@ def test_get_on_index_changes():
with pytest.raises(KeyError):
test = Foobar.get_on_index('unique-value', 'unique_value')
def test_get_with_indexed_value():
Foobar.wipe()
@ -96,6 +103,7 @@ def test_get_with_indexed_value():
assert 'unique-value2' in [x.unique_value for x in tests]
assert 'unique-value3' not in [x.unique_value for x in tests]
def test_get_with_indexed_value_changes():
Foobar.wipe()
@ -127,6 +135,7 @@ def test_get_with_indexed_value_changes():
assert len(tests) == 3
assert 'unique-value3' in [x.unique_value for x in tests]
def test_get_with_indexed_value_dict():
Foobar.wipe()
@ -209,6 +218,7 @@ def test_select():
assert len(Foobar.select([st.Contains('unique_value', [24, 25, 86])])) == 2
assert len(Foobar.select([st.NotContains('unique_value', [24, 25, 86])])) == 48
def test_select_order_by():
Foobar.wipe()
@ -222,6 +232,7 @@ def test_select_order_by():
assert [int(x.id) for x in Foobar.select(order_by='unique_value')] == list(range(50, 0, -1))
assert [int(x.id) for x in Foobar.select(order_by='-unique_value')] == list(range(1, 51))
def test_select_datetime():
Foobar.wipe()
@ -304,6 +315,7 @@ def test_select_criteria_or_and():
assert [int(x.id) for x in Foobar.select([st.And([st.Less('value', 10),
st.Greater('value', 5)])], order_by='id')] == list(range(6, 10))
def test_select_criteria_null():
Foobar.wipe()
@ -320,6 +332,7 @@ def test_select_criteria_null():
assert len(Foobar.select([st.Null('value')])) == 33
assert len(Foobar.select([st.NotNull('value')])) == 17
def test_select_criteria_ilike():
Foobar.wipe()
@ -339,6 +352,7 @@ def test_select_criteria_ilike():
assert [int(x.id) for x in Foobar.select([st.ILike('foo', 'bar')], order_by='id')] == list(range(21, 50))
assert [int(x.id) for x in Foobar.select([st.ILike('foo', 'BAR')], order_by='id')] == list(range(21, 50))
def test_store_async():
Foobar.wipe()
@ -359,6 +373,7 @@ def test_store_async():
test = Foobar.get(1)
assert test.value == 'value'
def test_items():
Foobar.wipe()
@ -368,6 +383,7 @@ def test_items():
assert sorted([(int(x), int(y.id)) for (x, y) in Foobar.items()]) == list(zip(range(1,51), range(1, 51)))
def test_reversed_order():
Foobar.wipe()
@ -378,6 +394,7 @@ def test_reversed_order():
assert len(Foobar.select()) == 50
assert [int(x.id) for x in Foobar.select(order_by='-id', limit=10)] == list(range(50, 40, -1))
def test_destroy_rebuild_index():
test_get_with_indexed_value()
assert os.path.exists(os.path.join(Foobar.get_objects_dir(), '.indexes'))
@ -393,6 +410,7 @@ def test_destroy_rebuild_index():
# the indexes should have been rebuilt automatically
assert os.path.exists(os.path.join(Foobar.get_objects_dir(), '.indexes'))
def test_concurrent_hashed_indexes():
Foobar.wipe()
@ -418,6 +436,7 @@ def test_concurrent_hashed_indexes():
index_selection = set([x.id for x in Foobar.get_with_indexed_value('dict_value', i)])
assert manual_selection == index_selection
def test_umask():
test = Foobar()
test.value = 'value'

View File

@ -2,6 +2,7 @@ import datetime
from wcs.qommon.misc import strftime
def test():
# Make sure that the day names are in order
# from 1/1/1800 until 1/1/2100
@ -30,6 +31,7 @@ def test():
prevday = day
testdate = testdate + one_day
def test_types():
assert strftime('%Y-%m-%d %H:%M:%S', datetime.datetime(2017, 11, 19, 13, 8, 0).timetuple()) == '2017-11-19 13:08:00'
assert strftime('%Y-%m-%d %H:%M:%S', datetime.datetime(2017, 11, 19, 13, 8, 0)) == '2017-11-19 13:08:00'

View File

@ -65,6 +65,7 @@ def test_template():
tmpl = Template('[if-any foo][foo][endif]')
assert tmpl.render({'foo': 'bar'}) == '[if-any foo][foo][endif]'
def test_now_and_today_variables():
# create a today string, verify it contains the year, at least
today = Template('{{d}}').render({'d': datetime.date.today()})
@ -95,6 +96,7 @@ def test_now_and_today_variables():
context = pub.substitutions.get_context_variables(mode=mode)
assert tmpl.render(context) == now
def test_template_templatetag():
# check qommon templatetags are always loaded
tmpl = Template('{{ date|parse_datetime|date:"Y" }}')
@ -104,12 +106,14 @@ def test_template_templatetag():
tmpl = Template('{% load i18n %}{% trans "hello" %}')
assert tmpl.render() == 'hello'
def test_startswith_templatetag():
tmpl = Template('{% if foo|startswith:"bar" %}hello{% endif %}')
assert tmpl.render() == ''
assert tmpl.render({'foo': 'bar-baz'}) == 'hello'
assert tmpl.render({'foo': 'baz-bar'}) == ''
def test_split_templatetag():
tmpl = Template('{{ foo|split|last }}')
assert tmpl.render() == ''
@ -121,6 +125,7 @@ def test_split_templatetag():
assert tmpl.render({'foo': 'bar-baz'}) == 'baz'
assert tmpl.render({'foo': 'baz-bar'}) == 'bar'
def test_strip_templatetag():
tmpl = Template('{{ foo|strip }}')
assert tmpl.render() == ''
@ -132,6 +137,7 @@ def test_strip_templatetag():
assert tmpl.render({'foo': 'XXfoo barXYX'}) == 'foo bar'
assert tmpl.render({'foo': ' foo barXX'}) == ' foo bar'
def test_template_encoding():
# django
tmpl = Template('{{ foo }} à vélo')
@ -286,6 +292,7 @@ def test_datetime_templatetags():
assert tmpl.render({'plop': {'foo': 'bar'}}) == ''
assert tmpl.render() == ''
def test_date_maths():
tmpl = Template('{{ plop|add_days:4 }}')
assert tmpl.render({'plop': '2017-12-21'}) == '2017-12-25'
@ -307,10 +314,12 @@ def test_date_maths():
assert tmpl.render({'plop': '2017-12-21'}) == '2017-12-21 12:30'
assert tmpl.render({'plop': '2017-12-21 18:00'}) == '2017-12-22 06:30'
def test_variable_unicode_error_handling():
tmpl = Template('{{ form_var_éléphant }}')
assert tmpl.render() == ''
def test_decimal_templatetag():
tmpl = Template('{{ plop|decimal }}')
assert tmpl.render({'plop': 'toto'}) == '0'
@ -351,6 +360,7 @@ def test_decimal_templatetag():
tmpl = Template('{% if 3|decimal|decimal == 3 %}hello{% endif %}')
assert tmpl.render() == 'hello'
def test_mathematics_templatetag():
tmpl = Template('{{ term1|add:term2 }}')
@ -415,6 +425,7 @@ def test_mathematics_templatetag():
tmpl = Template('{{ term1|divide:term2|decimal:2 }}')
assert tmpl.render({'term1': 2, 'term2': 3}) == '0.67'
def test_rounding_templatetag():
# ceil
tmpl = Template('{{ value|ceil }}')
@ -448,6 +459,7 @@ def test_rounding_templatetag():
assert tmpl.render({'value': ''}) == '0'
assert tmpl.render({'value': None}) == '0'
def test_abs_templatetag():
tmpl = Template('{{ value|abs }}')
assert tmpl.render({'value': 3.14}) == '3.14'
@ -488,6 +500,7 @@ def test_token_alphanum():
t = Template('{% if token1|token_check:token2 %}ok{% endif %}')
assert t.render({'token1': tokens[0] + ' ', 'token2': tokens[0].lower()}) == 'ok'
def test_distance():
t = Template('{{ "48;2"|distance:"48.1;2.1"|floatformat }}',)
assert t.render() == '13387.2'
@ -517,6 +530,7 @@ def test_distance():
t = Template(tpl,)
assert t.render({'formdata': lazy_formdata, 'coords': '49.1;3.1'}) == ''
def test_get_filter():
tmpl = Template('{{ foo|get:"bar" }}')
assert tmpl.render({'foo': {'bar': 'baz'}}) == 'baz'
@ -524,6 +538,7 @@ def test_get_filter():
tmpl = Template('{{ foo|get:0 }}')
assert tmpl.render({'foo': ['bar', 'baz']}) == 'bar'
def test_reproj():
class MockFormData(object):

View File

@ -7,6 +7,7 @@ from wcs.qommon.admin.texts import TextsDirectory
from utilities import create_temporary_pub, MockSubstitutionVariables
def setup_module(module):
cleanup()
global pub
@ -18,17 +19,21 @@ def setup_module(module):
user = pub.user_class(name='foo')
user.store()
def teardown_module(module):
shutil.rmtree(pub.APP_DIR)
def test_get_html_text_unset():
TextsDirectory.register('foo', 'Foo')
assert TextsDirectory.get_html_text('foo') == ''
def test_get_html_text_default():
TextsDirectory.register('foo2', 'Foo', default='Foo...')
assert TextsDirectory.get_html_text('foo2') == '<div class="text-foo2"><p>Foo...</p></div>'
def test_get_html_text_set():
TextsDirectory.register('foo3', 'Foo', default='Foo...')
pub.cfg['texts'] = {'text-foo3': None}
@ -41,6 +46,7 @@ def test_get_html_text_set():
pub.write_cfg()
assert TextsDirectory.get_html_text('foo3') == '<div class="text-foo3"><div>Bar...</div></div>'
def test_get_html_subst():
# test for variable substitution
TextsDirectory.register('foo4', 'Foo', default='Foo...')

View File

@ -4,17 +4,21 @@ from wcs.formdef import FormDef
from utilities import create_temporary_pub, clean_temporary_pub
def pytest_generate_tests(metafunc):
if 'pub' in metafunc.fixturenames:
metafunc.parametrize('pub', ['pickle', 'sql'], indirect=True)
@pytest.fixture
def pub(request):
return create_temporary_pub(sql_mode=(request.param == 'sql'))
def teardown_module(module):
clean_temporary_pub()
def test_tracking_code(pub):
klass = pub.tracking_code_class
klass.wipe()
@ -46,6 +50,7 @@ def test_tracking_code(pub):
assert klass.get(code.id).formdata.tracking_code == code.id
def test_tracking_code_duplicate(pub):
klass = pub.tracking_code_class
klass.wipe()

View File

@ -58,6 +58,7 @@ def test_get_users_with_role():
assert len(pub.user_class.get_users_with_role(1)) == 1
assert pub.user_class.get_users_with_role(1)[0].name == 'Pierre'
def test_user_formdef_getattr():
from wcs.admin.settings import UserFieldsFormDef
formdef = UserFieldsFormDef(pub)

View File

@ -5,10 +5,12 @@ from wcs.qommon.ezt import EZTException
from utilities import create_temporary_pub, clean_temporary_pub
@pytest.fixture
def pub(request):
return create_temporary_pub()
def teardown_module(module):
clean_temporary_pub()
@ -303,6 +305,7 @@ def test_url_base_and_missing_var(pub):
assert get_variadic_url('{{ url }}foobar/{{ path }}',
{'url': 'http://www.example.net/'}) == 'http://www.example.net/foobar/'
def test_url_bad_syntax(pub):
with pytest.raises(EZTException):
get_variadic_url('[if-any form_avr]https://example.net/[foo]/', {'foo': 'bar'})

View File

@ -18,6 +18,7 @@ from wcs.qommon.http_request import HTTPRequest
from utilities import create_temporary_pub
def setup_module(module):
cleanup()
global pub, req
@ -27,9 +28,11 @@ def setup_module(module):
req.language = None
pub._set_request(req)
def teardown_module(module):
shutil.rmtree(pub.APP_DIR)
class MockHtmlForm(object):
def __init__(self, widget):
widget = copy.deepcopy(widget)
@ -52,6 +55,7 @@ class MockHtmlForm(object):
def get_parsed_query(self):
return parse_query(self.form._request_data()[1], 'utf-8')
def mock_form_submission(req, widget, html_vars={}, click=None, hidden_html_vars={}):
form = MockHtmlForm(widget)
for k, v in html_vars.items():
@ -64,6 +68,7 @@ def mock_form_submission(req, widget, html_vars={}, click=None, hidden_html_vars
else:
req.form = form.get_parsed_query()
def test_stringwidget_values():
widget = StringWidget('test')
form = MockHtmlForm(widget)
@ -83,6 +88,7 @@ def test_stringwidget_values():
mock_form_submission(req, widget, {'test': 'bar'})
assert widget.parse() == 'bar'
def test_stringwidget_required():
widget = StringWidget('test', value='foo', required=True)
mock_form_submission(req, widget, {'test': ''})
@ -93,6 +99,7 @@ def test_stringwidget_required():
assert not widget.has_error()
assert widget.parse() == 'bar'
def test_table_list_rows():
widget = TableListRowsWidget('test', columns=['a', 'b', 'c'])
form = MockHtmlForm(widget)
@ -107,6 +114,7 @@ def test_table_list_rows():
'test$element1$col1': 'foo'})
assert widget.parse() == [[u'bar', None, None], [None, u'foo', None]]
def test_table_list_rows_add_row():
widget = TableListRowsWidget('test', columns=['a', 'b', 'c'])
form = MockHtmlForm(widget)
@ -118,6 +126,7 @@ def test_table_list_rows_add_row():
for col in range(3):
assert 'test$element%d$col%d' % (row, col) in form.as_html
def test_table_list_rows_required():
req.form = {}
widget = TableListRowsWidget('test', columns=['a', 'b', 'c'], required=True)
@ -132,6 +141,7 @@ def test_table_list_rows_required():
widget = TableListRowsWidget('test', columns=['a', 'b', 'c'], required=True)
assert not widget.has_error()
def test_table_list_rows_set_many_values():
widget = TableListRowsWidget('test', columns=['a', 'b', 'c'])
form = MockHtmlForm(widget)
@ -149,6 +159,7 @@ def test_table_list_rows_set_many_values():
form = MockHtmlForm(widget)
assert 'test$element%d$col%d' % (10, 0) in form.as_html
def test_table_widget():
req.form = {}
widget = TableWidget('test', columns=['a', 'b', 'c'], rows=['A', 'B'])
@ -164,6 +175,7 @@ def test_table_widget():
mock_form_submission(req, widget, {'test$c-0-0': 'X', 'test$c-0-1': 'Y'})
assert widget.parse() == [[u'X', u'Y', None], [u'1', None, None]]
def test_passwordentry_widget_success():
widget = PasswordEntryWidget('test')
form = MockHtmlForm(widget)
@ -282,6 +294,7 @@ def test_emailwidget():
mock_form_submission(req, widget, {'test': 'foo@localhost..localdomain'})
assert widget.has_error()
def test_date_widget():
widget = DateWidget('test')
form = MockHtmlForm(widget)
@ -405,6 +418,7 @@ def test_wysiwygwidget():
assert widget.parse() == '<p>bla bla bla</p>'
wcs.qommon.form._sanitizeHTML = sanitize_html
def test_select_widget():
widget = SingleSelectHintWidget('test',
options=[
@ -444,6 +458,7 @@ def test_select_widget():
('peach', 'Peach', 'peach', {'disabled': True})])
assert not widget.has_valid_options()
def test_select_or_other_widget():
widget = SingleSelectWidgetWithOther('test',
options=[('apple', 'Apple'), ('pear', 'Pear'), ('peach', 'Peach')])
@ -563,6 +578,7 @@ def test_computed_expression_widget():
assert widget.has_error()
assert widget.get_error().startswith('syntax error in ezt template')
def test_wcsextrastringwidget():
widget = WcsExtraStringWidget('test', value='foo', required=True)
mock_form_submission(req, widget, {'test': ''})
@ -573,6 +589,7 @@ def test_wcsextrastringwidget():
assert not widget.has_error()
assert widget.parse() == 'bar'
def test_wcsextrastringwidget_regex_validation():
# check regex validation
class FakeField: pass
@ -610,6 +627,7 @@ def test_wcsextrastringwidget_regex_validation():
mock_form_submission(req, widget, {'test': '12,34'})
assert widget.has_error()
def test_wcsextrastringwidget_builtin_validation():
class FakeField: pass
fakefield = FakeField()
@ -636,6 +654,7 @@ def test_wcsextrastringwidget_builtin_validation():
mock_form_submission(req, widget, {'test': '1234'})
assert widget.has_error()
def test_wcsextrastringwidget_siren_validation():
class FakeField: pass
fakefield = FakeField()
@ -824,6 +843,7 @@ def test_widgetdict_widget():
html_frags.index('name="test$element2key"') < # b
html_frags.index('name="test$element1key"')) # c
def test_map_widget():
widget = MapWidget('test', title='Map')
form = MockHtmlForm(widget)

View File

@ -25,34 +25,41 @@ from wcs.qommon.misc import indent_xml as indent
from utilities import create_temporary_pub, clean_temporary_pub
@pytest.fixture
def pub(request):
return create_temporary_pub()
def teardown_module(module):
clean_temporary_pub()
def export_to_indented_xml(workflow, include_id=False):
workflow_xml = workflow.export_to_xml(include_id=include_id)
indent(workflow_xml)
return workflow_xml
def assert_import_export_works(wf, include_id=False):
wf2 = Workflow.import_from_xml_tree(
ET.fromstring(ET.tostring(wf.export_to_xml(include_id))), include_id)
assert ET.tostring(export_to_indented_xml(wf)) == ET.tostring(export_to_indented_xml(wf2))
return wf2
def test_empty(pub):
wf = Workflow(name='empty')
assert_import_export_works(wf)
def test_status(pub):
wf = Workflow(name='status')
st1 = wf.add_status('Status1', 'st1')
st2 = wf.add_status('Status2', 'st2')
assert_import_export_works(wf)
def test_status_actions(pub):
wf = Workflow(name='status')
st1 = wf.add_status('Status1', 'st1')
@ -66,6 +73,7 @@ def test_status_actions(pub):
assert_import_export_works(wf)
def test_status_colour_css_class(pub):
wf = Workflow(name='status')
st1 = wf.add_status('Status1', 'st1')
@ -74,6 +82,7 @@ def test_status_colour_css_class(pub):
st2 = wf.add_status('Status2', 'st2')
assert_import_export_works(wf)
def test_status_forced_endpoint(pub):
wf = Workflow(name='status')
st1 = wf.add_status('Status1', 'st1')
@ -83,6 +92,7 @@ def test_status_forced_endpoint(pub):
assert wf2.possible_status[0].forced_endpoint is True
assert wf2.possible_status[1].forced_endpoint is False
def test_default_wf(pub):
wf = Workflow.get_default_workflow()
assert_import_export_works(wf)
@ -136,6 +146,7 @@ def test_action_dispatch(pub):
wf2 = assert_import_export_works(wf, include_id=True)
assert wf2.possible_status[0].items[0].role_id == 'Rolé [form_var_foo]'
def test_status_actions_named_role(pub):
wf = Workflow(name='status')
st1 = wf.add_status('Status1', 'st1')
@ -379,6 +390,7 @@ def test_variables_formdef(pub):
wf2 = assert_import_export_works(wf)
assert wf2.variables_formdef.fields[0].label == 'Test'
def test_wscall_action(pub):
wf = Workflow(name='status')
st1 = wf.add_status('Status1', 'st1')
@ -403,6 +415,7 @@ def test_wscall_action(pub):
assert wscall2.post_data == {'one': '1', 'two': '=2', 'good:name': 'ok'}
assert wscall2.qs_data == {'one': '2', 'two': '=3', 'good:name': 'ok'}
def test_backoffice_info_text(pub):
wf = Workflow(name='info texts')
st1 = wf.add_status('Status1', 'st1')
@ -419,6 +432,7 @@ def test_backoffice_info_text(pub):
assert wf2.possible_status[0].backoffice_info_text == '<p>Foo</p>'
assert wf2.possible_status[0].items[0].backoffice_info_text == '<p>Bar</p>'
def test_global_actions(pub):
role = Role()
role.id = '5'
@ -444,6 +458,7 @@ def test_global_actions(pub):
wf2 = assert_import_export_works(wf, True)
def test_backoffice_fields(pub):
wf = Workflow(name='bo fields')
wf.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(wf)
@ -453,6 +468,7 @@ def test_backoffice_fields(pub):
]
wf2 = assert_import_export_works(wf, True)
def test_complex_dispatch_action(pub):
wf = Workflow(name='status')
st1 = wf.add_status('Status1', 'st1')
@ -510,6 +526,7 @@ def test_complex_dispatch_action(pub):
xml_export = export_to_indented_xml(wf, include_id=True)
assert xml_export.find('possible_status/status/items/item/rules') is None
def test_display_message_action(pub):
wf = Workflow(name='status')
st1 = wf.add_status('Status1', 'st1')
@ -529,6 +546,7 @@ def test_display_message_action(pub):
wf2 = assert_import_export_works(wf, include_id=True)
def test_sendmail_other_destination(pub):
wf = Workflow(name='status')
st1 = wf.add_status('Status1', 'st1')
@ -547,6 +565,7 @@ def test_sendmail_other_destination(pub):
assert Role.count() == 0
assert wf2.possible_status[0].items[0].to == sendmail.to
def test_sendmail_attachments(pub):
wf = Workflow(name='status')
st1 = wf.add_status('Status1', 'st1')
@ -563,6 +582,7 @@ def test_sendmail_attachments(pub):
wf2 = assert_import_export_works(wf)
assert wf2.possible_status[0].items[0].attachments == []
def test_sms(pub):
wf = Workflow(name='status')
st1 = wf.add_status('Status1', 'st1')
@ -578,6 +598,7 @@ def test_sms(pub):
assert Role.count() == 0
assert wf2.possible_status[0].items[0].to == sendsms.to
def test_criticality_level(pub):
wf = Workflow(name='criticality level')
wf.criticality_levels = [
@ -590,6 +611,7 @@ def test_criticality_level(pub):
assert wf2.criticality_levels[0].name == 'green'
assert wf2.criticality_levels[1].name == 'yellow'
def test_global_timeout_trigger(pub):
wf = Workflow(name='global actions')
ac1 = wf.add_global_action('Action', 'ac1')
@ -601,6 +623,7 @@ def test_global_timeout_trigger(pub):
assert wf2.global_actions[0].triggers[-1].id == trigger.id
assert wf2.global_actions[0].triggers[-1].anchor == trigger.anchor
def test_global_webservice_trigger(pub):
wf = Workflow(name='global actions')
ac1 = wf.add_global_action('Action', 'ac1')
@ -611,6 +634,7 @@ def test_global_webservice_trigger(pub):
assert wf2.global_actions[0].triggers[-1].id == trigger.id
assert wf2.global_actions[0].triggers[-1].identifier == trigger.identifier
def test_profile_action(pub):
wf = Workflow(name='status')
st1 = wf.add_status('Status1', 'st1')
@ -625,6 +649,7 @@ def test_profile_action(pub):
item2 = wf2.possible_status[0].items[0]
assert item2.fields == [{'field_id': '__email', 'value': '=form_var_foo'}]
def test_set_backoffice_fields_action(pub):
wf = Workflow(name='status')
st1 = wf.add_status('Status1', 'st1')
@ -639,6 +664,7 @@ def test_set_backoffice_fields_action(pub):
item2 = wf2.possible_status[0].items[0]
assert item2.fields == [{'field_id': 'bo1', 'value': '=form_var_foo'}]
def test_action_condition(pub):
wf = Workflow(name='status')
st1 = wf.add_status('Status1', 'st1')

View File

@ -51,16 +51,20 @@ from wcs.wf.notification import SendNotificationWorkflowStatusItem
from utilities import (create_temporary_pub, MockSubstitutionVariables,
clean_temporary_pub)
def setup_module(module):
cleanup()
def teardown_module(module):
clean_temporary_pub()
def pytest_generate_tests(metafunc):
if 'two_pubs' in metafunc.fixturenames:
metafunc.parametrize('two_pubs', ['pickle', 'sql'], indirect=True)
@pytest.fixture
def pub(request):
pub = create_temporary_pub()
@ -74,6 +78,7 @@ def pub(request):
pub.set_config(req)
return pub
@pytest.fixture
def two_pubs(request):
pub = create_temporary_pub(sql_mode=(request.param == 'sql'))
@ -87,6 +92,7 @@ def two_pubs(request):
pub.set_config(req)
return pub
def test_get_json_export_dict(pub):
workflow = Workflow(name='wf')
st1 = workflow.add_status('Status1', 'st1')
@ -119,6 +125,7 @@ def test_get_json_export_dict(pub):
assert root['statuses'][1]['forced_endpoint'] is True
assert root['statuses'][1]['endpoint'] is True
def test_variable_compute(pub):
FormDef.wipe()
formdef = FormDef()
@ -175,6 +182,7 @@ def test_variable_compute(pub):
assert item.compute('{{ form_var_foo|safe }}') == '<b>hello</b>' # no escaping (implicit |safe)
assert item.compute('{{ form_var_foo|escape }}') == '&lt;b&gt;hello&lt;/b&gt;' #escaping
def test_variable_compute_dates(pub):
FormDef.wipe()
formdef = FormDef()
@ -193,6 +201,7 @@ def test_variable_compute_dates(pub):
assert item.compute('=date(form_var_foo) + days(1)') == datetime.date(2017, 7, 18)
assert item.compute('=date(2017, 7, 18)') == datetime.date(2017, 7, 18)
def test_jump_nothing(pub):
FormDef.wipe()
formdef = FormDef()
@ -202,6 +211,7 @@ def test_jump_nothing(pub):
item = JumpWorkflowStatusItem()
assert item.must_jump(formdata) is True
def test_jump_datetime_condition(pub):
FormDef.wipe()
formdef = FormDef()
@ -219,6 +229,7 @@ def test_jump_datetime_condition(pub):
tomorrow.timetuple()[:3]}
assert item.must_jump(formdata) is False
def test_jump_date_conditions(pub):
FormDef.wipe()
formdef = FormDef()
@ -264,6 +275,7 @@ def test_jump_date_conditions(pub):
'value': 'utils.time_delta(utils.time.localtime(), "2015-01-04").days > 0'}
assert item.must_jump(formdata) is True
def test_jump_count_condition(pub):
FormDef.wipe()
formdef = FormDef()
@ -283,6 +295,7 @@ def test_jump_count_condition(pub):
item.condition = {'type': 'python', 'value': 'form_objects.count < 2'}
assert item.must_jump(formdata) is False
def test_jump_bad_python_condition(pub):
FormDef.wipe()
formdef = FormDef()
@ -315,6 +328,7 @@ def test_jump_bad_python_condition(pub):
assert logged_error.expression == '~ invalid ~'
assert logged_error.expression_type == 'python'
def test_jump_django_conditions(pub):
FormDef.wipe()
formdef = FormDef()
@ -351,6 +365,7 @@ def test_jump_django_conditions(pub):
assert logged_error.expression == '~ invalid ~'
assert logged_error.expression_type == 'django'
def test_check_auth(pub):
user = pub.user_class(name='foo')
user.store()
@ -398,6 +413,7 @@ def test_check_auth(pub):
formdata.workflow_roles = None
assert status_item.check_auth(formdata, user) is True
def test_dispatch(pub):
formdef = FormDef()
formdef.name = 'baz'
@ -419,6 +435,7 @@ def test_dispatch(pub):
item.perform(formdata)
assert formdata.workflow_roles == {'_receiver': role.id}
def test_dispatch_auto(pub):
formdef = FormDef()
formdef.name = 'baz'
@ -478,6 +495,7 @@ def test_dispatch_auto(pub):
item.perform(formdata)
assert formdata.workflow_roles == {'_receiver': role2.id}
def test_dispatch_computed(pub, caplog):
pub.cfg['debug'] = {'logger': True}
pub.write_cfg()
@ -518,6 +536,7 @@ def test_dispatch_computed(pub, caplog):
assert not formdata.workflow_roles
assert caplog.records[-1].message == 'error in dispatch, missing role (="foobar")'
def test_roles(pub):
user = pub.user_class()
user.store()
@ -559,6 +578,7 @@ def test_roles(pub):
item.perform(formdata)
assert pub.user_class.get(user.id).roles == ['2']
def test_add_remove_computed_roles(pub):
user = pub.user_class()
user.store()
@ -605,6 +625,7 @@ def test_add_remove_computed_roles(pub):
item.perform(formdata)
assert pub.user_class.get(user.id).roles == [role2.id]
def test_roles_idp(pub):
pub.cfg['sp'] = {'idp-manage-user-attributes': True}
pub.cfg['idp'] = {'xxx': {'metadata_url': 'http://idp.example.net/idp/saml2/metadata'}}
@ -680,6 +701,7 @@ def test_roles_idp(pub):
item2.perform(formdata)
assert pub.user_class.get(user.id).roles == []
def test_anonymise(two_pubs):
# build a backoffice field
Workflow.wipe()
@ -725,6 +747,7 @@ def test_anonymise(two_pubs):
assert formdef.data_class().get(formdata.id).workflow_data is None
assert formdef.data_class().get(formdata.id).evolution[0].who is None
def test_remove(pub):
formdef = FormDef()
formdef.name = 'baz'
@ -750,6 +773,7 @@ def test_remove(pub):
req.response.filter = {}
assert req.session.message
def test_register_comment(pub):
pub.substitutions.feed(MockSubstitutionVariables())
@ -832,6 +856,7 @@ def test_register_comment(pub):
formdata.evolution[-1]._display_parts = None
assert formdata.evolution[-1].display_parts()[-1] == '<div>1 &lt; 3</div>'
def test_register_comment_django_escaping(pub, emails):
formdef = FormDef()
formdef.name = 'baz'
@ -857,6 +882,7 @@ def test_register_comment_django_escaping(pub, emails):
formdata.evolution[-1]._display_parts = None
assert formdata.evolution[-1].display_parts()[-1] == '<div><p>hello</p></div>'
def test_register_comment_attachment(pub):
pub.substitutions.feed(MockSubstitutionVariables())
@ -1199,6 +1225,7 @@ def test_email(pub, emails):
assert emails.count() == 1
assert emails.get('foobar').get('from') == 'foobar@localhost'
def test_email_django_escaping(pub, emails):
formdef = FormDef()
formdef.name = 'baz'
@ -1252,6 +1279,7 @@ def test_email_django_escaping(pub, emails):
assert emails.count() == 1
assert emails.get('1 < 3')
def test_email_attachments(pub, emails):
formdef = FormDef()
formdef.name = 'baz'
@ -1706,6 +1734,7 @@ def test_webservice_call(http_requests, pub):
payload = json.loads(http_requests.get_last('body'))
assert payload == {'one': 1, 'str': 'abcd', 'evalme': formdata.get_display_id()}
def test_webservice_waitpoint(pub):
item = WebserviceCallStatusItem()
assert item.waitpoint
@ -1718,6 +1747,7 @@ def test_webservice_waitpoint(pub):
item.action_on_network_errors = ':stop'
assert item.waitpoint
def test_webservice_call_error_handling(http_requests, pub):
pub.substitutions.feed(MockSubstitutionVariables())
@ -1944,6 +1974,7 @@ def test_webservice_call_error_handling(http_requests, pub):
assert 'ConnectionError: error\n' in formdata.evolution[-1].parts[-1].summary
assert formdata.workflow_data['plop_connection_error'] == 'error'
def test_webservice_call_store_in_backoffice_filefield(http_requests, pub):
wf = Workflow(name='wscall to backoffice file field')
wf.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(wf)
@ -2052,6 +2083,7 @@ def test_webservice_target_status(pub):
assert targets.count(status1) == 2
assert targets.count(status2) == 2
def test_timeout(two_pubs):
workflow = Workflow(name='timeout')
st1 = workflow.add_status('Status1', 'st1')
@ -2090,6 +2122,7 @@ def test_timeout(two_pubs):
formdef.store()
_apply_timeouts(two_pubs)
def test_legacy_timeout(pub):
workflow = Workflow(name='timeout')
st1 = workflow.add_status('Status1', 'st1')
@ -2121,6 +2154,7 @@ def test_legacy_timeout(pub):
assert formdef.data_class().get(formdata_id).status == 'wf-st2'
def test_timeout_then_remove(two_pubs):
workflow = Workflow(name='timeout-then-remove')
st1 = workflow.add_status('Status1', 'st1')
@ -2159,6 +2193,7 @@ def test_timeout_then_remove(two_pubs):
assert not str(formdata_id) in [str(x) for x in formdef.data_class().keys()]
def test_timeout_with_mark(two_pubs):
workflow = Workflow(name='timeout')
st1 = workflow.add_status('Status1', 'st1')
@ -2193,6 +2228,7 @@ def test_timeout_with_mark(two_pubs):
formdata = formdef.data_class().get(formdata_id)
assert formdata.workflow_data.get('_markers_stack') == [{'status_id': 'st1'}]
def test_sms(pub, sms_mocking):
pub.cfg['sms'] = {'mode': 'xxx'}
formdef = FormDef()
@ -2244,6 +2280,7 @@ def test_sms(pub, sms_mocking):
item.perform(formdata) # nothing
assert len(sms_mocking.sms) == 4
def test_sms_with_passerelle(pub):
pub.cfg['sms'] = {'mode': 'passerelle',
'passerelle_url': 'http://passerelle.example.com/send?nostop=1',
@ -2277,6 +2314,7 @@ def test_sms_with_passerelle(pub):
assert json_payload['to'] == ['1234']
assert json_payload['from'] == 'Passerelle'
def test_display_form(two_pubs):
formdef = FormDef()
formdef.name = 'baz'
@ -2329,6 +2367,7 @@ def test_display_form(two_pubs):
two_pubs.cfg['language'] = {'language': 'en'}
def test_display_form_and_comment(pub):
role = Role(name='bar1')
role.store()
@ -2374,6 +2413,7 @@ def test_display_form_and_comment(pub):
assert 'Test' in str(form.widgets[0].render())
assert '<textarea' in str(form.widgets[1].render())
def test_display_form_migration(pub):
wf = Workflow(name='status')
st1 = wf.add_status('Status1', 'st1')
@ -2439,6 +2479,7 @@ def test_choice_button_no_label(pub):
assert str(form.render()).count('<button') == 1
assert '>TEST</button>' in str(form.render())
def test_workflow_role_type_migration(pub):
workflow = Workflow(name='role migration')
st1 = workflow.add_status('Status1', 'st1')
@ -2454,6 +2495,7 @@ def test_workflow_role_type_migration(pub):
reloaded_workflow = Workflow.get(workflow.id)
assert reloaded_workflow.possible_status[0].items[0].by == ['1', '2']
def test_workflow_display_message(pub):
pub.substitutions.feed(MockSubstitutionVariables())
@ -2492,6 +2534,7 @@ def test_workflow_display_message(pub):
display_message.message = '[foo]'
assert display_message.get_message(formdata) == '1 &lt; 3'
def test_workflow_display_message_to(pub):
workflow = Workflow(name='display message to')
st1 = workflow.add_status('Status1', 'st1')
@ -2573,6 +2616,7 @@ def test_workflow_display_message_to(pub):
assert 'd1' in formdata.get_workflow_messages()
assert 'd2' in formdata.get_workflow_messages()
def test_workflow_display_message_line_details(pub):
workflow = Workflow(name='display message to')
st1 = workflow.add_status('Status1', 'st1')
@ -2592,6 +2636,7 @@ def test_workflow_display_message_line_details(pub):
display_message.to = [role.id]
assert display_message.get_line_details() == 'with actions, for foorole'
def test_workflow_roles(pub, emails):
pub.substitutions.feed(MockSubstitutionVariables())
@ -2648,6 +2693,7 @@ def test_workflow_roles(pub, emails):
assert substvars.get('form_role_slug_with_dash_name') == 'foo'
assert substvars.get('form_role_slug_with_dash_details') == 'Hello World'
def test_criticality(pub):
FormDef.wipe()
@ -2695,6 +2741,7 @@ def test_criticality(pub):
item.perform(formdata)
assert formdata.get_criticality_level_object().name == 'green'
def test_geolocate_address(pub):
formdef = FormDef()
formdef.geolocations = {'base': 'bla'}
@ -2791,6 +2838,7 @@ def test_geolocate_address(pub):
item.perform(formdata)
assert formdata.geolocations == {}
def test_geolocate_image(pub):
formdef = FormDef()
formdef.name = 'baz'
@ -2837,6 +2885,7 @@ def test_geolocate_image(pub):
item.perform(formdata)
assert formdata.geolocations == {}
def test_geolocate_map(pub):
formdef = FormDef()
formdef.name = 'baz'
@ -2866,6 +2915,7 @@ def test_geolocate_map(pub):
item.perform(formdata)
assert formdata.geolocations == {}
def test_geolocate_overwrite(pub):
formdef = FormDef()
formdef.name = 'baz'
@ -2900,6 +2950,7 @@ def test_geolocate_overwrite(pub):
assert int(formdata.geolocations['base']['lat']) == 48
assert int(formdata.geolocations['base']['lon']) == 3
@pytest.mark.skipif(transform_to_pdf is None, reason='libreoffice not found')
def test_transform_to_pdf():
instream = open(os.path.join(os.path.dirname(__file__), 'template.odt'), 'rb')
@ -2907,6 +2958,7 @@ def test_transform_to_pdf():
assert outstream is not False
assert outstream.read(10).startswith(b'%PDF-')
def test_export_to_model_image(pub):
formdef = FormDef()
formdef.name = 'baz'
@ -2965,6 +3017,7 @@ def test_export_to_model_image(pub):
assert formdata.evolution[-1].parts[-1].base_filename == 'formulaire-%s-%s-2.odt' % (formdef.id,
formdata.id)
def test_export_to_model_backoffice_field(pub):
wf = Workflow(name='email with attachments')
wf.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(wf)
@ -3030,6 +3083,7 @@ def test_export_to_model_backoffice_field(pub):
item.perform(formdata)
assert formdata.data == {}
def test_export_to_model_django_template(pub):
formdef = FormDef()
formdef.name = 'foo-export-to-template-with-django'
@ -3073,6 +3127,7 @@ def test_export_to_model_django_template(pub):
new_content = zipfile.ZipFile(open(formdata.evolution[0].parts[2].filename, 'rb')).read('content.xml')
assert b'>A &lt;&gt; name<' in new_content
def test_global_timeouts(two_pubs):
pub = two_pubs
FormDef.wipe()
@ -3291,6 +3346,7 @@ def test_global_timeouts(two_pubs):
assert formdef.data_class().get(formdata1.id).get_criticality_level_object().name == 'green'
formdata1.store()
def test_profile(two_pubs):
User = two_pubs.user_class
user = User()
@ -3505,6 +3561,7 @@ def test_set_backoffice_field(http_requests, two_pubs):
assert logged_error.exception_class == 'TemplateError'
assert logged_error.exception_message.startswith('syntax error in Django template')
def test_set_backoffice_field_file(http_requests, two_pubs):
Workflow.wipe()
FormDef.wipe()
@ -3651,6 +3708,7 @@ def test_set_backoffice_field_file(http_requests, two_pubs):
assert formdata.data.get('bo1') is None
assert formdata.data.get('bo3') is None
def test_set_backoffice_field_item(two_pubs):
Workflow.wipe()
FormDef.wipe()
@ -3756,6 +3814,7 @@ def test_set_backoffice_field_item(two_pubs):
assert formdata.data.get('bo1_display') is None
assert formdata.data.get('bo1_structured') is None
def test_set_backoffice_field_items(two_pubs):
Workflow.wipe()
FormDef.wipe()
@ -3832,6 +3891,7 @@ def test_set_backoffice_field_items(two_pubs):
assert {'id': 'a', 'more': 'aaa', 'text': 'aa'} in formdata.data['bo1_structured']
assert {'id': 'c', 'more': 'ccc', 'text': 'cc'} in formdata.data['bo1_structured']
def test_set_backoffice_field_date(two_pubs):
Workflow.wipe()
FormDef.wipe()
@ -3964,6 +4024,7 @@ def test_set_backoffice_field_immediate_use(http_requests, two_pubs):
assert formdata.data.get('bo1') == 'XHELLOX'
assert formdata.data.get('bo2') == 'YXHELLOXY'
def test_redirect_to_url(pub):
formdef = FormDef()
formdef.name = 'baz'
@ -3995,6 +4056,7 @@ def test_redirect_to_url(pub):
pub.substitutions.feed(formdata)
assert item.perform(formdata) == None
def test_workflow_jump_condition_migration(pub):
workflow = Workflow(name='jump condition migration')
st1 = workflow.add_status('Status1', 'st1')
@ -4014,6 +4076,7 @@ def test_workflow_jump_condition_migration(pub):
assert reloaded_workflow.possible_status[0].items[0].condition == {
'type': 'python', 'value': 'foobar'}
def test_workflow_action_condition(two_pubs):
pub = two_pubs
pub._set_request(None) # to avoid after jobs
@ -4089,6 +4152,7 @@ def test_workflow_action_condition(two_pubs):
assert logged_error.expression == 'foobar == barfoo'
assert logged_error.expression_type == 'python'
def test_notifications(pub, http_requests):
formdef = FormDef()
formdef.name = 'baz'
@ -4159,6 +4223,7 @@ def test_notifications(pub, http_requests):
'https://portal/api/notification/add/?NameID=xxy1',
'https://portal/api/notification/add/?NameID=xxy2'])
def test_workflow_field_migration(pub):
Workflow.wipe()
wf = Workflow(name='wf with backoffice field')

View File

@ -110,6 +110,7 @@ def test_webservice_post_with_no_payload(http_requests, pub):
wscall.call()
assert http_requests.get_last('body') is None
def test_wscall_ezt(http_requests, pub):
NamedWsCall.wipe()
@ -133,6 +134,7 @@ def test_wscall_ezt(http_requests, pub):
template = Template('<p>[webservice.hello.foo]</p>')
assert template.render(variables) == '<p>[webservice.hello.foo]</p>'
def test_webservice_post_put_patch(http_requests, pub):
NamedWsCall.wipe()
@ -149,6 +151,7 @@ def test_webservice_post_put_patch(http_requests, pub):
assert http_requests.get_last('method') == wscall.request['method']
assert json.loads(http_requests.get_last('body')) == wscall.request['post_data']
def test_webservice_delete(http_requests, pub):
NamedWsCall.wipe()

View File

@ -1,5 +1,6 @@
from wcs.qommon.x509utils import *
def test_x509utils():
assert can_generate_rsa_key_pair()
publickey, privatekey = generate_rsa_keypair()

View File

@ -32,6 +32,7 @@ import wcs.middleware
wcs.middleware.AfterJobsMiddleware.ASYNC = False
class KnownElements(object):
pickle_app_dir = None
sql_app_dir = None
@ -41,6 +42,7 @@ class KnownElements(object):
known_elements = KnownElements()
def create_temporary_pub(sql_mode=False, templates_mode=False, lazy_mode=False):
if sql_mode is True:
if pytest.config.getoption('without_postgresql_tests'):
@ -175,6 +177,7 @@ def create_temporary_pub(sql_mode=False, templates_mode=False, lazy_mode=False):
return pub
def clean_temporary_pub():
if get_publisher():
get_publisher().cleanup()
@ -224,6 +227,7 @@ def get_app(pub, https=False):
extra_environ['HTTPS'] = 'off'
return TestApp(wcs.wsgi.application, extra_environ=extra_environ)
def login(app, username='admin', password='admin'):
login_page = app.get('/login/')
login_form = login_page.forms['login-form']

View File

@ -25,6 +25,7 @@ from wcs.qommon.backoffice.menu import html_top
from wcs.formdef import FormDef
class CategoryUI(object):
def __init__(self, category):
self.category = category

View File

@ -27,6 +27,7 @@ from wcs.data_sources import (NamedDataSource, DataSourceSelectionWidget,
get_structured_items)
from wcs.formdef import FormDef, get_formdefs_of_all_kinds
class NamedDataSourceUI(object):
def __init__(self, datasource):
self.datasource = datasource

View File

@ -31,6 +31,7 @@ from wcs.formdef import FormDef
from wcs.fields import get_field_types
import copy
class FieldDefPage(Directory):
_q_exports = ['', 'delete', 'duplicate']

View File

@ -49,6 +49,7 @@ from .categories import CategoriesDirectory
from .data_sources import NamedDataSourcesDirectory
from .logged_errors import LoggedErrorsDirectory
def get_categories():
t = sorted([(misc.simplify(x.name), x.id, x.name, x.id) for x in Category.select()])
return [x[1:] for x in t]

View File

@ -25,6 +25,7 @@ from wcs.qommon.misc import localstrftime
from wcs.logged_errors import LoggedError
class LoggedErrorDirectory(Directory):
_q_exports = ['', 'delete', 'ack']

View File

@ -27,6 +27,7 @@ from wcs.qommon.backoffice.menu import html_top
from wcs.roles import Role, get_user_roles
from wcs.formdef import FormDef
class RoleUI(object):
def __init__(self, role):
self.role = role

View File

@ -62,6 +62,7 @@ from .fields import FieldDefPage, FieldsDirectory
from .data_sources import NamedDataSourcesDirectory
from .wscalls import NamedWsCallsDirectory
class UserFormDirectory(Directory):
_q_exports = ['']

View File

@ -35,6 +35,7 @@ from wcs.qommon.admin.emails import EmailsDirectory
from wcs.qommon.backoffice.menu import html_top
from wcs.qommon.admin.menu import error_page
class UserUI(object):
def __init__(self, user):
self.user = user
@ -298,6 +299,7 @@ class UserPage(Directory):
get_response().breadcrumb.append((component + '/', None))
return ident.get_method_user_directory(component, self.user)
class UsersDirectory(Directory):
_q_exports = ['', 'new']

View File

@ -52,6 +52,7 @@ from wcs.backoffice.studio import StudioDirectory
def svg(tag):
return '{http://www.w3.org/2000/svg}%s' % tag
def xlink(tag):
return '{http://www.w3.org/1999/xlink}%s' % tag
@ -59,11 +60,13 @@ TITLE = svg('title')
POLYGON = svg('polygon')
XLINK_TITLE = xlink('title')
def remove_tag(node, tag):
for child in node:
if child.tag == tag:
node.remove(child)
def remove_attribute(node, att):
if att in node.attrib:
del node.attrib[att]
@ -98,6 +101,7 @@ def adjust_style(node, top, colours, white_text=False, colour_class=None):
remove_attribute(child, 'style')
adjust_style(child, top, colours, white_text=white_text, colour_class=colour_class)
def graphviz_post_treatment(content, colours, include=False):
''' Remove all svg:title and top-level svg:polygon nodes, remove style
attributes and xlink:title attributes.
@ -120,6 +124,7 @@ def graphviz_post_treatment(content, colours, include=False):
adjust_style(child, child, colours)
return force_str(ET.tostring(tree))
def graphviz(workflow, url_prefix='', select=None, svg=True,
include=False):
out = StringIO()
@ -249,6 +254,7 @@ class WorkflowUI(object):
workflow.store()
return workflow
class WorkflowItemPage(Directory):
_q_exports = ['', 'delete']
@ -373,6 +379,7 @@ class GlobalActionTriggerPage(Directory):
self.workflow.store()
return redirect('../../')
class ToChildDirectory(Directory):
_q_exports = ['']
klass = None

View File

@ -24,6 +24,7 @@ from wcs.qommon.form import *
from wcs.qommon.backoffice.menu import html_top
from wcs.wscalls import NamedWsCall, WsCallRequestWidget
class NamedWsCallUI(object):
def __init__(self, wscall):
self.wscall = wscall

View File

@ -46,6 +46,7 @@ from wcs.api_utils import sign_url_auto_orig, is_url_signed, get_user_from_api_q
from .backoffice.management import FormPage as BackofficeFormPage
from .backoffice.management import ManagementDirectory
def posted_json_data_to_formdata_data(formdef, data):
# remap fields from varname to field id
for field in formdef.get_all_fields():
@ -855,6 +856,7 @@ def reverse_geocoding(request, *args, **kwargs):
url += '&accept-language=%s' % (get_publisher().get_site_language() or 'en')
return HttpResponse(misc.urlopen(url).read(), content_type='application/json')
def geocoding(request, *args, **kwargs):
if not 'q' in request.GET:
return HttpResponseBadRequest()
@ -883,6 +885,7 @@ def validate_expression(request, *args, **kwargs):
hint['msg'] = _('Make sure you want a Python expression, not a simple template string.')
return HttpResponse(json.dumps(hint), content_type='application/json')
def validate_condition(request, *args, **kwargs):
condition = {}
condition['type'] = request.GET.get('type') or ''

View File

@ -189,6 +189,7 @@ def get_secret_and_orig(url):
raise MissingSecret()
return secret, orig
def sign_url_auto_orig(url):
try:
signature_key, orig = get_secret_and_orig(url)

View File

@ -65,6 +65,7 @@ from wcs.workflows import get_role_translation, template_on_formdata
from .submission import FormFillPage
def geojson_formdatas(formdatas, geoloc_key='base', fields=None):
geojson = {
'type': 'FeatureCollection',
@ -2835,6 +2836,7 @@ def get_global_criteria(request, parsed_values=None):
return criterias
def format_time(t, units = 2):
days = int(t/86400)
hours = int((t-days*86400)/3600)

View File

@ -20,6 +20,7 @@ from django.core.cache.backends.base import InvalidCacheBackendError
from quixote import get_publisher
class TenantBaseCache(object):
'''Prepend the tenant application directory to the cache prefix'''
def set_key_prefix(self, prefix):

View File

@ -23,6 +23,7 @@ from .qommon.misc import simplify
from .qommon.substitution import Substitutions
from .qommon.xml_storage import XmlStorableObject
class Category(XmlStorableObject):
_names = 'categories'
_xml_tagname = 'category'

View File

@ -254,6 +254,7 @@ class CompatWcsPublisher(WcsPublisher):
# the publisher instance can't be shared for concurrent requests.
quixote_lock = Lock()
def quixote(request):
pub = get_publisher()
return pub.process_request(pub.get_request())

View File

@ -16,11 +16,13 @@
from quixote import get_publisher, get_response, get_request, get_session
def get_global_context():
pub = get_publisher()
if pub:
return pub.substitutions.get_context_variables(mode='lazy')
def publisher(request):
template_base = 'wcs/base.html'
if request.path.startswith('/backoffice/'):

View File

@ -43,6 +43,7 @@ from django.utils.encoding import force_bytes
class NoChange(Exception):
pass
def atomic_symlink(src, dst):
if os.path.exists(dst) and os.readlink(dst) == src:
return
@ -51,6 +52,7 @@ def atomic_symlink(src, dst):
os.symlink(src, dst + '.tmp')
os.rename(dst + '.tmp', dst)
class CmdCheckHobos(Command):
name = 'hobo_deploy'

View File

@ -20,6 +20,7 @@ import os
from ..qommon.ctl import Command, make_option
class CmdExportSettings(Command):
name = 'export_settings'

View File

@ -86,6 +86,7 @@ def get_rows(args):
for row in json.load(file(arg)):
yield row
def get_status_ids_accepting_trigger(workflow, trigger):
for status in workflow.possible_status:
for item in status.items:
@ -94,6 +95,7 @@ def get_status_ids_accepting_trigger(workflow, trigger):
yield 'wf-%s' % status.id, item
break
def get_formdata_accepting_trigger(formdef, trigger, status_ids=None):
if status_ids is None:
workflow = formdef.get_workflow()
@ -106,6 +108,7 @@ def get_formdata_accepting_trigger(formdef, trigger, status_ids=None):
for formdata_id in formdata_ids:
yield data_class.get(id=formdata_id), action_item
def match_row(substitution_variables, row):
select = row['select']
for key, value in select.items():
@ -113,6 +116,7 @@ def match_row(substitution_variables, row):
return False
return True
def jump_and_perform(formdata, action, workflow_data=None):
get_publisher().substitutions.reset()
get_publisher().substitutions.feed(get_publisher())
@ -121,6 +125,7 @@ def jump_and_perform(formdata, action, workflow_data=None):
print('formdata %s jumps to status %s' % (formdata, action.status))
wcs_jump_and_perform(formdata, action, workflow_data=workflow_data)
def select_and_jump_formdata(formdef, trigger, rows, status_ids=None):
for formdata, action_item in get_formdata_accepting_trigger(formdef, trigger, status_ids):
if rows == '__all__':

View File

@ -18,6 +18,7 @@ import os
from ..qommon.ctl import Command, make_option
def rebuild_vhost_indexes(pub, destroy=False):
from wcs.formdef import FormDef
if destroy:

View File

@ -21,6 +21,7 @@ import sys
from ..qommon.ctl import Command, make_option
class CmdRunScript(Command):
'''Run a script within a given host publisher context'''

View File

@ -25,6 +25,7 @@ import os.path
from ..qommon.ctl import Command, make_option
class CmdShell(Command):
'''Launch a shell and initialize a publisher on a given host'''

View File

@ -21,6 +21,7 @@ import sys
from ..qommon.ctl import Command, make_option
class CmdWipeData(Command):
name = 'wipe-data'

View File

@ -42,6 +42,7 @@ from .api_utils import sign_url_auto_orig
data_source_functions = {}
def register_data_source_function(function, function_name=None):
if not function_name:
function_name = function.__name__

View File

@ -575,6 +575,7 @@ class WidgetField(Field):
field_classes = []
field_types = []
def register_field_class(klass):
if not klass in field_classes:
field_classes.append(klass)
@ -702,6 +703,7 @@ class CommentField(Field):
register_field_class(CommentField)
def is_datasource_advanced(value):
data_source_in_advanced = (not value)
if data_source_in_advanced and (get_request().form.get('data_source$apply') or
@ -2411,6 +2413,7 @@ def get_field_class_by_type(type):
return k
raise KeyError()
def get_field_types():
return field_types

View File

@ -95,6 +95,7 @@ def get_dict_with_varnames(fields, data, formdata=None, varnames_only=False):
new_data['var_%s_%s_%s' % (field.varname, i, k)] = v
return new_data
def flatten_dict(d):
for k, v in list(d.items()):
if type(v) is dict:

View File

@ -26,6 +26,7 @@ from ..qommon.backoffice.listing import pagination_links
from wcs.qommon.storage import Null
from wcs.roles import logged_users_role
class FormDefUI(object):
def __init__(self, formdef):
self.formdef = formdef

View File

@ -67,6 +67,7 @@ class SubmittedDraftException(Exception):
def html_top(title = None):
template.html_top(title = title, default_org = _('Forms'))
def get_user_forms(formdef):
"""Return forms data for the current user
@ -82,6 +83,7 @@ def get_user_forms(formdef):
from wcs.forms.common import FormStatusPage
def tryauth(url):
# tries to log the user in before redirecting to the asked url; this won't
# do anything for local logins but will use a passive SAML request when
@ -96,6 +98,7 @@ def tryauth(url):
login_url = '/login/?ReturnUrl=%s&IsPassive=true' % quote(url)
return redirect(login_url)
def auth(url):
# logs the user in before redirecting to asked url.
if get_request().user:
@ -191,6 +194,7 @@ class TrackingCodesDirectory(Directory):
def _q_lookup(self, component):
return TrackingCodeDirectory(component, self.formdef)
class FormPage(Directory, FormTemplateMixin):
_q_exports = ['', 'tempfile', 'schema', 'tryauth',
'auth', 'forceauth', 'qrcode', 'autosave', 'code', 'removedraft', 'live']

View File

@ -21,6 +21,7 @@ from .qommon.xml_storage import XmlStorableObject
from wcs.formdef import FormDef
from wcs.workflows import Workflow
class LoggedError(XmlStorableObject):
_names = 'logged-errors'
_xml_tagname = 'error'

View File

@ -28,6 +28,7 @@ _thread_local = threading.local()
cleanup_orig = quixote.publish.cleanup
PublisherOrig = quixote.publish.Publisher
class Publisher(quixote.publish.Publisher):
def __init__(self, root_directory, *args, **kwargs):
try:
@ -41,24 +42,31 @@ class Publisher(quixote.publish.Publisher):
def set_in_thread(self):
_thread_local.publisher = self
def get_publisher():
return getattr(_thread_local, 'publisher', None)
def get_request():
return _thread_local.publisher.get_request()
def get_response():
return get_request() and _thread_local.publisher.get_request().response
def get_field(name, default=None):
return _thread_local.publisher.get_request().get_field(name, default)
def get_cookie(name, default=None):
return _thread_local.publisher.get_request().get_cookie(name, default)
def get_path(n=0):
return _thread_local.publisher.get_request().get_path(n)
def redirect(location, permanent=False):
"""(location : string, permanent : boolean = false) -> string
@ -71,12 +79,15 @@ def redirect(location, permanent=False):
location = urlparse.urljoin(request.get_url(), str(location))
return request.response.redirect(location, permanent)
def get_session():
return _thread_local.publisher.get_request().session
def get_session_manager():
return _thread_local.publisher.session_manager
def get_user():
session = _thread_local.publisher.get_request().session
if session is None:
@ -84,6 +95,7 @@ def get_user():
else:
return session.user
def cleanup():
cleanup_orig()
_thread_local.publisher = None

View File

@ -17,6 +17,7 @@
from quixote import get_request, redirect
from .qommon import myspace
class MyspaceDirectory(myspace.MyspaceDirectory):
_q_exports = ['', 'profile', 'new', 'password', 'remove', 'drafts', 'forms']

View File

@ -55,6 +55,7 @@ from .logged_errors import LoggedError
import pickle
class UnpicklerClass(pickle.Unpickler):
def find_class(self, module, name):
if module == 'qommon.form':

View File

@ -47,12 +47,14 @@ else:
# unpickle python2 strings as bytes
PICKLE_KWARGS = {'encoding': 'bytes', 'fix_imports': True}
def _(message):
pub = get_publisher()
if pub is None:
return message
return force_str(force_text(pub.gettext(str(message))))
def ngettext(*args):
pub = get_publisher()
if pub is None:

View File

@ -18,6 +18,7 @@ from quixote import get_publisher
from .. import get_cfg
def cfg_submit(form, cfg_key, fields):
get_publisher().reload_cfg()
cfg_key = str(cfg_key)

View File

@ -24,6 +24,7 @@ from .. import misc, get_cfg
from ..backoffice.menu import html_top
from ..admin.cfg import cfg_submit
class EmailsDirectory(Directory):
emails_dict = {}
_q_exports = ['', 'options']

View File

@ -26,6 +26,7 @@ from .. import logger, errors
from ..backoffice.menu import html_top
from ..admin.menu import error_page
class ByUserDirectory(Directory):
def _q_lookup(self, component):
return ByUserPages(component)

View File

@ -21,6 +21,7 @@ from .. import _
from ..backoffice.menu import html_top
import re
def _find_vc_version():
'''Find current version of the source code'''
import os.path
@ -91,9 +92,11 @@ def _find_vc_version():
vc_version = _find_vc_version()
def get_vc_version():
return vc_version
def command_icon(url, type, label=None, popup=False):
labels = {
'add': N_('Add'),
@ -116,6 +119,7 @@ def command_icon(url, type, label=None, popup=False):
<a href="%(url)s" rel="%(rel)s" title="%(label)s">%(label)s</a>
</span>''') % locals()
def error_page(section, error):
html_top(section, title = _('Error'))
r = TemplateIO(html=True)

View File

@ -23,6 +23,7 @@ from ..form import *
from ..admin.cfg import cfg_submit
from ..backoffice.menu import html_top
class SettingsDirectory(AccessControlled, Directory):
def _q_access(self):
get_response().breadcrumb.append( ('settings/', _('Settings')) )

View File

@ -21,6 +21,7 @@ from . import errors
from .http_response import AfterJob
from . import _
class AfterJobStatusDirectory(Directory):
def _q_lookup(self, component):
try:

View File

@ -20,6 +20,7 @@ from quixote import get_request, get_response
from .. import _
def pagination_links(offset, limit, total_count):
get_response().add_javascript(['jquery.js', 'wcs.listing.js'])
# pagination

View File

@ -20,6 +20,7 @@ from quixote.html import htmltext, TemplateIO
from .. import get_cfg
from .. import _
def generate_header_menu(selected = None):
return get_publisher().get_backoffice_root().generate_header_menu(selected=selected)

View File

@ -20,6 +20,7 @@ from quixote import get_publisher, get_request, get_response
from .. import _
from .. import errors
class BackofficeRootDirectory(AccessControlled, Directory):
@classmethod

View File

@ -18,6 +18,7 @@ import sys
from django.conf import settings
class CronJob(object):
name = None
hours = None
@ -34,6 +35,7 @@ class CronJob(object):
self.weekdays = weekdays
self.days = days
def cron_worker(publisher, now, job_name=None):
try:
publisher.set_config()

View File

@ -31,6 +31,7 @@ from wcs import qommon
from . import _
qommon._commands = {}
class Command(object):
doc = ''
name = None
@ -87,6 +88,7 @@ class Command(object):
def register(cls):
qommon._commands[cls.name] = cls
class Ctl(object):
def __init__(self, cmd_prefixes=[]):
self.cmd_prefixes = cmd_prefixes

View File

@ -110,6 +110,7 @@ def custom_template_email(key, mail_body_data, email_rcpt, **kwargs):
return template_email(mail_subject, mail_body, mail_body_data, email_type=key,
email_rcpt=email_rcpt, **kwargs)
def template_email(subject, mail_body, mail_body_data, email_rcpt, email_type=None, **kwargs):
data = get_publisher().substitutions.get_context_variables()
if mail_body_data:
@ -119,16 +120,19 @@ def template_email(subject, mail_body, mail_body_data, email_rcpt, email_type=No
return email(real_subject, real_mail_body, email_rcpt=email_rcpt,
email_type=email_type, **kwargs)
def data_as_octet_stream(data, filename, **kwargs):
msg = MIMEApplication(data, **kwargs)
msg.add_header('Content-Disposition', 'attachment', filename=filename)
return msg
def data_as_text(data, filename, **kwargs):
msg = MIMEText(data, **kwargs)
msg.add_header('Content-Disposition', 'attachment', filename=filename)
return msg
def convert_to_mime(attachment):
if hasattr(attachment, 'get_file_pointer'): # qommon.form.PicklableUpload-like object
attachment.get_file_pointer().seek(0)
@ -154,6 +158,7 @@ def convert_to_mime(attachment):
return part
get_logger().warn('Failed to build MIME part from %r', attachment)
def email(subject, mail_body, email_rcpt, replyto=None, bcc=None,
email_from=None, exclude_current_user=False, email_type=None,
want_html=True, hide_recipients=False, fire_and_forget=False,
@ -338,6 +343,7 @@ def email(subject, mail_body, email_rcpt, replyto=None, bcc=None,
EmailToSend(email_from, rcpts, msg.as_string()),
fire_and_forget = True)
def create_smtp_server(emails_cfg, smtp_timeout=None):
try:
s = smtplib.SMTP(emails_cfg.get('smtp_server', None) or 'localhost',
@ -373,6 +379,7 @@ def create_smtp_server(emails_cfg, smtp_timeout=None):
raise errors.EmailError('Failed to authenticate to SMTP server, unknown error.')
return s
class EmailToSend(object):
def __init__(self, msg_from, rcpts, msg_as_string):
self.msg_from = msg_from

View File

@ -58,9 +58,11 @@ class AccessUnauthorizedError(AccessForbiddenError):
login_url += '?' + urllib.urlencode({'next': request.get_frontoffice_url()})
return quixote.redirect(login_url)
class EmailError(Exception):
pass
class InternalServerError(object):
def render(self):
from . import _
@ -76,6 +78,7 @@ class InternalServerError(object):
r += htmltext('</p>')
return r.getvalue()
class FormError(Exception):
def __init__(self, field, msg):
self.field = field
@ -84,6 +87,7 @@ class FormError(Exception):
def __str__(self):
return self.msg
class ConnectionError(Exception):
def __init__(self, msg):
self.msg = msg
@ -91,6 +95,7 @@ class ConnectionError(Exception):
def __str__(self):
return self.msg
class ConfigurationError(Exception):
def __init__(self, msg):
self.msg = msg
@ -98,12 +103,15 @@ class ConfigurationError(Exception):
def __str__(self):
return self.msg
class LoginError(Exception):
pass
class CertificateError(Exception):
pass
class SMSError(Exception):
pass

View File

@ -63,17 +63,21 @@ def make_datetime(datetime_var):
except ValueError:
raise ValueError('invalid datetime value: %s' % datetime_var)
def date(var, month=None, day=None):
if var and month and day:
return datetime.date(int(var), int(month), int(day))
return make_date(var)
def days(count):
return datetime.timedelta(days=int(count))
def time_delta(t1, t2):
return make_date(t1) - make_date(t2)
def date_delta(t1, t2):
'''Return the timedelta between two date like values'''
t1, t2 = make_date(t1), make_date(t2)

View File

@ -275,6 +275,7 @@ _re_whitespace = re.compile(r'\s\s+')
# an integer.
_re_subst = re.compile('%(%|[0-9]+)')
class Template:
_printers = {
@ -572,6 +573,7 @@ class Template:
self._execute(section, valfp, ctx)
ctx.defines[name] = valfp.getvalue()
def boolean(value):
"Return a value suitable for [if-any bool_var] usage in a template."
if value:
@ -627,6 +629,7 @@ def _prepare_ref(refname, for_names, file_args):
return refname, start, rest
def _get_value(value_ref, ctx):
"""(refname, start, rest) -> a prepared `value reference' (see above).
ctx -> an execution context instance.
@ -673,6 +676,7 @@ def _get_value(value_ref, ctx):
# string or a sequence
return ob
def _get_value_fallback(value_ref, ctx):
try:
return _get_value(value_ref, ctx)
@ -680,6 +684,7 @@ def _get_value_fallback(value_ref, ctx):
(refname, start, rest) = value_ref
return '[' + refname + ']'
def _write_value(valrefs, fp, ctx, format=lambda s: s):
try:
value = _get_value(valrefs[0], ctx)
@ -738,6 +743,7 @@ class _context:
class Reader:
"Abstract class which allows EZT to detect Reader objects."
class _FileReader(Reader):
"""Reads templates from the filesystem."""
def __init__(self, fname):
@ -746,6 +752,7 @@ class _FileReader(Reader):
def read_other(self, relative):
return _FileReader(os.path.join(self._dir, relative))
class _TextReader(Reader):
"""'Reads' a template from provided text."""
def __init__(self, text):
@ -770,29 +777,38 @@ class EZTException(Exception):
s += ' at line %d column %d' % (self.line + 1, self.column + 1)
return s
class ArgCountSyntaxError(EZTException):
"""A bracket directive got the wrong number of arguments."""
class UnknownReference(EZTException):
"""The template references an object not contained in the data dictionary."""
class NeedSequenceError(EZTException):
"""The object dereferenced by the template is no sequence (tuple or list)."""
class UnclosedBlocksError(EZTException):
"""This error may be simply a missing [end]."""
class UnmatchedEndError(EZTException):
"""This error may be caused by a misspelled if directive."""
class UnmatchedElseError(EZTException):
"""This error may be caused by a misspelled if directive."""
class BaseUnavailableError(EZTException):
"""Base location is unavailable, which disables includes."""
class BadFormatConstantError(EZTException):
"""Format specifiers must be string constants."""
class UnknownFormatConstantError(EZTException):
"""The format specifier is an unknown value."""

View File

@ -87,18 +87,21 @@ QuixoteForm = Form
Widget.REQUIRED_ERROR = N_('required field')
get_error_orig = Widget.get_error
def get_i18n_error(self, request=None):
error = get_error_orig(self, request)
if error == Widget.REQUIRED_ERROR:
return _(error)
return error
def is_prefilled(self):
if hasattr(self, 'prefilled'):
return self.prefilled
else:
return False
def render_title(self, title):
if title:
if self.required:
@ -109,6 +112,7 @@ def render_title(self, title):
else:
return ''
def get_template_names(widget):
template_names = []
widget_template_name = getattr(widget, 'template_name', None)
@ -127,6 +131,7 @@ def get_template_names(widget):
template_names.append('qommon/forms/widget.html')
return template_names
def render(self):
# quixote/form/widget.py, Widget::render
def safe(text):
@ -151,6 +156,7 @@ Widget.cleanup = None
Widget.render_title = render_title
Widget.is_prefilled = is_prefilled
def string_render_content(self):
attrs = {'id': 'form_' + self.name}
if self.required:
@ -219,6 +225,7 @@ class RadiobuttonsWidget(quixote.form.RadiobuttonsWidget):
'selected': self.is_selected(object)
}
def checkbox_render_content(self, standalone=True):
attrs = {'id': 'form_' + self.name}
if self.required:
@ -540,6 +547,7 @@ class TextWidget(quixote.form.TextWidget):
except ValueError as e:
self.error = str(e)
class CheckboxWidget(quixote.form.CheckboxWidget):
'''
Widget just like CheckboxWidget but with an effective support for the
@ -558,6 +566,7 @@ class CheckboxWidget(quixote.form.CheckboxWidget):
else:
self.value = True
class UploadedFile: #pylint: disable=C1001
def __init__(self, directory, filename, upload):
self.directory = directory
@ -1225,6 +1234,7 @@ class CheckboxesWidget(CompositeWidget):
r += htmltext('</ul>')
return r.getvalue()
class ValidatedStringWidget(StringWidget):
'''StringWidget which checks the value entered is correct according to a regex'''
regex = None
@ -1241,6 +1251,7 @@ class ValidatedStringWidget(StringWidget):
if not match or not match.group() == self.value:
self.error = _('wrong format')
class UrlWidget(ValidatedStringWidget):
'''StringWidget which checks the value entered is a correct url starting with http or https'''
regex = r'^https?://.+'
@ -1350,6 +1361,7 @@ class CaptchaWidget(CompositeWidget):
r += widget.render_content()
return r.getvalue()
class WidgetList(quixote.form.widget.WidgetList):
def __init__(self, name, value=None,
element_type=StringWidget,
@ -1382,6 +1394,7 @@ class WidgetList(quixote.form.widget.WidgetList):
r += add_element_widget.render()
return r.getvalue()
class WidgetDict(quixote.form.widget.WidgetDict):
# Fix the title and hint setting
# FIXME: to be fixed in Quixote upstream : title and hint parameters should be removed
@ -1438,6 +1451,7 @@ class WidgetDict(quixote.form.widget.WidgetDict):
r += self.get_widget('added_elements').render()
return r.getvalue()
class TagsWidget(StringWidget):
def __init__(self, name, value = None, known_tags = None, **kwargs):
StringWidget.__init__(self, name, value, **kwargs)
@ -1476,6 +1490,7 @@ $("#%s").autocompleteArray([
</script>''' % (id, known_tags))
return r.getvalue()
class WysiwygTextWidget(TextWidget):
def _parse(self, request):
TextWidget._parse(self, request)
@ -1702,6 +1717,7 @@ class TableRowWidget(CompositeWidget):
for i, column in enumerate(self.columns):
self.add(StringWidget, name='col%s'%i, title=column, **kwargs)
class TableListRowsWidget(WidgetListAsTable):
readonly = False
@ -1788,6 +1804,7 @@ class TableListRowsWidget(WidgetListAsTable):
except IndexError:
pass
class RankedItemsWidget(CompositeWidget):
readonly = False
@ -1929,6 +1946,7 @@ class JsonpSingleSelectWidget(Widget):
return Widget.parse(self, request=request)
class AutocompleteStringWidget(WcsExtraStringWidget):
url = None

View File

@ -27,6 +27,7 @@ from quixote.errors import RequestError
from .http_response import HTTPResponse
class HTTPRequest(quixote.http_request.HTTPRequest):
signed = False
parsed = False

View File

@ -27,6 +27,7 @@ from quixote import get_publisher, get_request
from .storage import StorableObject
class AfterJob(StorableObject):
_names = 'afterjobs'

View File

@ -24,6 +24,7 @@ _day = _hour * 24
_month = _day * 31
_year = int(_day * 365.25)
def list2human(stringlist):
'''Transform a string list to human enumeration'''
beginning = stringlist[:-1]
@ -38,6 +39,7 @@ _humandurations = (( (N_("day"), N_("days")), _day),
( (N_("minute"), N_("minutes")), _minute),
( (N_("second"), N_("seconds")), 1),)
def timewords():
'''List of words one can use to specify durations'''
result = []
@ -46,6 +48,7 @@ def timewords():
result.append(_(word))
return result
def humanduration2seconds(humanduration):
if not humanduration:
raise ValueError()
@ -59,6 +62,7 @@ def humanduration2seconds(humanduration):
break
return seconds
def seconds2humanduration(seconds):
'''Convert a time range in seconds to a human string representation
'''

View File

@ -18,30 +18,36 @@ from quixote import get_publisher
from . import base
def login(method):
m = get_publisher().ident_methods.get(method)
if m and hasattr(m, 'login'):
return m().login()
return get_method_directory(method).login()
def register(method):
return get_method_directory(method).register()
def get_method_directory(method):
m = get_publisher().ident_methods.get(method)
if not m:
raise KeyError
return m.method_directory()
def get_method_admin_directory(method):
return get_publisher().ident_methods.get(method).method_admin_directory()
def get_method_user_directory(method, user):
try:
return get_publisher().ident_methods.get(method).method_user_directory(user)
except (AttributeError, NotImplementedError, base.NoSuchMethodForUserError):
return None
def get_method_classes():
return get_publisher().ident_methods.values()

View File

@ -14,6 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
class AuthMethod(object):
method_admin_widget = None

View File

@ -46,18 +46,22 @@ from .. import saml2utils
ADMIN_TITLE = N_('SAML2')
def is_idp_managing_user_attributes():
return get_cfg('sp', {}).get('idp-manage-user-attributes', False)
def is_idp_managing_user_roles():
return get_cfg('sp', {}).get('idp-manage-roles', False)
def get_file_content(filename):
try:
return open(filename,'r').read()
except:
return None
def get_text_file_preview(filename):
'''Return a preformatted HTML blocks displaying content
of filename, or None if filename is not accessible

View File

@ -676,6 +676,7 @@ class MethodDirectory(Directory):
ADMIN_TITLE = N_('Username / Password')
class MethodAdminDirectory(Directory):
title = ADMIN_TITLE
label = N_('Configure username/password identification method')
@ -1122,6 +1123,7 @@ class MethodUserDirectory(Directory):
emails.custom_template_email(email_key, data, self.user.email)
class PasswordAuthMethod(AuthMethod):
key = 'password'
description = _('Username / password')

Some files were not shown because too many files have changed in this diff Show More