Source

wsgitalk / examples3-lifecycle / lifecycle.py

'''
Now a semi-real-world example of what you can do with middleware.

Let's say we have a requirement that our site responds differently based on a
few different criteria:

 * Given a 'launch date', we want to serve up a 'prelaunch page' if today's
   date is before the launch date
 * Similarly, given an 'expiration date', if today's date is after the
   expiration date then we serve up an 'expired page'
 * Finally, given a 'maintenance flag', we can toggle the site between its
   normal functioning state and a maintenance page that says the site is
   temporarily offline.

If none of these conditions apply then we just want to pass the request through
to the base app.

This is a perfect place to use middleware! The great thing is that this
middleware is used like a library, it can be imported into any WSGI app and
used right away.

See run_with_lifecycle.py for an example of this middleware being used on the
app that was created in base_app.py.
'''

from datetime import datetime
from webob import Request

## utils ######################################################################

class StaticPageApp(object):
    '''A WSGI app that serves up a static HTML file.'''
    def __init__(self, filename):
        self.filename = filename
    def __call__(self, environ, start_response):
        contents = open(self.filename).read()
        start_response('200 OK', [('content-type', 'text/html')])
        yield contents

def parse_date(datestring):
    '''Parses "2009-01-01 00:00" into datetime(2009, 1, 1, 0, 0).'''
    return datetime.strptime(datestring, '%Y-%m-%d %H:%M')

## lifecycle middleware #######################################################

LIFECYCLE_KEYS = ['in_maintenance', 'date_launch', 'date_expire', 'page_prelaunch', 'page_expired', 'page_maintenance']

class LifecycleMiddleware(object):
    def __init__(self, app, config=None):
        self.app = app
        if config is None:
            raise ValueError("Missing `config` keyword argument.")
        if set(config.keys()) != set(LIFECYCLE_KEYS):
            raise ValueError("Missing required keys in `config`. Got: %s -- Expected: %s." % (repr(config.keys()), repr(LIFECYCLE_KEYS)))

        self.in_maintenance = config['in_maintenance']
        self.date_launch = parse_date(config['date_launch'])
        self.date_expire = parse_date(config['date_expire'])
        self.prelaunch_app = StaticPageApp(config['page_prelaunch'])
        self.expired_app = StaticPageApp(config['page_expired'])
        self.maint_app = StaticPageApp(config['page_maintenance'])

    def __call__(self, environ, start_response):
        req = Request(environ)
        req.remove_conditional_headers()

        if self.in_maintenance:
            #maintenance flag is True, show maint page
            resp = self.maint_app
        elif datetime.now() < self.date_launch:
            #current date is before prelaunch, show prelaunch page
            resp = self.prelaunch_app
        elif datetime.now() > self.date_expire:
            #current date is after expired date, show expired page
            resp = self.expired_app
        else:
            #otherwise pass everything through to the original app
            resp = req.get_response(self.app)
        return resp(environ, start_response)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.