From feb968d368822ab55b052e0002b7f052e1b86439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= Date: Mon, 17 Aug 2015 16:14:32 +0200 Subject: [PATCH] misc: create session substitution variables from query string (#7858) --- tests/test_form_pages.py | 57 ++++++++++++++++++++++++++++++++++++++++++++++++ wcs/qommon/publisher.py | 29 ++++++++++++++++++++++++ wcs/qommon/sessions.py | 14 ++++++++++++ wcs/root.py | 1 + 4 files changed, 101 insertions(+) diff --git a/tests/test_form_pages.py b/tests/test_form_pages.py index f9a0704..aa49cd4 100644 --- a/tests/test_form_pages.py +++ b/tests/test_form_pages.py @@ -1,5 +1,6 @@ import pytest import hashlib +import os from wcs.qommon.ident.password_accounts import PasswordAccount from wcs.formdef import FormDef @@ -884,3 +885,59 @@ def test_form_items_data_source_field_submit(pub): '0_structured': [ {'id': '1', 'more': 'foo', 'text': 'un'}, {'id': '3', 'more': 'baz', 'text': 'trois'}]} + +def test_form_page_query_string_prefill(pub): + user = create_user(pub) + formdef = create_formdef() + formdef.data_class().wipe() + formdef.fields = [fields.StringField(id='0', label='string', + prefill={'type': 'formula', 'value': 'session_var_foo'})] + formdef.store() + + # check it's empty if it doesn't exist + resp = get_app(pub).get('/test/') + assert resp.forms[0]['f0'].value == '' + + # check it's not set if it's not whitelisted + resp = get_app(pub).get('/?session_var_foo=hello') + assert resp.location == 'http://example.net/' + resp = resp.follow() + resp = resp.click('test') + assert resp.forms[0]['f0'].value == '' + + # check it works + open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w').write('''[options] +query_string_allowed_vars = foo,bar +''') + + resp = get_app(pub).get('/?session_var_foo=hello') + assert resp.location == 'http://example.net/' + resp = resp.follow() + resp = resp.click('test') + assert resp.forms[0]['f0'].value == 'hello' + + # check it survives a login + resp = get_app(pub).get('/?session_var_foo=hello2') + assert resp.location == 'http://example.net/' + resp = resp.follow() + resp = resp.click('Login') + resp = resp.follow() + resp.forms[0]['username'] = 'foo' + resp.forms[0]['password'] = 'foo' + resp = resp.forms[0].submit() + resp = resp.follow() + resp = resp.click('test') + assert resp.forms[0]['f0'].value == 'hello2' + + # check repeated options are ignored + resp = get_app(pub).get('/?session_var_foo=hello&session_var_foo=hello2') + assert resp.location == 'http://example.net/' + resp = resp.follow() + resp = resp.click('test') + assert resp.forms[0]['f0'].value == '' + + # check extra query string parameters are not lost + resp = get_app(pub).get('/?session_var_foo=hello&foo=bar') + assert resp.location == 'http://example.net/?foo=bar' + + os.unlink(os.path.join(pub.app_dir, 'site-options.cfg')) diff --git a/wcs/qommon/publisher.py b/wcs/qommon/publisher.py index a0fb073..fbd957c 100644 --- a/wcs/qommon/publisher.py +++ b/wcs/qommon/publisher.py @@ -578,6 +578,35 @@ class QommonPublisher(Publisher): if request.get_environ('QOMMON_PAGE_TEMPLATE_KEY'): request.response.page_template_key = request.get_environ('QOMMON_PAGE_TEMPLATE_KEY') + # handle session_var_ in query strings, add them to session and + # redirect to same URL without the parameters + if request.get_method() == 'GET' and request.form: + query_string_allowed_vars = self.get_site_option( + 'query_string_allowed_vars') or '' + query_string_allowed_vars = [x.strip() for x in + query_string_allowed_vars.split(',')] + had_session_variables = False + session_variables = {} + for k, v in request.form.items(): + if k.startswith('session_var_'): + had_session_variables = True + session_variable = str(k[len('session_var_'):]) + # only add variable to session if it's a string, this + # handles the case of repeated parameters producing a + # list of values (by ignoring those parameters altogether). + if session_variable in query_string_allowed_vars and ( + isinstance(v, str)): + session_variables[session_variable] = v + del request.form[k] + if had_session_variables: + self.start_request() # creates session + request.session.add_extra_variables(**session_variables) + self.finish_successful_request() # commits session + new_query_string = '' + if request.form: + new_query_string = '?' + urllib.urlencode(request.form) + return redirect(request.get_path() + new_query_string) + request.language = self.get_site_language() self.install_lang(request.language) self.substitutions.feed(self) diff --git a/wcs/qommon/sessions.py b/wcs/qommon/sessions.py index 74158fa..874feee 100644 --- a/wcs/qommon/sessions.py +++ b/wcs/qommon/sessions.py @@ -80,6 +80,7 @@ class Session(QommonSession, CaptchaSession, StorableObject): ident_idp_token = None tempfiles = None jsonp_display_values = None + extra_variables = None username = None # only set on password authentication @@ -92,6 +93,7 @@ class Session(QommonSession, CaptchaSession, StorableObject): self.ident_idp_token or \ self.tempfiles or \ self.jsonp_display_values or \ + self.extra_variables or \ CaptchaSession.has_info(self) or \ QuixoteSession.has_info(self) is_dirty = has_info @@ -205,6 +207,18 @@ class Session(QommonSession, CaptchaSession, StorableObject): value.fp = open(filename) return value + def add_extra_variables(self, **kwargs): + if not self.extra_variables: + self.extra_variables = {} + self.extra_variables.update(kwargs) + + def get_substitution_variables(self, prefix='session_var_'): + d = {} + if self.extra_variables: + for k, v in self.extra_variables.items(): + d[prefix + k] = v + return d + class QommonSessionManager(QuixoteSessionManager): def start_request(self): diff --git a/wcs/root.py b/wcs/root.py index 520c2bf..9ad8ed4 100644 --- a/wcs/root.py +++ b/wcs/root.py @@ -283,6 +283,7 @@ class RootDirectory(Directory): if not hasattr(response, 'breadcrumb'): response.breadcrumb = [ ('', _('Home')) ] + get_publisher().substitutions.feed(get_session()) get_publisher().substitutions.feed(get_request().user) get_publisher().substitutions.feed(NamedDataSource) -- 2.5.0