terom@5: terom@7: """ terom@7: Handling page requests terom@7: """ terom@7: terom@8: # for filesystem ops terom@8: import os, os.path terom@7: terom@8: # for ResponseError terom@8: import http terom@8: terom@8: # for TemplatePage terom@8: import template terom@8: terom@8: # path to directory containing the page heirarcy terom@8: PAGE_DIR = "pages" terom@8: terom@8: class PageError (http.ResponseError) : terom@8: """ terom@8: Error looking up/handling a page terom@8: """ terom@8: terom@8: pass terom@8: terom@8: class Page (object) : terom@8: """ terom@8: This object represents the information about our attempt to render some specific page terom@8: """ terom@8: terom@8: def __init__ (self, url, path, basename, url_tail) : terom@8: """ terom@8: Initialize the page at the given location terom@8: terom@8: @param url the URL leading to this page terom@8: @param path the filesystem path to this page's file terom@8: @param basename the filesystem name of this page's file, without the file extension terom@8: @param url_trail trailing URL for this page terom@8: """ terom@8: terom@8: # store terom@8: self.url = url terom@8: self.path = path terom@8: self.basename = basename terom@8: self.url_tail = url_tail terom@8: terom@8: # sub-init terom@8: self._init() terom@8: terom@8: def _init (self) : terom@8: """ terom@8: Do initial data loading, etc terom@8: """ terom@8: terom@8: pass terom@8: terom@8: def get_title (self) : terom@8: """ terom@8: Return the page's title terom@8: terom@8: Defaults to the Titlecase'd file basename terom@8: """ terom@8: terom@8: return self.basename.title() terom@8: terom@8: def get_content (self) : terom@8: """ terom@8: Return the page content as a string terom@8: """ terom@8: terom@8: abstract terom@8: terom@8: class HTMLPage (Page) : terom@8: """ terom@8: A simple .html page that's just passed through directly terom@8: """ terom@8: terom@8: def get_content (self) : terom@8: """ terom@8: Opens the .html file, reads and returns contents terom@8: """ terom@8: terom@8: return open(self.path, 'rb').read() terom@8: terom@8: class TemplatePage (Page) : terom@8: """ terom@8: A template that's rendered using our template library terom@8: """ terom@8: terom@8: def get_content (self) : terom@8: """ terom@8: Loads the .tmpl file, and renders it terom@8: """ terom@8: terom@8: return template.render_file(self.path) terom@7: terom@7: # list of page handlers, by type terom@8: TYPE_HANDLERS = [ terom@8: ('html', HTMLPage ), terom@8: (template.TEMPLATE_EXT, TemplatePage ), terom@7: ] terom@7: terom@8: def _lookup_handler (url, path, filename, basename, extension, tail) : terom@5: """ terom@8: We found the file that we looked for, now get its handler terom@5: """ terom@5: terom@8: # find appropriate handler terom@8: for handler_ext, handler in TYPE_HANDLERS : terom@8: # match against file extension? terom@8: if handler_ext == extension : terom@8: # found handler, return instance terom@8: return handler(url, path, basename, tail) terom@5: terom@8: # no handler found terom@8: raise PageError("No handler found for page %r of type %r" % (url, extension)) terom@8: terom@8: def lookup (name) : terom@8: """ terom@8: Look up and return a Page object for the given page, or raise an error terom@8: """ terom@8: terom@8: # inital path terom@8: path = PAGE_DIR terom@8: url_segments = [] terom@8: terom@8: # name segments terom@8: segments = name.split('/') terom@8: terom@8: # iterate through the parts of the page segments terom@8: while segments : terom@8: # pop segment terom@8: segment = segments.pop(0) terom@8: terom@8: # add to page url terom@8: url_segments.append(segment) terom@8: terom@8: # translate empty -> index terom@8: if not segment : terom@8: segment = 'index' terom@8: terom@8: # look for it in the dir terom@8: for filename in os.listdir(path) : terom@8: # build full file path terom@8: file_path = os.path.join(path, filename) terom@8: terom@8: # stat, recurse into subdirectory? terom@8: if os.path.isdir(file_path) and filename == segment : terom@8: # use new dir terom@8: path = file_path terom@8: terom@8: # break for-loop to look at next segment terom@8: break terom@8: terom@8: # split into basename + extension terom@8: basename, extension = os.path.splitext(filename) terom@8: terom@8: # ...remove that dot terom@8: extension = extension.lstrip('.') terom@8: terom@8: # match against requested page name? terom@8: if basename == segment : terom@8: # found the file we wanted terom@8: return _lookup_handler('/'.join(url_segments), file_path, filename, basename, extension, '/'.join(segments)) terom@8: terom@8: else : terom@8: # inspect next file in dir terom@8: continue terom@8: terom@8: # did not find the filename we were looking for in os.listdir terom@8: raise PageError("Page not found: %s" % name, status='404 Not Found') terom@8: