Code

Ticket #2548: session_middleware.15.diff

File session_middleware.15.diff, 10.0 KB (added by SmileyChris, 7 years ago)

Updated for session backend changes

Line 
1Index: django/contrib/sessions/middleware.py
2===================================================================
3--- django/contrib/sessions/middleware.py       (revision 6594)
4+++ django/contrib/sessions/middleware.py       (working copy)
5@@ -25,17 +25,15 @@
6             if accessed:
7                 patch_vary_headers(response, ('Cookie',))
8             if modified or settings.SESSION_SAVE_EVERY_REQUEST:
9-                if settings.SESSION_EXPIRE_AT_BROWSER_CLOSE:
10+                if request.session.get_expire_at_browser_close():
11                     max_age = None
12                     expires = None
13                 else:
14-                    max_age = settings.SESSION_COOKIE_AGE
15-                    rfcdate = formatdate(time.time() + settings.SESSION_COOKIE_AGE)
16-
17+                    max_age = request.session.get_max_age()
18+                    expiry_date = request.session.get_expiry_date()
19                     # Fixed length date must have '-' separation in the format
20                     # DD-MMM-YYYY for compliance with Netscape cookie standard
21-                    expires = datetime.datetime.strftime(datetime.datetime.utcnow() + \
22-                              datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE), "%a, %d-%b-%Y %H:%M:%S GMT")
23+                    expires = expiry_date.strftime('%a, %d-%b-%Y %H:%M:%S GMT')
24 
25                 # Save the seesion data and refresh the client cookie.
26                 request.session.save()
27Index: django/contrib/sessions/tests.py
28===================================================================
29--- django/contrib/sessions/tests.py    (revision 6594)
30+++ django/contrib/sessions/tests.py    (working copy)
31@@ -75,6 +75,100 @@
32 
33 >>> s.pop('some key', 'does not exist')
34 'does not exist'
35+
36+#########################
37+# Custom session expiry #
38+#########################
39+
40+>>> from django.conf import settings
41+>>> from datetime import datetime, timedelta
42+
43+>>> td10 = timedelta(seconds=10)
44+
45+# A normal session has a max age equal to settings
46+>>> s.get_max_age() == settings.SESSION_COOKIE_AGE
47+True
48+
49+# So does a custom session with an idle expiration time of 0 (but it'll expire
50+# at browser close)
51+>>> s.set_expiry(0)
52+>>> s.get_max_age() == settings.SESSION_COOKIE_AGE
53+True
54+
55+# Custom session idle expiration time
56+>>> s.set_expiry(10)
57+>>> delta = s.get_expiry_date() - datetime.utcnow()
58+>>> delta.seconds in (9, 10)
59+True
60+>>> age = s.get_max_age()
61+>>> age in (9, 10)
62+True
63+
64+# Custom session fixed expiry date (timedelta)
65+>>> s.set_expiry(td10)
66+>>> delta = s.get_expiry_date() - datetime.utcnow()
67+>>> delta.seconds in (9, 10)
68+True
69+>>> age = s.get_max_age()
70+>>> age in (9, 10)
71+True
72+
73+# Custom session fixed expiry date (fixed datetime)
74+>>> s.set_expiry(datetime.utcnow() + td10)
75+>>> delta = s.get_expiry_date() - datetime.utcnow()
76+>>> delta.seconds in (9, 10)
77+True
78+>>> age = s.get_max_age()
79+>>> age in (9, 10)
80+True
81+
82+# Set back to default session age
83+>>> s.set_expiry(None)
84+>>> s.get_max_age() == settings.SESSION_COOKIE_AGE
85+True
86+
87+# Allow to set back to default session age even if no alternate has been set
88+>>> s.set_expiry(None)
89+
90+
91+# We're changing the setting then reverting back to the original setting at the
92+# end of these tests.
93+>>> original_expire_at_browser_close = settings.SESSION_EXPIRE_AT_BROWSER_CLOSE
94+>>> settings.SESSION_EXPIRE_AT_BROWSER_CLOSE = False
95+
96+# Custom session age
97+>>> s.set_expiry(10)
98+>>> s.get_expire_at_browser_close()
99+False
100+
101+# Custom expire-at-browser-close
102+>>> s.set_expiry(0)
103+>>> s.get_expire_at_browser_close()
104+True
105+
106+# Default session age
107+>>> s.set_expiry(None)
108+>>> s.get_expire_at_browser_close()
109+False
110+
111+>>> settings.SESSION_EXPIRE_AT_BROWSER_CLOSE = True
112+
113+# Custom session age
114+>>> s.set_expiry(10)
115+>>> s.get_expire_at_browser_close()
116+False
117+
118+# Custom expire-at-browser-close
119+>>> s.set_expiry(0)
120+>>> s.get_expire_at_browser_close()
121+True
122+
123+# Default session age
124+>>> s.set_expiry(None)
125+>>> s.get_expire_at_browser_close()
126+True
127+
128+>>> settings.SESSION_EXPIRE_AT_BROWSER_CLOSE = original_expire_at_browser_close
129 """
130 
131 if __name__ == '__main__':
132Index: django/contrib/sessions/backends/base.py
133===================================================================
134--- django/contrib/sessions/backends/base.py    (revision 6594)
135+++ django/contrib/sessions/backends/base.py    (working copy)
136@@ -4,6 +4,7 @@
137 import random
138 import sys
139 import time
140+from datetime import datetime, timedelta
141 from django.conf import settings
142 from django.core.exceptions import SuspiciousOperation
143 
144@@ -120,6 +121,54 @@
145 
146     _session = property(_get_session)
147 
148+    def get_max_age(self):
149+        expiry = self.get('_session_expiry')
150+        if not expiry:   # Checks both None and 0 cases
151+            return settings.SESSION_COOKIE_AGE
152+        if not isinstance(expiry, datetime):
153+            return expiry
154+        delta = expiry - datetime.utcnow()
155+        return delta.days * 86400 + delta.seconds
156+
157+    def get_expiry_date(self):
158+        "Returns the expiry date (in UTC)"
159+        expiry = self.get('_session_expiry', settings.SESSION_COOKIE_AGE)
160+        if isinstance(expiry, datetime):
161+            return expiry
162+        return datetime.utcnow() + timedelta(seconds=expiry)
163+
164+    def set_expiry(self, value):
165+        """
166+        Sets a custom expiration for the session. ``value`` can be an integer, a
167+        Python ``datetime`` or ``timedelta`` object or ``None``.
168+
169+        If ``value`` is an integer, the session will expire after that many
170+        seconds of inactivity. If set to ``0`` then the session will expire on
171+        browser close.
172+
173+        If ``value`` is a ``datetime`` or ``timedelta`` object, the session
174+        will expire at that specific future time (``datetime`` objects should be
175+        UTC).
176+
177+        If ``value`` is ``None``, the session uses the global session expiry
178+        policy.
179+        """
180+        if value is None:
181+            # Remove any custom expiration for this session.
182+            try:
183+                del self['_session_expiry']
184+            except KeyError:
185+                pass
186+            return
187+        if isinstance(value, timedelta):
188+            value = datetime.utcnow() + value
189+        self['_session_expiry'] = value
190+
191+    def get_expire_at_browser_close(self):
192+        if self.get('_session_expiry') is None:
193+            return settings.SESSION_EXPIRE_AT_BROWSER_CLOSE
194+        return self.get('_session_expiry') == 0
195+
196     # Methods that child classes must implement.
197 
198     def exists(self, session_key):
199Index: AUTHORS
200===================================================================
201--- AUTHORS     (revision 6594)
202+++ AUTHORS     (working copy)
203@@ -311,7 +311,7 @@
204     tstromberg@google.com
205     Makoto Tsuyuki <mtsuyuki@gmail.com>
206     tt@gurgle.no
207-    Amit Upadhyay
208+    Amit Upadhyay <http://www.amitu.com/blog/>
209     Geert Vanderkelen
210     viestards.lists@gmail.com
211     George Vilches <gav@thataddress.com>
212Index: docs/sessions.txt
213===================================================================
214--- docs/sessions.txt   (revision 6594)
215+++ docs/sessions.txt   (working copy)
216@@ -80,42 +80,81 @@
217 It implements the following standard dictionary methods:
218 
219     * ``__getitem__(key)``
220+
221       Example: ``fav_color = request.session['fav_color']``
222 
223     * ``__setitem__(key, value)``
224+
225       Example: ``request.session['fav_color'] = 'blue'``
226 
227     * ``__delitem__(key)``
228+
229       Example: ``del request.session['fav_color']``. This raises ``KeyError``
230       if the given ``key`` isn't already in the session.
231 
232     * ``__contains__(key)``
233+
234       Example: ``'fav_color' in request.session``
235 
236     * ``get(key, default=None)``
237+
238       Example: ``fav_color = request.session.get('fav_color', 'red')``
239 
240     * ``keys()``
241 
242     * ``items()``
243 
244-It also has these three methods:
245+It also has these methods:
246 
247     * ``set_test_cookie()``
248+
249       Sets a test cookie to determine whether the user's browser supports
250       cookies. Due to the way cookies work, you won't be able to test this
251       until the user's next page request. See "Setting test cookies" below for
252       more information.
253 
254     * ``test_cookie_worked()``
255+
256       Returns either ``True`` or ``False``, depending on whether the user's
257       browser accepted the test cookie. Due to the way cookies work, you'll
258       have to call ``set_test_cookie()`` on a previous, separate page request.
259       See "Setting test cookies" below for more information.
260 
261     * ``delete_test_cookie()``
262+
263       Deletes the test cookie. Use this to clean up after yourself.
264 
265+    * ``set_expiry(value)``
266+
267+      Sets a custom expiration for the session.
268+
269+      If ``value`` is an integer, the session will expire after that many
270+      seconds of inactivity. If set to ``0`` then the session will expire when
271+      the user's browser is closed.
272+
273+      If ``value`` is a ``datetime`` or ``timedelta`` object, the session will
274+      expire at that specific time.
275+
276+      If ``value`` is ``None``, the session reverts to using the global session
277+      expiry policy.
278+
279+    * ``get_max_age()``
280+
281+      Returns the number of seconds until this session expires. For sessions
282+      with no custom expiration (or those set to expire at browser close), this
283+      will equal ``settings.SESSION_COOKIE_AGE``.
284+
285+    * ``get_expiry_date()``
286+
287+      Returns the date this session will expire. For sessions with no custom
288+      expiration (or those set to expire at browser close), this will equal the
289+      date ``settings.SESSION_COOKIE_AGE`` seconds from now.
290+
291+    * ``get_expire_at_browser_close()``
292+
293+      Returns either ``True`` or ``False``, depending on whether this session
294+      will expire when the user's browser is closed.
295+
296 You can edit ``request.session`` at any point in your view. You can edit it
297 multiple times.
298 
299@@ -276,6 +315,10 @@
300 her browser. Use this if you want people to have to log in every time they open
301 a browser.
302 
303+This setting is a global default and can be overwritten by explicitly calling
304+``request.session.set_expiry()`` as described above in
305+`using sessions in views`_.
306+
307 Clearing the session table
308 ==========================
309