Mercurial > p > roundup > code
view roundup/backends/sessions_rdbms.py @ 8240:1189c742e4b3
fix: crash roundup-admin perftest password without rounds= argument.
If the rounds value is taken from the config file, it doesn't need to
be parsed into an int.
| author | John Rouillard <rouilj@ieee.org> |
|---|---|
| date | Mon, 30 Dec 2024 02:59:27 -0500 |
| parents | fe0091279f50 |
| children | ee17f62c8341 |
line wrap: on
line source
"""This module defines a very basic store that's used by the CGI interface to store session and one-time-key information. Yes, it's called "sessions" - because originally it only defined a session class. It's now also used for One Time Key handling too. """ __docformat__ = 'restructuredtext' import time from roundup.anypy.html import html_escape as escape from roundup.backends.sessions_common import SessionCommon class BasicDatabase(SessionCommon): ''' Provide a nice encapsulation of an RDBMS table. Keys are id strings, values are automatically marshalled data. ''' name = None def __init__(self, db): self.db = db self.conn, self.cursor = self.db.sql_open_connection() def clear(self): self.cursor.execute('delete from %ss' % self.name) def exists(self, infoid): n = self.name self.cursor.execute('select count(*) from %ss where %s_key=%s' % (n, n, self.db.arg), (infoid,)) return int(self.cursor.fetchone()[0]) _marker = [] def get(self, infoid, value, default=_marker): n = self.name self.cursor.execute('select %s_value from %ss where %s_key=%s' % (n, n, n, self.db.arg), (infoid,)) res = self.cursor.fetchone() if not res: if default != self._marker: return default raise KeyError('No such %s "%s"' % (self.name, escape(infoid))) values = eval(res[0]) return values.get(value, None) def getall(self, infoid): n = self.name self.cursor.execute('select %s_value from %ss where %s_key=%s' % (n, n, n, self.db.arg), (infoid,)) res = self.cursor.fetchone() if not res: raise KeyError('No such %s "%s"' % (self.name, escape(infoid))) return eval(res[0]) def set(self, infoid, **newvalues): """ Store all newvalues under key infoid with a timestamp in database. If newvalues['__timestamp'] exists and is representable as a floating point number (i.e. could be generated by time.time()), that value is used for the <name>_time column in the database. """ c = self.cursor n = self.name a = self.db.arg c.execute('select %s_value from %ss where %s_key=%s' % (n, n, n, a), (infoid,)) res = c.fetchone() timestamp = time.time() if res: values = eval(res[0]) else: values = {} if '__timestamp' in newvalues: try: # __timestamp must be representable as a float. Check it. timestamp = float(newvalues['__timestamp']) except ValueError: if res: # keep the original timestamp del(newvalues['__timestamp']) else: # here timestamp is the new timestamp newvalues['__timestamp'] = timestamp values.update(newvalues) if res: sql = ('update %ss set %s_value=%s, %s_time=%s ' 'where %s_key=%s' % (n, n, a, n, a, n, a)) args = (repr(values), timestamp, infoid) else: sql = 'insert into %ss (%s_key, %s_time, %s_value) '\ 'values (%s, %s, %s)' % (n, n, n, n, a, a, a) args = (infoid, timestamp, repr(values)) c.execute(sql, args) def list(self): c = self.cursor n = self.name c.execute('select %s_key from %ss' % (n, n)) return [res[0] for res in c.fetchall()] def destroy(self, infoid): self.cursor.execute('delete from %ss where %s_key=%s' % (self.name, self.name, self.db.arg), (infoid,)) def updateTimestamp(self, infoid): """ don't update every hit - once a minute should be OK """ now = time.time() self.cursor.execute('''update %ss set %s_time=%s where %s_key=%s ''' '''and %s_time < %s''' % (self.name, self.name, self.db.arg, self.name, self.db.arg, self.name, self.db.arg), (now, infoid, now-60)) def clean(self): ''' Remove session records that haven't been used for a week. ''' now = time.time() week = 60*60*24*7 old = now - week self.cursor.execute('delete from %ss where %s_time < %s' % (self.name, self.name, self.db.arg), (old, )) def commit(self): self.log_info('commit %s' % self.name) self.conn.commit() self.cursor = self.conn.cursor() def lifetime(self, item_lifetime=0): """Return the proper timestamp for a key with key_lifetime specified in seconds. Default lifetime is 0. """ now = time.time() week = 60*60*24*7 return now - week + item_lifetime def close(self): self.conn.close() class Sessions(BasicDatabase): name = 'session' class OneTimeKeys(BasicDatabase): name = 'otk' # vim: set et sts=4 sw=4 :
