########################################################################
# $Header: /var/local/cvsroot/4Suite/Ft/Server/Server/Drivers/SessionManager.py,v 1.4 2005/01/01 17:22:06 uogbuji Exp $
"""
Login session operations for the driver

Copyright 2004 Fourthought, Inc. (USA).
Detailed license and copyright information: http://4suite.org/COPYRIGHT
Project home, documentation, distributions: http://4suite.org/
"""

import time, cPickle
from Ft.Server.Server import FtServerServerException, Error
from Ft.Server.Common import AclConstants, ResourceTypes
from Ft.Lib import Time, Uuid
DEFAULT_SESSION_TIME_TO_LIVE = 60*15 #15 mins

class SessionManager:
    def createSession(self, key, userName, password,
                      ttl=DEFAULT_SESSION_TIME_TO_LIVE):
        """
        Create a new session object

        key - session key to use
        userName - user name for log in
        password - password for log in
        ttl - session time to live, in seconds, default 15 minutes
        """
        ttl = ttl or DEFAULT_SESSION_TIME_TO_LIVE
        #Append a prefix for underlying datastores that won't allow numerically leading filenames (FlatFile, for instance)
        sid = "ftsession-" + Uuid.UuidAsString(Uuid.GenerateUuid())

        session = {'USERNAME':userName,
                   'PASSWORD':password,
                   'EXPIRE':int(time.time() + ttl + 0.5),
                   'TTL': ttl + 0.5,
                   'KEY':key,
                   'DATA':{}}

        if self._driver.hasFile(sid, ResourceTypes.SESSION_DATA):
            #Its time for it to go
            self._driver.deleteFile(sid, ResourceTypes.SESSION_DATA)
        self._driver.createFile(sid, ResourceTypes.SESSION_DATA,
                                cPickle.dumps(session))
        return sid

    def retrieveSession(self, sid, key):
        """Get and validate a session"""
        driver = apply(self._driverMod.Begin, (), self._driverProperties)

        try:
            if not driver.hasFile(sid, ResourceTypes.SESSION_DATA):
                raise FtServerServerException(Error.INVALID_SESSION)

            session = cPickle.loads(driver.fetchFile(sid, ResourceTypes.SESSION_DATA).encode('latin1'))

            if session['EXPIRE'] < time.time():
                driver.deleteFile(sid,ResourceTypes.SESSION_DATA)
                raise FtServerServerException(Error.INVALID_SESSION)

            if session['KEY'] != key:
                driver.deleteFile(sid,ResourceTypes.SESSION_DATA)
                raise FtServerServerException(Error.INVALID_SESSION)

            session['EXPIRE'] = time.time() + session.get('TTL', 0)

            driver.updateFile(sid, ResourceTypes.SESSION_DATA,
                              cPickle.dumps(session))
        finally:
            driver.commit()

        #Now, do a login
        self.login(session['USERNAME'], session['PASSWORD'])
        return

    def setSessionData(self, sid, key, value):
        self._verifyTx()
        if not self._driver.hasFile(sid, ResourceTypes.SESSION_DATA):
            raise FtServerServerException(Error.INVALID_SESSION)

        session = cPickle.loads(self._driver.fetchFile(
            sid, ResourceTypes.SESSION_DATA))
        session['DATA'][key] = value
        self._driver.updateFile(sid, ResourceTypes.SESSION_DATA,
                                cPickle.dumps(session))

    def deleteSessionData(self, sid, key):
        self._verifyTx()
        if not self._driver.hasFile(sid, ResourceTypes.SESSION_DATA):
            raise FtServerServerException(Error.INVALID_SESSION)

        session = cPickle.loads(self._driver.fetchFile(
            sid, ResourceTypes.SESSION_DATA
            ))
        if session['DATA'].has_key(key):
            del session['DATA'][key]

        self._driver.updateFile(
            sid, ResourceTypes.SESSION_DATA, cPickle.dumps(session)
            )

    def getSessionData(self, sid, key):
        self._verifyTx()
        if not self._driver.hasFile(sid,ResourceTypes.SESSION_DATA):
            raise FtServerServerException(Error.INVALID_SESSION)

        session = cPickle.loads(self._driver.fetchFile(
            sid, ResourceTypes.SESSION_DATA))

        return session['DATA'].get(key)

    def getSessionExpiration(self,sid):
        self._verifyTx()
        if not self._driver.hasFile(sid, ResourceTypes.SESSION_DATA):
            raise FtServerServerException(Error.INVALID_SESSION)

        session = cPickle.loads(self._driver.fetchFile(
            sid, ResourceTypes.SESSION_DATA
            ))

        return session['EXPIRE']

    def invalidateSession(self, sid):
        self._verifyTx()
        if not self._driver.hasFile(sid, ResourceTypes.SESSION_DATA):
            raise FtServerServerException(Error.INVALID_SESSION)
        self._driver.deleteFile(sid, ResourceTypes.SESSION_DATA)
        return
    
