|
1 |
|
2 from __future__ import with_statement |
|
3 |
|
4 # XXX: for _HTMLPage |
|
5 import page |
|
6 import templates |
|
7 |
|
8 from pages import error404 |
|
9 |
|
10 import os.path |
|
11 import imp |
|
12 |
|
13 # the page dir |
|
14 PAGE_DIR_PATH = "pages/" |
|
15 |
|
16 def build_page_path (*bits) : |
|
17 # XXX: fix directory traversal... |
|
18 |
|
19 return os.path.join(PAGE_DIR_PATH, *bits) |
|
20 |
|
21 class PageLoader (object) : |
|
22 """ |
|
23 Load Page objects from files under pages/ |
|
24 """ |
|
25 |
|
26 # file extension, e.g. '.html' or '.py' |
|
27 suffix = None |
|
28 |
|
29 def __init__ (self, suffix) : |
|
30 self.suffix = suffix |
|
31 |
|
32 def _build_path (self, page_path) : |
|
33 """ |
|
34 Builds a path from base_path + page_path + suffix. Returns None if the path does not exist |
|
35 """ |
|
36 |
|
37 path = build_page_path(page_path) + self.suffix |
|
38 |
|
39 if os.path.exists(path) : |
|
40 return path |
|
41 |
|
42 else : |
|
43 return None |
|
44 |
|
45 def load (self, page_path) : |
|
46 """ |
|
47 Attempts to load the page at the given path, returns the class on success, None on failure |
|
48 """ |
|
49 |
|
50 abstract |
|
51 |
|
52 class _HTMLPage (page.Page) : |
|
53 # the path to the .html file |
|
54 file_path = None |
|
55 |
|
56 # parent page |
|
57 # parent = None |
|
58 |
|
59 def __init__ (self, *args) : |
|
60 super(_HTMLPage, self).__init__(*args) |
|
61 |
|
62 # open the .html and read in the contents |
|
63 with open(self.file_path, "r") as fh : |
|
64 self.file_data = fh.read() |
|
65 |
|
66 def render_template (self) : |
|
67 tpl = self._build_template(templates.layout) |
|
68 |
|
69 tpl.page_content = self.file_data |
|
70 |
|
71 return tpl |
|
72 |
|
73 class HTMLLoader (PageLoader) : |
|
74 """ |
|
75 Static .html files that are inserted into the layout template as-is |
|
76 |
|
77 Sub-pages are not supported... |
|
78 """ |
|
79 |
|
80 def __init__ (self) : |
|
81 super(HTMLLoader, self).__init__(".html") |
|
82 |
|
83 def get_title (self, page_path) : |
|
84 head, tail = os.path.split(page_path) |
|
85 |
|
86 return tail.title() if tail else "Index" |
|
87 |
|
88 def load (self, _page_path) : |
|
89 _file_path = self._build_path(_page_path) |
|
90 |
|
91 # ignore if it doesn't exist |
|
92 if not _file_path : |
|
93 return |
|
94 |
|
95 # get page title |
|
96 _title = self.get_title(_page_path) |
|
97 |
|
98 # create a new class and return it |
|
99 class _html_page (_HTMLPage) : |
|
100 file_path = _file_path |
|
101 title = _title |
|
102 name = _title |
|
103 path = _page_path |
|
104 |
|
105 # return it |
|
106 return _html_page |
|
107 |
|
108 class PythonLoader (PageLoader) : |
|
109 """ |
|
110 Dynamic .py files that define a Page class |
|
111 """ |
|
112 |
|
113 def __init__ (self) : |
|
114 super(PythonLoader, self).__init__(".py") |
|
115 |
|
116 def load (self, page_path) : |
|
117 path = self._build_path(page_path) |
|
118 |
|
119 # ignore if not exists |
|
120 if not path : |
|
121 return |
|
122 |
|
123 # load the module dynamically |
|
124 module = imp.load_source("__dyn_%d" % id(path), path) |
|
125 |
|
126 # return the Page object |
|
127 return module.Page |
|
128 |
|
129 # our defined loaders |
|
130 loaders = [ |
|
131 HTMLLoader(), |
|
132 PythonLoader(), |
|
133 ] |
|
134 |
|
135 def load_page (req) : |
|
136 """ |
|
137 Returns an instance of a Page object corresponding to the given req |
|
138 """ |
|
139 |
|
140 # page path is given in req |
|
141 page_path = req.page_path |
|
142 |
|
143 # if it's a dir, then add 'index' |
|
144 if os.path.isdir(build_page_path(page_path)) : |
|
145 page_path = os.path.join(page_path, "index") |
|
146 |
|
147 # try each loader in turn |
|
148 for loader in loaders : |
|
149 page = loader.load(req.page_path) |
|
150 |
|
151 # found? |
|
152 if page : |
|
153 break |
|
154 |
|
155 # 404 error... |
|
156 if not page : |
|
157 page = error404.Error404 |
|
158 |
|
159 return page(req, req.page_path) |
|
160 |