from django.conf import settings
import codecs
import datetime
import logging; log = logging.getLogger('qmsk_www_pages.pages')
import os, os.path
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
class Tree (object):
INDEX = 'index'
@classmethod
def lookup (cls, site, parts):
path = site.root
for part in parts:
if part.startswith('.'):
# evil
return None
if not part:
continue
path = os.path.join(path, part)
if not os.path.exists(path):
return None
if not os.path.isdir(path):
return None
return cls(path, parts, site)
def __init__ (self, path, parts, site):
self.path = path
self.parts = parts
self.site = site
def url (self, tree=None, page=None):
path = '/'.join(self.parts)
if path:
path += '/'
if tree:
path = tree + '/'
if page:
path += page
return path
def breadcrumb (self):
path = []
yield '', self.site.name
for part in self.parts:
path.append(part)
yield '/'.join(path) + '/', part
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 list (self):
"""
Lists all Trees and Pages for this Tree
"""
for path, file_name, file_type in self.scan():
# trees
if os.path.isdir(path):
yield self.url(tree=file_name), file_name, None
if file_name == self.INDEX:
continue
# pages
if not file_type:
continue
if file_type not in TYPES:
continue
yield self.url(page=file_name), file_name, file_type
def page (self, name):
"""
Scans through tree looking for a matching page.
Returns Page.
"""
if not name:
name = self.INDEX
for path, file_name, file_type in self.scan():
# match on name
if file_name != name:
continue
# match on type
if not file_type:
continue
page_type = TYPES.get(file_type)
if not page_type:
continue
# out
return page_type(
path = path,
name = name,
tree = self,
)
class Page (object):
ENCODING = 'utf-8'
@classmethod
def lookup (cls, site, page):
"""
Lookup a Page from disk.
Returns None if there is no such page.
"""
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)
if not tree:
return None
# scan page
page = tree.page(page_name)
if not page:
return None
return page
def __init__ (self, path, name, tree, encoding=ENCODING):
self.path = path
self.name = name
self.tree = tree
self.encoding = encoding
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 path, name in self.tree.breadcrumb():
yield path, name
if self.name != self.tree.INDEX:
yield self.url(), self.name
def modified (self):
return datetime.datetime.utcfromtimestamp(self.stat().st_mtime)
def render (self, request):
raise NotImplementedError()
class HTML_Page (Page):
def render (self, request):
return self.open().read()
SITE = Site.lookup()
TYPES = {
'html': HTML_Page,
}
def page (page):
return Page.lookup(SITE, page)