From 5c74e9e05977053c40ed3be3e2a222fe9b02dd5b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= <fpeters@entrouvert.com>
Date: Tue, 8 Jan 2019 16:23:14 +0100
Subject: [PATCH] misc: expose request (/query string) in expression variables
 (#29565)

---
 .../qommon/forms/widgets/select--test.html    |  3 +-
 tests/test_form_pages.py                      | 41 ++++++++++++++++++-
 wcs/context_processors.py                     |  1 +
 wcs/qommon/http_request.py                    |  3 +-
 wcs/settings.py                               |  1 -
 wcs/variables.py                              | 27 ++++++++++++
 6 files changed, 72 insertions(+), 4 deletions(-)

diff --git a/tests/templates/qommon/forms/widgets/select--test.html b/tests/templates/qommon/forms/widgets/select--test.html
index 98a2cba88..463c500fa 100644
--- a/tests/templates/qommon/forms/widgets/select--test.html
+++ b/tests/templates/qommon/forms/widgets/select--test.html
@@ -1,7 +1,8 @@
 {% extends "qommon/forms/widget.html" %}
 {% block widget-control %}
 <!-- TEST TEMPLATE -->
-<!-- backoffice: {{ request.quixote_request.is_in_backoffice|pprint }} -->
+<!-- backoffice: {{ request.is_in_backoffice|pprint }} -->
+<!-- backoffice compat: {{ request.quixote_request.is_in_backoffice|pprint }} -->
 <!-- substitution variable: {{ example_url }} -->
 <select id="form_{{widget.name}}" name="{{widget.name}}"
     {% for attr in widget.attrs.items %}{{attr.0}}="{{attr.1}}"{% endfor %}>
diff --git a/tests/test_form_pages.py b/tests/test_form_pages.py
index d6aee5134..116b2c963 100644
--- a/tests/test_form_pages.py
+++ b/tests/test_form_pages.py
@@ -2189,7 +2189,7 @@ def test_form_page_template_prefill(pub):
     assert resp.form['f0'].value == ''
     assert 'widget-prefilled' not in resp.body
 
-def test_form_page_query_string_prefill(pub):
+def test_form_page_session_var_prefill(pub):
     user = create_user(pub)
     formdef = create_formdef()
     formdef.data_class().wipe()
@@ -2246,6 +2246,44 @@ query_string_allowed_vars = foo,bar
 
     os.unlink(os.path.join(pub.app_dir, 'site-options.cfg'))
 
+def test_form_page_query_string_list_prefill(pub):
+    user = create_user(pub)
+    formdef = create_formdef()
+    formdef.data_class().wipe()
+    formdef.fields = [fields.ItemField(id='1', label='item',
+        varname='item', required=False, data_source={'type': 'foobar'},
+        prefill={'type': 'string', 'value': '{{request.query_string.preselect}}'},
+        )]
+    formdef.store()
+
+    NamedDataSource.wipe()
+    data_source = NamedDataSource(name='foobar')
+    data_source.data_source = {'type': 'formula',
+            'value': repr([{'id': '1', 'text': 'un'},
+                           {'id': '2', 'text': 'deux'},
+                           {'id': '3', 'text': 'trois'},
+                           {'id': '4', 'text': 'quatre'},
+                           ])}
+    data_source.store()
+
+    resp = get_app(pub).get('/test/')
+    assert resp.form['f1'].value == '1'
+
+    resp = get_app(pub).get('/test/?preselect=2')
+    assert resp.form['f1'].value == '2'
+    resp = resp.form.submit('submit')
+    resp = resp.form.submit('submit').follow()
+    assert 'deux' in resp.body
+
+    formdef.fields = [fields.ItemField(id='1', label='item',
+        varname='item', required=False, data_source={'type': 'foobar'},
+        prefill={'type': 'string', 'value': '{{request.GET.preselect}}'},
+        )]
+    formdef.store()
+
+    resp = get_app(pub).get('/test/?preselect=3')
+    assert resp.form['f1'].value == '3'
+
 def test_form_page_profile_prefill_list(pub):
     user = create_user(pub)
     formdef = create_formdef()
@@ -4966,6 +5004,7 @@ def test_form_custom_select_template(pub):
     assert 'TEST TEMPLATE' in resp.body
     # make sure request is available in context
     assert '<!-- backoffice: False -->' in resp.body
+    assert '<!-- backoffice compat: False -->' in resp.body
 
     # test for substitution variables being available
     if not pub.site_options.has_section('variables'):
diff --git a/wcs/context_processors.py b/wcs/context_processors.py
index a68da8f64..0413fa4a8 100644
--- a/wcs/context_processors.py
+++ b/wcs/context_processors.py
@@ -25,6 +25,7 @@ def publisher(request):
     template_base = 'wcs/base.html'
     if request.path.startswith('/backoffice/'):
         template_base = 'wcs/blank.html'
+    from .variables import LazyRequest
     return {'publisher': get_publisher,
             'response': get_response,
             'user': lambda: get_request() and get_request().user,
diff --git a/wcs/qommon/http_request.py b/wcs/qommon/http_request.py
index 35d1b90b1..71b79088c 100644
--- a/wcs/qommon/http_request.py
+++ b/wcs/qommon/http_request.py
@@ -85,8 +85,9 @@ class HTTPRequest(quixote.http_request.HTTPRequest):
 
     def get_substitution_variables(self):
         # environment variables APPNAME_* are exported to env_*
+        from wcs.variables import LazyRequest
         prefix = get_publisher().APP_NAME.lower() + '_'
-        variables = {}
+        variables = {'request': LazyRequest(self)}
         for k, v in self.environ.items():
             if k.lower().startswith(prefix):
                 variables['env_' + k.lower()[len(prefix):]] = v
diff --git a/wcs/settings.py b/wcs/settings.py
index 6060ff37b..cac673e6e 100644
--- a/wcs/settings.py
+++ b/wcs/settings.py
@@ -94,7 +94,6 @@ TEMPLATES = [
                 "django.template.context_processors.debug",
                 "django.template.context_processors.i18n",
                 "django.template.context_processors.media",
-                "django.template.context_processors.request",
                 "django.template.context_processors.static",
                 "django.template.context_processors.tz",
                 "django.contrib.messages.context_processors.messages",
diff --git a/wcs/variables.py b/wcs/variables.py
index b155b2833..5b859ddef 100644
--- a/wcs/variables.py
+++ b/wcs/variables.py
@@ -486,3 +486,30 @@ class LazyUser(object):
             return super(LazyUser, self).__getattr__(attr)
         except AttributeError:
             return getattr(self.user, attr)
+
+
+class LazyRequest(object):
+    def __init__(self, request):
+        self.request = request
+
+    @property
+    def quixote_request(self):  # compatibility
+        return self.request
+
+    @property
+    def GET(self):
+        return self.request.django_request.GET
+
+    query_string = GET
+
+    @property
+    def is_in_backoffice(self):
+        return self.request.is_in_backoffice()
+
+    @property
+    def method(self):
+        return self.request.method
+
+    @property
+    def user(self):
+        return self.request.user
-- 
2.20.1

