--- a/qmsk_www_pages/pages.py Sat Oct 04 13:32:35 2014 +0300
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,379 +0,0 @@
-from django.conf import settings
-
-import codecs
-import datetime
-import logging; log = logging.getLogger('qmsk_www_pages.pages')
-import os, os.path
-
-import markdown
-import mako.template
-
-class NotFound (Exception):
- pass
-
-class RenderError (Exception):
- pass
-
-class Site (object):
- @classmethod
- def lookup (cls):
- return cls(
- root = settings.QMSK_WWW_PAGES_DIR,
- name = settings.QMSK_WWW_PAGES_SITE,
- )
-
- def __init__ (self, root, name):
- self.root = root
- self.name = name
-
- def tree (self):
- return Tree(self.root, None, (), self,
- title = self.name,
- )
-
-class Tree (object):
- INDEX = 'index'
-
- @classmethod
- def lookup (cls, site, parts):
- """
- Returns Tree
-
- Raises NotFound
- """
-
- parents = ( )
- tree = site.tree()
-
- for name in parts:
- if name.startswith('.'):
- # evil
- raise NotFound()
-
- if not name:
- continue
-
- path = os.path.join(tree.path, name)
-
- if not os.path.exists(path):
- raise NotFound()
-
- if not os.path.isdir(path):
- raise NotFound()
-
- # title
- title = tree.item_title(name)
-
- parents += (tree, )
- tree = cls(path, name, parents, site,
- title = title,
- )
-
- return tree
-
- def __init__ (self, path, name, parents, site,
- title = None,
- ):
- """
- path: filesystem path
- name: subtree name, or None for root
- parents: (Tree)
- site: Site
- """
-
- self.path = path
- self.name = name
- self.parents = parents
- self.site = site
-
- self.title = title or name
-
- def hierarchy (self):
- """
- Yield Tree.
- """
-
- for tree in self.parents:
- yield tree
-
- yield self
-
- def url (self, tree=None, page=None):
- path = '/'.join(tree.name for tree in self.hierarchy() if tree.name is not None)
-
- if path:
- path += '/'
-
- if tree:
- path = tree + '/'
-
- if page:
- path += page
-
- return path
-
- def scan (self):
- """
- Scan for files in tree.
- """
-
- for filename in os.listdir(self.path):
- if filename.startswith('.'):
- continue
-
- if '.' in filename:
- file_name, file_type = filename.rsplit('.', 1)
- else:
- file_name = filename
- file_type = None
-
- if not file_name:
- continue
-
- path = os.path.join(self.path, filename)
-
- yield path, file_name, file_type
-
- def item_title (self, name):
- """
- Lookup item title if exists.
- """
-
- title_path = os.path.join(self.path, name + '.title')
-
- log.info("%s: %s title_path=%s", self, name, title_path)
-
- if os.path.exists(title_path):
- return open(title_path).read().strip()
- else:
- return None
-
- def list (self):
- """
- Lists all Trees and Pages for this Tree.
-
- Yields (name, url, page_type or None, title)
- """
-
- for path, name, file_type in self.scan():
- title = self.item_title(name) or name
-
- # trees
- if os.path.isdir(path):
- yield name, self.url(tree=name), None, title
-
- if name == self.INDEX:
- continue
-
- # pages
- if not file_type:
- continue
-
- if file_type not in TYPES:
- continue
-
- yield name, self.url(page=name), file_type, title
-
- def list_sorted (self):
- return sorted(list(self.list()))
-
- def page (self, name):
- """
- Scans through tree looking for a matching page.
-
- Returns Page or None.
- """
-
- if not name:
- name = self.INDEX
- title_default = self.title
- else:
- title_default = None
-
- parents = self.parents + (self, )
-
- for path, file_name, file_type in self.scan():
- # match on name
- if file_name == name:
- pass
- elif file_type and (file_name + '.' + file_type == name):
- pass
- else:
- continue
-
- # redirects?
- if os.path.islink(path):
- target = os.readlink(path)
-
- # XXX: this should be some kind of common code
- if '.' in target:
- target, target_type = target.rsplit('.', 1)
-
- log.info("%s: %s -> %s", self, name, target)
-
- return RedirectPage(path, name, self, parents,
- target = target,
- )
-
- # match on type
- if not file_type:
- continue
-
- page_type = TYPES.get(file_type)
-
- if not page_type:
- continue
-
- # out
- title = self.item_title(file_name) or title_default
-
- return page_type(path, name, self, parents,
- title = title,
- )
-
-class Page (object):
- ENCODING = 'utf-8'
-
- @classmethod
- def lookup (cls, site, page):
- """
- Returns Page.
-
- Raises NotFound
- """
-
- log.info("page=%r", page)
-
- if page:
- parts = page.split('/')
- else:
- parts = [ ]
-
- if parts:
- page_name = parts.pop(-1)
- tree_parts = parts
- else:
- page_name = ''
- tree_parts = []
-
- # scan dir
- tree = Tree.lookup(site, tree_parts)
-
- # scan page
- page = tree.page(page_name)
-
- if not page:
- raise NotFound()
-
- return page
-
- def __init__ (self, path, name, tree, parents=(), encoding=ENCODING, title=None):
- self.path = path
- self.name = name
- self.tree = tree
- self.parents = parents
-
- self.encoding = encoding
- self.title = title or name
-
- def hierarchy (self):
- """
- Yield (Tree, name) pairs
- """
-
- parent = None
-
- for tree in self.parents:
- if parent:
- yield parent, tree.name
-
- parent = tree
-
- yield parent, self.name
-
- def url (self):
- return self.tree.url(page=self.name)
-
- def open (self):
- return codecs.open(self.path, encoding=self.encoding)
-
- def stat (self):
- return os.stat(self.path)
-
- def breadcrumb (self):
- for tree in self.tree.hierarchy():
- yield tree.url(), tree.title
-
- if self.name != self.tree.INDEX:
- yield self.url(), self.title
-
- def modified (self):
- return datetime.datetime.utcfromtimestamp(self.stat().st_mtime)
-
- def redirect_page (self, request):
- return None
-
- def render_html (self, request):
- raise NotImplementedError()
-
-# TODO: tree redirects
-class RedirectPage (Page):
- def __init__ (self, path, name, tree, parents,
- target,
- **opts
- ) :
- super(RedirectPage, self).__init__(path, name, tree, parents, **opts)
-
- self.target = target
-
- def redirect_page (self, request):
- return os.path.normpath(self.tree.url() + '/' + self.target)
-
-class HTML_Page (Page):
- def render_html (self, request):
- return self.open().read()
-
-class MarkdownPage (Page):
- FORMAT = 'html5'
-
- def __init__ (self, path, name, tree, parents,
- format=FORMAT,
- **opts
- ) :
- super(MarkdownPage, self).__init__(path, name, tree, parents, **opts)
-
- self.format = format
-
- def render_html (self, request):
- return markdown.markdown(self.open().read(),
- output_format = self.format,
- )
-
-class TemplatePage (Page):
- def render_html (self, request):
- """
- Raises RenderError if !DEBUG, arbitrary error with stack trace otherwise.
- """
-
- try:
- return mako.template.Template(filename=self.path).render(
- request = request,
- )
- except Exception as error:
- if settings.DEBUG:
- raise
- else:
- raise RenderError(error)
-
-SITE = Site.lookup()
-
-TYPES = {
- 'html': HTML_Page,
- 'md': MarkdownPage,
- 'markdown': MarkdownPage,
- 'tmpl': TemplatePage,
-}
-
-def page (page):
- return Page.lookup(SITE, page)
-