source: main/waeup.cas/trunk/waeup/cas/db.py @ 10494

Last change on this file since 10494 was 10419, checked in by uli, 11 years ago

Make sure memory-based database is thread-oriented (all connections should share the same memory-DB).

File size: 4.0 KB
Line 
1# components to store tickets in a database
2# we use sqlite3
3import time
4from sqlalchemy import (
5    create_engine, Column, Integer, Float, String, Boolean, MetaData)
6from sqlalchemy.ext.declarative import declarative_base
7from sqlalchemy.orm import sessionmaker, scoped_session
8from sqlalchemy.pool import StaticPool
9
10
11Base = declarative_base()
12
13
14class ServiceTicket(Base):
15    __tablename__ = 'service_tickets'
16
17    id = Column(Integer, primary_key=True)
18    ticket = Column(String(255), nullable=False)
19    ts = Column(Float, nullable=False)
20    service = Column(String(2048), nullable=True)
21    user = Column(String(512), nullable=False)
22    sso = Column(Boolean, nullable=False, default=True)
23
24    def __init__(self, ticket, user, service=None, sso=True, timestamp=None):
25        if timestamp is None:
26            timestamp = time.time()
27        self.ticket = ticket
28        self.ts = timestamp
29        self.service = service
30        self.user = user
31        self.sso = sso
32
33    def __repr__(self):
34        return "ServiceTicket('%s', '%s', '%s', %s, %s)" % (
35            self.ticket, self.user, self.service, self.sso, self.ts)
36
37
38class LoginTicket(Base):
39    __tablename__ = 'login_tickets'
40
41    ticket = Column(String(255), primary_key=True)
42    ts = Column(Float, nullable=False)
43
44    def __init__(self, ticket, timestamp=None):
45        if timestamp is None:
46            timestamp = time.time()
47        self.ticket = ticket
48        self.ts = timestamp
49
50    def __repr__(self):
51        return "LoginTicket('%s', %s)" % (self.ticket, self.ts)
52
53
54class TicketGrantingCookie(Base):
55    __tablename__ = 'ticket_granting_cookies'
56
57    value = Column(String(255), primary_key=True)
58    ts = Column(Float, nullable=False)
59
60    def __init__(self, value, timestamp=None):
61        if timestamp is None:
62            timestamp = time.time()
63        self.value = value
64        self.ts = timestamp
65
66    def __repr__(self):
67        return "TicketGrantingCookie('%s', %s)" % (self.value, self.ts)
68
69
70Session = scoped_session(sessionmaker())
71
72
73class DB(object):
74    """Abstract database to make data persistent.
75
76    Creates a database identified by `connection_string` if it does
77    not exist and initializes sessions.
78    """
79    @property
80    def session(self):
81        return Session
82
83    def __init__(self, connection_string):
84        args = {}
85        if connection_string in ('sqlite:///', 'sqlite:///:memory:'):
86            # make sure all threads access the same memory
87            args = dict(connect_args={'check_same_thread': False},
88                        poolclass=StaticPool)
89        self.engine = create_engine(connection_string, **args)
90        self.metadata = MetaData()
91        Base.metadata.create_all(self.engine)
92        Session.configure(bind=self.engine)
93
94    def add(self, item):
95        """Insert `item` into database.
96
97        `item` must be an instance of the database content types
98        defined in this module, normally some `Ticket` instance.
99        """
100        Session.add(item)
101        Session.commit()
102
103    def delete(self, item):
104        """Delete `item` from database.
105
106        `item must be an instance of the database content types
107        defined in this module, normally some `Ticket` instance.
108        """
109        Session.delete(item)
110        Session.commit()
111
112    def query(self, *args, **kw):
113        return Session.query(*args, **kw)
114
115
116class DBSessionContext(object):
117    """A context manager providing database sessions.
118
119    Creates a new (threadlocal) database session when entering and
120    tears down the session after leaving the context.
121
122    Tearing down includes committing transactions and closing the
123    connection.
124
125    Meant to be used as a wrapper for web request handlers, such, that
126    a session is created when a request comes in and released when
127    the response is ready to be delivered.
128
129    This context manager does *not* catch any exceptions.
130    """
131    def __enter__(self):
132        return Session()
133
134    def __exit__(self, *args, **kw):
135        if args or kw:
136            Session.rollback()
137        Session.remove()
138        return False
Note: See TracBrowser for help on using the repository browser.