Sessions - db backed
Manage sessions and save them in the database.
- associate with users?
- devices?
1import time
2from importlib import import_module
3
4from plain.runtime import settings
5from plain.sessions.backends.base import UpdateError
6from plain.sessions.exceptions import SessionInterrupted
7from plain.utils.cache import patch_vary_headers
8from plain.utils.http import http_date
9
10
11class SessionMiddleware:
12 def __init__(self, get_response):
13 self.get_response = get_response
14 engine = import_module(settings.SESSION_ENGINE)
15 self.SessionStore = engine.SessionStore
16
17 def __call__(self, request):
18 session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
19 request.session = self.SessionStore(session_key)
20
21 response = self.get_response(request)
22
23 """
24 If request.session was modified, or if the configuration is to save the
25 session every time, save the changes and set a session cookie or delete
26 the session cookie if the session has been emptied.
27 """
28 try:
29 accessed = request.session.accessed
30 modified = request.session.modified
31 empty = request.session.is_empty()
32 except AttributeError:
33 return response
34 # First check if we need to delete this cookie.
35 # The session should be deleted only if the session is entirely empty.
36 if settings.SESSION_COOKIE_NAME in request.COOKIES and empty:
37 response.delete_cookie(
38 settings.SESSION_COOKIE_NAME,
39 path=settings.SESSION_COOKIE_PATH,
40 domain=settings.SESSION_COOKIE_DOMAIN,
41 samesite=settings.SESSION_COOKIE_SAMESITE,
42 )
43 patch_vary_headers(response, ("Cookie",))
44 else:
45 if accessed:
46 patch_vary_headers(response, ("Cookie",))
47 if (modified or settings.SESSION_SAVE_EVERY_REQUEST) and not empty:
48 if request.session.get_expire_at_browser_close():
49 max_age = None
50 expires = None
51 else:
52 max_age = request.session.get_expiry_age()
53 expires_time = time.time() + max_age
54 expires = http_date(expires_time)
55 # Save the session data and refresh the client cookie.
56 # Skip session save for 5xx responses.
57 if response.status_code < 500:
58 try:
59 request.session.save()
60 except UpdateError:
61 raise SessionInterrupted(
62 "The request's session was deleted before the "
63 "request completed. The user may have logged "
64 "out in a concurrent request, for example."
65 )
66 response.set_cookie(
67 settings.SESSION_COOKIE_NAME,
68 request.session.session_key,
69 max_age=max_age,
70 expires=expires,
71 domain=settings.SESSION_COOKIE_DOMAIN,
72 path=settings.SESSION_COOKIE_PATH,
73 secure=settings.SESSION_COOKIE_SECURE or None,
74 httponly=settings.SESSION_COOKIE_HTTPONLY or None,
75 samesite=settings.SESSION_COOKIE_SAMESITE,
76 )
77 return response