Code

*** empty log message ***
[roundup.git] / roundup / backends / sessions.py
1 #$Id: sessions.py,v 1.10 2004-02-26 04:20:45 drkorg Exp $
2 """This module defines a very basic store that's used by the CGI interface
3 to store session and one-time-key information.
5 Yes, it's called "sessions" - because originally it only defined a session
6 class. It's now also used for One Time Key handling too.
7 """
8 __docformat__ = 'restructuredtext'
10 import anydbm, whichdb, os, marshal, time
12 class BasicDatabase:
13     ''' Provide a nice encapsulation of an anydbm store.
15         Keys are id strings, values are automatically marshalled data.
16     '''
17     _db_type = None
19     def __init__(self, config):
20         self.config = config
21         self.dir = config.DATABASE
22         # ensure files are group readable and writable
23         os.umask(0002)
25     def clear(self):
26         path = os.path.join(self.dir, self.name)
27         if os.path.exists(path):
28             os.remove(path)
29         elif os.path.exists(path+'.db'):    # dbm appends .db
30             os.remove(path+'.db')
32     def cache_db_type(self, path):
33         ''' determine which DB wrote the class file, and cache it as an
34             attribute of __class__ (to allow for subclassed DBs to be
35             different sorts)
36         '''
37         db_type = ''
38         if os.path.exists(path):
39             db_type = whichdb.whichdb(path)
40             if not db_type:
41                 raise hyperdb.DatabaseError, "Couldn't identify database type"
42         elif os.path.exists(path+'.db'):
43             # if the path ends in '.db', it's a dbm database, whether
44             # anydbm says it's dbhash or not!
45             db_type = 'dbm'
46         self.__class__._db_type = db_type
48     def get(self, infoid, value):
49         db = self.opendb('c')
50         try:
51             if db.has_key(infoid):
52                 values = marshal.loads(db[infoid])
53             else:
54                 return None
55             return values.get(value, None)
56         finally:
57             db.close()
59     def getall(self, infoid):
60         db = self.opendb('c')
61         try:
62             try:
63                 return marshal.loads(db[infoid])
64             except KeyError:
65                 raise KeyError, 'No such One Time Key "%s"'%infoid
66         finally:
67             db.close()
69     def set(self, infoid, **newvalues):
70         db = self.opendb('c')
71         try:
72             if db.has_key(infoid):
73                 values = marshal.loads(db[infoid])
74             else:
75                 values = {}
76             values.update(newvalues)
77             db[infoid] = marshal.dumps(values)
78         finally:
79             db.close()
81     def list(self):
82         db = self.opendb('r')
83         try:
84             return db.keys()
85         finally:
86             db.close()
88     def destroy(self, infoid):
89         db = self.opendb('c')
90         try:
91             if db.has_key(infoid):
92                 del db[infoid]
93         finally:
94             db.close()
96     def opendb(self, mode):
97         '''Low-level database opener that gets around anydbm/dbm
98            eccentricities.
99         '''
100         # figure the class db type
101         path = os.path.join(os.getcwd(), self.dir, self.name)
102         if self._db_type is None:
103             self.cache_db_type(path)
105         db_type = self._db_type
107         # new database? let anydbm pick the best dbm
108         if not db_type:
109             return anydbm.open(path, 'c')
111         # open the database with the correct module
112         dbm = __import__(db_type)
113         return dbm.open(path, mode)
115     def commit(self):
116         pass
118     def updateTimestamp(self, sessid):
119         self.set(sessid, **{self.timestamp: time.time()})
121     def clean(self, now):
122         """Age sessions, remove when they haven't been used for a week.
123         """
124         week = 60*60*24*7
125         for sessid in self.list():
126             interval = now - self.get(sessid, self.timestamp)
127             if interval > week:
128                 self.destroy(sessid)
130 class Sessions(BasicDatabase):
131     name = 'sessions'
132     timestamp = 'last_use'
134 class OneTimeKeys(BasicDatabase):
135     name = 'otks'
136     timestamp = '__time'