[albatross-users] Session and validate_request()

Dave Cole djc at object-craft.com.au
Tue Mar 29 11:57:35 EST 2005


Denis Toporov wrote:
> Hi again,
> it seems like I'm in trouble again:)
> lets imagine I have modular random session application,
> and initialize session variables in main script (specified as start_page 
> script in application
> constructor) in validate_request() method.
> I hoped that validate_request() called on each request.
> The problem: if user have no actions for a while, session is dead 
> because of session timeout.
> And if user try to request after dead session any page he gets an 
> exception, because of session is dead,
> and no session variables any more. So he got no variable exception trace.
> 
> The way to avoid this is to put check of session
> variables existence in each .py module, but this is brute force method.
> Is any smart solution already exists for this kind of problem?

Random access applications are inherently difficult.  There is no 
escaping that.

The best approach to this sort of problem is to make your own execution 
context class that tests the contents of the session and enforce 
exceptional processing in the absence of required variables.

Something like this:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
from albatross import RandomModularSessionApp, SessionAppContext
from albatross.cgiapp import Request


class AppContext(SessionAppContext):

     def assert_user(self):
         if not hasattr(self.locals, '_user'):
             self.redirect('login')

     def assert_something_else(self):
         self.assert_user()
         if not hasattr(self.locals, '_something_else'):
             self.redirect('somepage')


class App(RandomModularSessionApp):

     def create_context(self):
         return AppContext(self)


app = App(base_url='myapp', page_path='pages', start_page='login',
           secret='mysecret', session_appid='myapp')


if __name__ == '__main__':
     app.run(Request())
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


Then for each page you need to do something like this:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
def page_process(ctx):
     ctx.assert_user()
     # prepare to display thispage


def page_display(ctx):
     ctx.run_template('thispage.html')
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

The redirect method on the execution context will raise Redirect 
exception that is handled within the normal application run() method.

Taking that sort of approach should make things easier.

Once that is working you might want to be able to go back to the 
originally requested page.  You could probably do that by doing 
something similar to the following:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class AppContext(SessionAppContext):

     def memo_redirect(self, page):
         ctx.locals._memo_page = self.locals.__page__
         self.add_session_vars('_memo_page')
         self.redirect(page)

     def memo_restore(self):
         try:
             page = ctx.locals._memo_page
         except AttributeError:
             return
         self.del_session_vars('_memo_page')
         self.redirect(page)


class App(RandomModularSessionApp):

     def load_page_module(self, ctx, page):
         RandomModularSessionApp.load_page_module(self, ctx, page)
         ctx.locals.__page__ = page
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Then instead of calling redirect() in your assert methods you would call 
memo_redirect().

The extension of the load_page_module() method is required because (for 
some reason) Albatross does not seem to be maintaining __page__ for 
random applications.

In the page_process() function for the assertion handling pages you can 
then call ctx.memo_restore().  If the method returns then the user was 
not visiting the page in response to an assertion, so some sort of 
normal application processing would need to be performed.

Hopefully that makes sense.

Note that none of the above code has been tested - it is only provided 
as an illustration.

- Dave

-- 
http://www.object-craft.com.au



More information about the Albatross-users mailing list