fixes
[unfold.git] / unfold / sessioncache.py
1 import uuid
2
3 from manifold.util.singleton import Singleton
4
5 from myslice.settings import logger
6
7 # the key attached to the session object, where we store
8 # the uuid attached to that session in this cache
9 cache_key = 'cached_uuid'
10
11 class _SessionExtension(object):
12     """
13     This object holds all the data we need to attach to a django session object
14     """
15
16     def __init__(self):
17         self.metadata = None
18         self.auth = None
19
20     def __repr__(self):
21         result = "<SessionExtension"
22         if self.metadata: result += " .metadata"
23         if self.auth:     result += " .auth"
24         result += ">"
25         return result
26
27 class SessionCache(dict):
28     """
29     As of django1.7, the session object as attached to a django request
30     gets JSON-serialized instead of pickled
31     This breaks our previous or passing data from request to request across
32     a given session - in particular for metadata and auth/session keys
33     Not that the problem is more with metadata as this is a class instance
34     and JSON cannot handle that
35     So instead we decorate the session object with a UID and retrieve all the rest 
36     from the present - singleton - cache instance
37     """
38
39     __metaclass__ = Singleton
40
41     def get_auth(self, request):
42         """
43         Get the auth previously attached to the request's session, or None
44         """
45         result = self._get(request, 'auth')
46         return result
47
48     def store_auth(self, request, auth):
49         """
50         Store the auth object attached to this request's session
51         create that extension if needed
52         """
53         return self._store(request, 'auth', auth)
54
55     def get_metadata(self, request):
56         """
57         retrieve metadata attached to this request's session, or None
58         """
59         return self._get(request, 'metadata')
60
61     def store_metadata(self, request, metadata):
62         """
63         Store the metadata object attached to this request's session
64         create that extension if needed
65         """
66         return self._store(request, 'metadata', metadata)
67
68     def _get(self, request, key):
69         "internal - retrieve key - do not create anything"
70         session = request.session
71         logger.debug("sessioncache._get_{} session={}".format(key, SessionCache._debug_session(session)))
72 #        self._debug(request)
73         if cache_key not in session:
74             return None
75         cached_uuid = session[cache_key]
76         if cached_uuid not in self:
77             return None
78         extension = self[cached_uuid]
79         return getattr(extension, key)
80
81     def _store(self, request, key, value):
82         "internal - set key, attach and create extension if needed"
83         session = request.session
84         if cache_key not in session:
85             session[cache_key] = uuid.uuid1().int
86         cached_uuid = session[cache_key]
87         if cached_uuid not in self:
88             self[cached_uuid] = _SessionExtension()
89         extension = self[cached_uuid]
90         setattr(extension, key, value)
91         logger.debug("sessioncache._store_{} session={}".format(key, SessionCache._debug_session(session)))
92 #        self._debug(request)
93
94     def end_session(self, request):
95         """
96         Clear all data related to this request's session has we are logging out
97         This is for garbage collection
98         """
99         session = request.session
100         logger.debug("SessionCache.end_session() {}".format(self._debug_session(session)))
101         if cache_key not in session:
102             return
103         cached_uuid = session[cache_key]
104         if cached_uuid in self:
105             del self[cached_uuid]
106
107     def _debug(self, request):
108         session = request.session
109         logger.debug("SessionCache: ---------- with session {}".format(self._debug_session(session)))
110         for k,v in self.iteritems():
111             logger.debug("SessionCache {} -> {}".format(k,v))
112         if cache_key not in session:
113             return
114         cached_uuid = session[cache_key]
115         if cached_uuid not in self:
116             return
117         extension = self[cached_uuid]
118         logger.debug("SessionCache: found extension {}".format(extension))
119         logger.debug("SessionCache: ----------")
120         
121     @staticmethod
122     def _debug_session(session):
123         result = ""
124         result += "{} x {}".format(session, session.keys())
125         if cache_key in session:
126             result += " <{} = {}>".format(cache_key, session[cache_key])
127         return result