view commentator/middleware.py @ 5:451169e51935

work to make cache expiry work
author k0s <k0scist@gmail.com>
date Fri, 26 Feb 2010 12:27:25 -0500
parents d0d8524d9495
children
line wrap: on
line source

"""
request dispatcher:
data persisting across requests should go here
"""

import os
import re
import time

from handlers import PostComment
#from model import CouchComments
from model import PickleComments
from genshi.template import TemplateLoader
from lxml import etree
from lxmlmiddleware import LXMLMiddleware
from paste.fileapp import FileApp
from pkg_resources import resource_filename
from string import Template
from webob import Request, Response, exc

class LaxTemplate(Template):
    idpattern = r'[_a-z0-9]+'

class Commentator(LXMLMiddleware):

    ### class level variables
    defaults = { 'auto_reload': 'False',
                 'database': 'commentator',
                 'date_format': '%H:%M %m/%d/%Y',
                 'template_dirs': '',
                 'pattern': '.*',
                 'path': 'html',
                 'url': '.comment',
                 'template': 'comment.html' }

    def __init__(self, app, **kw):

        self.app = app

        # set instance parameters from kw and defaults
        for key in self.defaults:
            setattr(self, key, kw.get(key, self.defaults[key]))
        self.auto_reload = self.auto_reload.lower() == 'true'

        # request handlers
        self.handlers = [ PostComment ]

        # template loader
        self.template_dirs = self.template_dirs.split()
        self.template_dirs.append(resource_filename(__name__, 'templates'))
        self.loader = TemplateLoader(self.template_dirs,
                                     auto_reload=self.auto_reload)

        # URL,path
        assert '#' in self.pattern
        self.url_pattern, self.xpath_pattern = self.pattern.split('#', 1)
        assert '->' in self.xpath_pattern
        self.xpath_pattern, self.mapping = [i.strip() for i in self.xpath_pattern.split('->')]

        # string template for URL substitution
        self.mapping = LaxTemplate(self.mapping)

        # backend: comment storage
        self.model = PickleComments(self.database)

    def __call__(self, environ, start_response):

        # get a request object
        request = Request(environ)

        # get the path 
        path = request.path_info.strip('/').split('/')
        if path == ['']:
            path = []
        request.environ['path'] = path

        # XXX save the path;  not sure why i need to do this
        environ['commentator.path_info'] = request.path_info

        # match the request to a handler
        for h in self.handlers:
            handler = h.match(self, request)
            if handler is not None:
                break
        else:
            return LXMLMiddleware.__call__(self, environ, start_response)

        # get response
        res = handler()
        return res(environ, start_response)

    def manipulate(self, request, response, tree):
        url_match = re.match(self.url_pattern, request.environ['commentator.path_info'])
        if not url_match:
            return tree

        # make string template of the groups
        groups_dict = dict([(str(index+1), value) 
                         for index, value in enumerate(url_match.groups())])

        last_modified = None
        commentable = False
        for element in tree.findall(self.xpath_pattern):
            commentable = True

            # get url
            str_dict = groups_dict.copy()
            for key in element.keys():
                str_dict[key] = element.get(key)
            uri = self.mapping.substitute(str_dict)

            # genshi data
            data = {}
            data['comments'] = self.model.comments(uri)
            if data['comments']:
                _last_modified = data['comments'][-1]['date'] 
                if last_modified is None:
                    last_modified = _last_modified
                else:
                    last_modified = max(last_modified, _last_modified)
            data['action'] = '%s/%s' % (uri, self.url)
            data['date_format'] = self.date_format
            data['request'] = request

            # render template
            template = self.loader.load(self.template)
            comments = template.generate(**data).render()
            comments = etree.fromstring(comments)
            element.append(comments)

        if commentable:
            response.cache_expires(0)

        if last_modified: # there are comments
            page_age = time.mktime(response.last_modified.timetuple())
            comments_age = time.mktime(last_modified.timetuple())
            if comments_age > page_age:
                response.last_modified = comments_age

        return tree