##// END OF EJS Templates
sessions: fixed regression in handlin sqlalchemy params for beaker DB based sessions
super-admin -
r5132:896a74f1 default
parent child Browse files
Show More
@@ -1,158 +1,172 b''
1 # Copyright (c) 2010 Agendaless Consulting and Contributors.
1 # Copyright (c) 2010 Agendaless Consulting and Contributors.
2 # (http://www.agendaless.com), All Rights Reserved
2 # (http://www.agendaless.com), All Rights Reserved
3 # License: BSD-derived (http://www.repoze.org/LICENSE.txt)
3 # License: BSD-derived (http://www.repoze.org/LICENSE.txt)
4 # With Patches from RhodeCode GmBH
4 # With Patches from RhodeCode GmBH
5
5
6
7 import os
6 import os
8
7
9 from beaker import cache
8 from beaker import cache
10 from beaker.session import SessionObject
9 from beaker.session import SessionObject, Session
11 from beaker.util import coerce_cache_params
10 from beaker.util import coerce_cache_params
12 from beaker.util import coerce_session_params
11 from beaker.util import coerce_session_params
13
12
14 from pyramid.interfaces import ISession
13 from pyramid.interfaces import ISession
15 from pyramid.settings import asbool
14 from pyramid.settings import asbool
16 from zope.interface import implementer
15 from zope.interface import implementer
17
16
18 from binascii import hexlify
17 from binascii import hexlify
19
18
20
19
20
21 class CustomSession(Session):
22 pass
23
24
21 def BeakerSessionFactoryConfig(**options):
25 def BeakerSessionFactoryConfig(**options):
22 """ Return a Pyramid session factory using Beaker session settings
26 """ Return a Pyramid session factory using Beaker session settings
23 supplied directly as ``**options``"""
27 supplied directly as ``**options``"""
24
28
25 class PyramidBeakerSessionObject(SessionObject):
29 class PyramidBeakerSessionObject(SessionObject):
26 _options = options
30 _options = options
27 _cookie_on_exception = _options.pop('cookie_on_exception', True)
31 _cookie_on_exception = _options.pop('cookie_on_exception', True)
28 _constant_csrf_token = _options.pop('constant_csrf_token', False)
32 _constant_csrf_token = _options.pop('constant_csrf_token', False)
33 _sa_opts = _options.pop('sa_opts', {})
29
34
30 def __init__(self, request):
35 def __init__(self, request):
36 self._options['session_class'] = CustomSession
37 self._options['sa_opts'] = self._sa_opts
31 SessionObject.__init__(self, request.environ, **self._options)
38 SessionObject.__init__(self, request.environ, **self._options)
32
39
33 def session_callback(_request, _response):
40 def session_callback(_request, _response):
34 exception = getattr(_request, 'exception', None)
41 exception = getattr(_request, 'exception', None)
35 file_response = getattr(_request, '_file_response', None)
42 file_response = getattr(_request, '_file_response', None)
36 api_call = getattr(_request, 'rpc_method', None)
43 api_call = getattr(_request, 'rpc_method', None)
37
44
38 if file_response is not None:
45 if file_response is not None:
39 return
46 return
40 if api_call is not None:
47 if api_call is not None:
41 return
48 return
42
49
43 if exception is not None and not self._cookie_on_exception:
50 if exception is not None and not self._cookie_on_exception:
44 return
51 return
45
52
46 if self.accessed():
53 if self.accessed():
47 self.persist()
54 self.persist()
48 headers = self.__dict__['_headers']
55 headers = self.__dict__['_headers']
49 if headers.get('set_cookie') and headers.get('cookie_out'):
56 if headers.get('set_cookie') and headers.get('cookie_out'):
50 _response.headerlist.append(('Set-Cookie', headers['cookie_out']))
57 _response.headerlist.append(('Set-Cookie', headers['cookie_out']))
51
58
52 request.add_response_callback(session_callback)
59 request.add_response_callback(session_callback)
53
60
54 # ISession API
61 # ISession API
55
62
56 @property
63 @property
57 def id(self):
64 def id(self):
58 # this is as inspected in SessionObject.__init__
65 # this is as inspected in SessionObject.__init__
59 if self.__dict__['_params'].get('type') != 'cookie':
66 if self.__dict__['_params'].get('type') != 'cookie':
60 return self._session().id
67 return self._session().id
61 return None
68 return None
62
69
63 @property
70 @property
64 def new(self):
71 def new(self):
65 return self.last_accessed is None
72 return self.last_accessed is None
66
73
67 changed = SessionObject.save
74 changed = SessionObject.save
68
75
69 # modifying dictionary methods
76 # modifying dictionary methods
70
77
71 @call_save
78 @call_save
72 def clear(self):
79 def clear(self):
73 return self._session().clear()
80 return self._session().clear()
74
81
75 @call_save
82 @call_save
76 def update(self, d, **kw):
83 def update(self, d, **kw):
77 return self._session().update(d, **kw)
84 return self._session().update(d, **kw)
78
85
79 @call_save
86 @call_save
80 def setdefault(self, k, d=None):
87 def setdefault(self, k, d=None):
81 return self._session().setdefault(k, d)
88 return self._session().setdefault(k, d)
82
89
83 @call_save
90 @call_save
84 def pop(self, k, d=None):
91 def pop(self, k, d=None):
85 return self._session().pop(k, d)
92 return self._session().pop(k, d)
86
93
87 @call_save
94 @call_save
88 def popitem(self):
95 def popitem(self):
89 return self._session().popitem()
96 return self._session().popitem()
90
97
91 __setitem__ = call_save(SessionObject.__setitem__)
98 __setitem__ = call_save(SessionObject.__setitem__)
92 __delitem__ = call_save(SessionObject.__delitem__)
99 __delitem__ = call_save(SessionObject.__delitem__)
93
100
94 # Flash API methods
101 # Flash API methods
95 def flash(self, msg, queue='', allow_duplicate=True):
102 def flash(self, msg, queue='', allow_duplicate=True):
96 storage = self.setdefault('_f_' + queue, [])
103 storage = self.setdefault(f'_f_{queue}', [])
97 if allow_duplicate or (msg not in storage):
104 if allow_duplicate or (msg not in storage):
98 storage.append(msg)
105 storage.append(msg)
99
106
100 def pop_flash(self, queue=''):
107 def pop_flash(self, queue=''):
101 storage = self.pop('_f_' + queue, [])
108 storage = self.pop(f'_f_{queue}', [])
102 return storage
109 return storage
103
110
104 def peek_flash(self, queue=''):
111 def peek_flash(self, queue=''):
105 storage = self.get('_f_' + queue, [])
112 storage = self.get('_f_' + queue, [])
106 return storage
113 return storage
107
114
108 # CSRF API methods
115 # CSRF API methods
109 def new_csrf_token(self):
116 def new_csrf_token(self):
110 token = (self._constant_csrf_token
117 token = (self._constant_csrf_token
111 or hexlify(os.urandom(20)).decode('ascii'))
118 or hexlify(os.urandom(20)).decode('ascii'))
112 self['_csrft_'] = token
119 self['_csrft_'] = token
113 return token
120 return token
114
121
115 def get_csrf_token(self):
122 def get_csrf_token(self):
116 token = self.get('_csrft_', None)
123 token = self.get('_csrft_', None)
117 if token is None:
124 if token is None:
118 token = self.new_csrf_token()
125 token = self.new_csrf_token()
119 return token
126 return token
120
127
121 return implementer(ISession)(PyramidBeakerSessionObject)
128 return implementer(ISession)(PyramidBeakerSessionObject)
122
129
123
130
124 def call_save(wrapped):
131 def call_save(wrapped):
125 """ By default, in non-auto-mode beaker badly wants people to
132 """ By default, in non-auto-mode beaker badly wants people to
126 call save even though it should know something has changed when
133 call save even though it should know something has changed when
127 a mutating method is called. This hack should be removed if
134 a mutating method is called. This hack should be removed if
128 Beaker ever starts to do this by default. """
135 Beaker ever starts to do this by default. """
129 def save(session, *arg, **kw):
136 def save(session, *arg, **kw):
130 value = wrapped(session, *arg, **kw)
137 value = wrapped(session, *arg, **kw)
131 session.save()
138 session.save()
132 return value
139 return value
133 save.__doc__ = wrapped.__doc__
140 save.__doc__ = wrapped.__doc__
134 return save
141 return save
135
142
136
143
137 def session_factory_from_settings(settings):
144 def session_factory_from_settings(settings):
138 """ Return a Pyramid session factory using Beaker session settings
145 """ Return a Pyramid session factory using Beaker session settings
139 supplied from a Paste configuration file"""
146 supplied from a Paste configuration file"""
140 prefixes = ('session.', 'beaker.session.')
147 prefixes = ('session.', 'beaker.session.')
141 options = {}
148 options = {}
142
149
150 # custom gather of our specific sqlalchemy session db configuration we need to translate this into a single entry
151 # dict because this is how beaker expects that.
152 sa_opts = {}
153
143 # Pull out any config args meant for beaker session. if there are any
154 # Pull out any config args meant for beaker session. if there are any
144 for k, v in settings.items():
155 for k, v in settings.items():
145 for prefix in prefixes:
156 for prefix in prefixes:
146 if k.startswith(prefix):
157 if k.startswith(prefix):
147 option_name = k[len(prefix):]
158 option_name = k[len(prefix):]
148 if option_name == 'cookie_on_exception':
159 if option_name == 'cookie_on_exception':
149 v = asbool(v)
160 v = asbool(v)
161 if option_name.startswith('sa.'):
162 sa_opts[option_name] = v
150 options[option_name] = v
163 options[option_name] = v
151
164
152 options = coerce_session_params(options)
165 options = coerce_session_params(options)
166 options['sa_opts'] = sa_opts
153 return BeakerSessionFactoryConfig(**options)
167 return BeakerSessionFactoryConfig(**options)
154
168
155
169
156 def includeme(config):
170 def includeme(config):
157 session_factory = session_factory_from_settings(config.registry.settings)
171 session_factory = session_factory_from_settings(config.registry.settings)
158 config.set_session_factory(session_factory)
172 config.set_session_factory(session_factory)
General Comments 0
You need to be logged in to leave comments. Login now