lib/page.py
changeset 44 d09cc8b3709c
parent 28 b68145b5ce24
parent 43 fc11c4e86a82
child 45 e94ab812c0c8
equal deleted inserted replaced
28:b68145b5ce24 44:d09cc8b3709c
     1 
       
     2 """
       
     3     Handling page requests
       
     4 """
       
     5 
       
     6 # for filesystem ops
       
     7 import os, os.path
       
     8 import time
       
     9 
       
    10 # for ResponseError
       
    11 import http
       
    12 
       
    13 # for TemplatePage
       
    14 import template
       
    15 
       
    16 from page_tree import page_tree
       
    17 import config
       
    18 
       
    19 # path to directory containing the page heirarcy
       
    20 PAGE_DIR = "pages"
       
    21 
       
    22 class PageError (http.ResponseError) :
       
    23     """
       
    24         Error looking up/handling a page
       
    25     """
       
    26 
       
    27     pass
       
    28 
       
    29 # XXX: should inherit from PageInfo
       
    30 class Page (object) :
       
    31     """
       
    32         This object represents the information about our attempt to render some specific page
       
    33     """
       
    34 
       
    35     def __init__ (self, url, path, basename, url_tail, charset='utf8') :
       
    36         """
       
    37             Initialize the page at the given location
       
    38 
       
    39             @param url the URL leading to this page
       
    40             @param path the filesystem path to this page's file
       
    41             @param basename the filesystem name of this page's file, without the file extension
       
    42             @param url_trail trailing URL for this page
       
    43             @param charset file charset
       
    44         """
       
    45         
       
    46         # store
       
    47         self.url = url
       
    48         self.path = path
       
    49         self.basename = basename
       
    50         self.url_tail = url_tail
       
    51         self.charset = charset
       
    52 
       
    53         # unbound
       
    54         self.request = None
       
    55 
       
    56         # sub-init
       
    57         self._init()
       
    58 
       
    59     def _init (self) :
       
    60         """
       
    61             Do initial data loading, etc
       
    62         """
       
    63         
       
    64         pass
       
    65 
       
    66     def bind_request (self, request) :
       
    67         """
       
    68             Bind this page-render to the given request
       
    69         """
       
    70 
       
    71         self.request = request
       
    72 
       
    73     @property
       
    74     def title (self) :
       
    75         """
       
    76             Return the page's title
       
    77 
       
    78             Defaults to the retreiving the page title from page_list, or basename in Titlecase.
       
    79         """
       
    80         
       
    81         # lookup in page_list
       
    82         page_info = page_tree.get_page(self.url)
       
    83         
       
    84         # fallback to titlecase
       
    85         if page_info :
       
    86             title = page_info.title
       
    87 
       
    88         else :
       
    89             title = self.basename.title()
       
    90 
       
    91         return title
       
    92     
       
    93     @property
       
    94     def content (self) :
       
    95         """
       
    96             Return the page content as a string
       
    97         """
       
    98 
       
    99         abstract
       
   100     
       
   101     @property
       
   102     def modified (self) :
       
   103         """
       
   104             Returns the page modification timestamp
       
   105         """
       
   106         
       
   107         # stat
       
   108         timestamp = os.stat(self.path).st_mtime
       
   109 
       
   110         return time.strftime(config.DATETIME_FMT, time.gmtime(timestamp))
       
   111 
       
   112 class HTMLPage (Page) :
       
   113     """
       
   114         A simple .html page that's just passed through directly
       
   115     """
       
   116 
       
   117     @property
       
   118     def content (self) :
       
   119         """
       
   120             Opens the .html file, reads and returns contents
       
   121         """
       
   122 
       
   123         return open(self.path, 'rb').read().decode(self.charset)
       
   124 
       
   125 class TemplatePage (Page) :
       
   126     """
       
   127         A template that's rendered using our template library
       
   128     """
       
   129     
       
   130     @property
       
   131     def content (self) :
       
   132         """
       
   133             Loads the .tmpl file, and renders it
       
   134         """
       
   135 
       
   136         return template.render_file(self.path,
       
   137             request     = self.request,
       
   138             page_tree   = page_tree
       
   139         )
       
   140 
       
   141 # list of page handlers, by type
       
   142 TYPE_HANDLERS = [
       
   143     ('html',                    HTMLPage        ),
       
   144     (template.TEMPLATE_EXT,     TemplatePage    ),
       
   145 ]
       
   146 
       
   147 def _lookup_handler (url, path, filename, basename, extension, tail) :
       
   148     """
       
   149         We found the file that we looked for, now get its handler
       
   150     """
       
   151 
       
   152     # find appropriate handler
       
   153     for handler_ext, handler in TYPE_HANDLERS :
       
   154         # match against file extension?
       
   155         if handler_ext == extension :
       
   156             # found handler, return instance
       
   157             return handler(url, path, basename, tail)
       
   158 
       
   159     # no handler found
       
   160     raise PageError("No handler found for page %r of type %r" % (url, extension))
       
   161 
       
   162 def lookup (name) :
       
   163     """
       
   164         Look up and return a Page object for the given page, or raise an error
       
   165     """
       
   166 
       
   167     # inital path
       
   168     path = PAGE_DIR
       
   169     url_segments = []
       
   170 
       
   171     # name segments
       
   172     segments = name.split('/')
       
   173 
       
   174     # iterate through the parts of the page segments
       
   175     while True :
       
   176         segment = None
       
   177 
       
   178         # pop segment
       
   179         if segments :
       
   180             segment = segments.pop(0)
       
   181 
       
   182             url_segments.append(segment)
       
   183 
       
   184         # translate empty -> index
       
   185         if not segment :
       
   186             segment = 'index'
       
   187 
       
   188         # look for it in the dir
       
   189         for filename in os.listdir(path) :
       
   190             # build full file path
       
   191             file_path = os.path.join(path, filename)
       
   192 
       
   193             # stat, recurse into subdirectory?
       
   194             if os.path.isdir(file_path) and filename == segment :
       
   195                 # use new dir
       
   196                 path = file_path
       
   197 
       
   198                 # break for-loop to look at next segment
       
   199                 break
       
   200  
       
   201             # split into basename + extension
       
   202             basename, extension = os.path.splitext(filename)
       
   203 
       
   204             # ...remove that dot
       
   205             extension = extension.lstrip('.')
       
   206             
       
   207             # match against requested page name?
       
   208             if basename == segment :
       
   209                 # found the file we wanted
       
   210                 return _lookup_handler('/'.join(url_segments), file_path, filename, basename, extension, '/'.join(segments))
       
   211             
       
   212             else :
       
   213                 # inspect next file in dir
       
   214                 continue
       
   215 
       
   216         else :
       
   217             # did not find any dir or file, break out of while loop
       
   218             break
       
   219 
       
   220     # did not find the filename we were looking for in os.listdir
       
   221     raise PageError("Page not found: %s" % name, status='404 Not Found')
       
   222