Project

General

Profile

0001-misc-create-session-substitution-variables-from-quer.patch

Frédéric Péters, 18 August 2015 09:35 AM

Download (8.87 KB)

View differences:

Subject: [PATCH] misc: create session substitution variables from query string
 (#7858)

 help/fr/misc-substvars.page | 46 ++++++++++++++++++++++++++++++++++++
 tests/test_form_pages.py    | 57 +++++++++++++++++++++++++++++++++++++++++++++
 wcs/qommon/publisher.py     | 29 +++++++++++++++++++++++
 wcs/qommon/sessions.py      | 14 +++++++++++
 wcs/root.py                 |  1 +
 5 files changed, 147 insertions(+)
help/fr/misc-substvars.page
213 213

  
214 214
</section>
215 215

  
216
<section id="session-variables">
217
  <title>Variables de session</title>
218

  
219
  <p>
220
   La session de l'usager contient une série d'informations fixes (par exemple
221
   le <code>session_user_display_name</code> décrit en haut de page), il est
222
   aussi possible d'y ajouter de nouvelles données par l'intermédiaire de
223
   liens contenant des paramètres. Cela permet par exemple d'inclure une URL
224
   personnalisée dans un courriel vers l'usager, qui assurera le
225
   préremplissage automatique de champs.
226
  </p>
227

  
228
  <p>
229
   Le fonctionnement est simple, si le site reçoit une adresse avec des
230
   paramètres de la forme <code>session_var_<var>nom</var></code>, une
231
   variable du même nom (<code>session_var_<var>nom</var></code>) est rendue
232
   disponible.
233
  </p>
234

  
235
  <p>
236
   Un autre exemple pourrait être de faire varier le thème en fonction du site
237
   extérieur ayant pointé vers le formulaire, une URL serait par exemple
238
   <code>https://www.example.net/?session_var_departement=42</code> et le
239
   squelette du site pourrait avoir le code suivant :
240
  </p>
241

  
242
  <example>
243
   [if-any session_var_departement]
244
     &lt;link rel="stylesheet" type="text/css" href="extra/[session_var_departement].css"/&gt;
245
   [end]
246
  </example>
247

  
248
  <note style="important">
249
   <p>
250
    L'utilisation de ce fonctionnement doit explicitement être autorisé par
251
    l'administrateur système, la liste des variables permises doit être ajoutée
252
    au fichier <code>site_options.cfg</code>, dans la section
253
    <code>[options]</code>, par exemple :
254
   </p>
255
   <example>
256
    <code>query_string_allowed_vars = departement,une_autre_variable</code>
257
   </example>
258
  </note>
259

  
260
</section>
261

  
216 262
</page>
tests/test_form_pages.py
1 1
import pytest
2 2
import hashlib
3
import os
3 4

  
4 5
from wcs.qommon.ident.password_accounts import PasswordAccount
5 6
from wcs.formdef import FormDef
......
884 885
            '0_structured': [
885 886
                {'id': '1', 'more': 'foo', 'text': 'un'},
886 887
                {'id': '3', 'more': 'baz', 'text': 'trois'}]}
888

  
889
def test_form_page_query_string_prefill(pub):
890
    user = create_user(pub)
891
    formdef = create_formdef()
892
    formdef.data_class().wipe()
893
    formdef.fields = [fields.StringField(id='0', label='string',
894
        prefill={'type': 'formula', 'value': 'session_var_foo'})]
895
    formdef.store()
896

  
897
    # check it's empty if it doesn't exist
898
    resp = get_app(pub).get('/test/')
899
    assert resp.forms[0]['f0'].value == ''
900

  
901
    # check it's not set if it's not whitelisted
902
    resp = get_app(pub).get('/?session_var_foo=hello')
903
    assert resp.location == 'http://example.net/'
904
    resp = resp.follow()
905
    resp = resp.click('test')
906
    assert resp.forms[0]['f0'].value == ''
907

  
908
    # check it works
909
    open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w').write('''[options]
910
query_string_allowed_vars = foo,bar
911
''')
912

  
913
    resp = get_app(pub).get('/?session_var_foo=hello')
914
    assert resp.location == 'http://example.net/'
915
    resp = resp.follow()
916
    resp = resp.click('test')
917
    assert resp.forms[0]['f0'].value == 'hello'
918

  
919
    # check it survives a login
920
    resp = get_app(pub).get('/?session_var_foo=hello2')
921
    assert resp.location == 'http://example.net/'
922
    resp = resp.follow()
923
    resp = resp.click('Login')
924
    resp = resp.follow()
925
    resp.forms[0]['username'] = 'foo'
926
    resp.forms[0]['password'] = 'foo'
927
    resp = resp.forms[0].submit()
928
    resp = resp.follow()
929
    resp = resp.click('test')
930
    assert resp.forms[0]['f0'].value == 'hello2'
931

  
932
    # check repeated options are ignored
933
    resp = get_app(pub).get('/?session_var_foo=hello&session_var_foo=hello2')
934
    assert resp.location == 'http://example.net/'
935
    resp = resp.follow()
936
    resp = resp.click('test')
937
    assert resp.forms[0]['f0'].value == ''
938

  
939
    # check extra query string parameters are not lost
940
    resp = get_app(pub).get('/?session_var_foo=hello&foo=bar')
941
    assert resp.location == 'http://example.net/?foo=bar'
942

  
943
    os.unlink(os.path.join(pub.app_dir, 'site-options.cfg'))
wcs/qommon/publisher.py
578 578
        if request.get_environ('QOMMON_PAGE_TEMPLATE_KEY'):
579 579
            request.response.page_template_key = request.get_environ('QOMMON_PAGE_TEMPLATE_KEY')
580 580

  
581
        # handle session_var_<xxx> in query strings, add them to session and
582
        # redirect to same URL without the parameters
583
        if request.get_method() == 'GET' and request.form:
584
            query_string_allowed_vars = self.get_site_option(
585
                    'query_string_allowed_vars') or ''
586
            query_string_allowed_vars = [x.strip() for x in
587
                    query_string_allowed_vars.split(',')]
588
            had_session_variables = False
589
            session_variables = {}
590
            for k, v in request.form.items():
591
                if k.startswith('session_var_'):
592
                    had_session_variables = True
593
                    session_variable = str(k[len('session_var_'):])
594
                    # only add variable to session if it's a string, this
595
                    # handles the case of repeated parameters producing a
596
                    # list of values (by ignoring those parameters altogether).
597
                    if session_variable in query_string_allowed_vars and (
598
                            isinstance(v, str)):
599
                        session_variables[session_variable] = v
600
                    del request.form[k]
601
            if had_session_variables:
602
                self.start_request() # creates session
603
                request.session.add_extra_variables(**session_variables)
604
                self.finish_successful_request() # commits session
605
                new_query_string = ''
606
                if request.form:
607
                    new_query_string = '?' + urllib.urlencode(request.form)
608
                return redirect(request.get_path() + new_query_string)
609

  
581 610
        request.language = self.get_site_language()
582 611
        self.install_lang(request.language)
583 612
        self.substitutions.feed(self)
wcs/qommon/sessions.py
80 80
    ident_idp_token = None
81 81
    tempfiles = None
82 82
    jsonp_display_values = None
83
    extra_variables = None
83 84

  
84 85
    username = None # only set on password authentication
85 86

  
......
92 93
            self.ident_idp_token or \
93 94
            self.tempfiles or \
94 95
            self.jsonp_display_values or \
96
            self.extra_variables or \
95 97
            CaptchaSession.has_info(self) or \
96 98
            QuixoteSession.has_info(self)
97 99
    is_dirty = has_info
......
205 207
        value.fp = open(filename)
206 208
        return value
207 209

  
210
    def add_extra_variables(self, **kwargs):
211
        if not self.extra_variables:
212
            self.extra_variables = {}
213
        self.extra_variables.update(kwargs)
214

  
215
    def get_substitution_variables(self, prefix='session_var_'):
216
        d = {}
217
        if self.extra_variables:
218
            for k, v in self.extra_variables.items():
219
                d[prefix + k] = v
220
        return d
221

  
208 222

  
209 223
class QommonSessionManager(QuixoteSessionManager):
210 224
    def start_request(self):
wcs/root.py
283 283
        if not hasattr(response, 'breadcrumb'):
284 284
            response.breadcrumb = [ ('', _('Home')) ]
285 285

  
286
        get_publisher().substitutions.feed(get_session())
286 287
        get_publisher().substitutions.feed(get_request().user)
287 288
        get_publisher().substitutions.feed(NamedDataSource)
288 289

  
289
-