1 |
1 |
2 """ |
2 """ |
3 Handling page requests |
3 Handling page requests |
4 """ |
4 """ |
5 |
5 |
6 def handle_html (env) : |
6 # for filesystem ops |
7 return "A HTML page" |
7 import os, os.path |
8 |
8 |
|
9 # for ResponseError |
|
10 import http |
|
11 |
|
12 # for TemplatePage |
|
13 import template |
|
14 |
|
15 # path to directory containing the page heirarcy |
|
16 PAGE_DIR = "pages" |
|
17 |
|
18 class PageError (http.ResponseError) : |
|
19 """ |
|
20 Error looking up/handling a page |
|
21 """ |
|
22 |
|
23 pass |
|
24 |
|
25 class Page (object) : |
|
26 """ |
|
27 This object represents the information about our attempt to render some specific page |
|
28 """ |
|
29 |
|
30 def __init__ (self, url, path, basename, url_tail) : |
|
31 """ |
|
32 Initialize the page at the given location |
|
33 |
|
34 @param url the URL leading to this page |
|
35 @param path the filesystem path to this page's file |
|
36 @param basename the filesystem name of this page's file, without the file extension |
|
37 @param url_trail trailing URL for this page |
|
38 """ |
|
39 |
|
40 # store |
|
41 self.url = url |
|
42 self.path = path |
|
43 self.basename = basename |
|
44 self.url_tail = url_tail |
|
45 |
|
46 # sub-init |
|
47 self._init() |
|
48 |
|
49 def _init (self) : |
|
50 """ |
|
51 Do initial data loading, etc |
|
52 """ |
|
53 |
|
54 pass |
|
55 |
|
56 def get_title (self) : |
|
57 """ |
|
58 Return the page's title |
|
59 |
|
60 Defaults to the Titlecase'd file basename |
|
61 """ |
|
62 |
|
63 return self.basename.title() |
|
64 |
|
65 def get_content (self) : |
|
66 """ |
|
67 Return the page content as a string |
|
68 """ |
|
69 |
|
70 abstract |
|
71 |
|
72 class HTMLPage (Page) : |
|
73 """ |
|
74 A simple .html page that's just passed through directly |
|
75 """ |
|
76 |
|
77 def get_content (self) : |
|
78 """ |
|
79 Opens the .html file, reads and returns contents |
|
80 """ |
|
81 |
|
82 return open(self.path, 'rb').read() |
|
83 |
|
84 class TemplatePage (Page) : |
|
85 """ |
|
86 A template that's rendered using our template library |
|
87 """ |
|
88 |
|
89 def get_content (self) : |
|
90 """ |
|
91 Loads the .tmpl file, and renders it |
|
92 """ |
|
93 |
|
94 return template.render_file(self.path) |
9 |
95 |
10 # list of page handlers, by type |
96 # list of page handlers, by type |
11 type_handlers = [ |
97 TYPE_HANDLERS = [ |
12 ('.html', handle_html), |
98 ('html', HTMLPage ), |
|
99 (template.TEMPLATE_EXT, TemplatePage ), |
13 ] |
100 ] |
14 |
101 |
15 def lookup_handler (path) : |
102 def _lookup_handler (url, path, filename, basename, extension, tail) : |
16 """ |
103 """ |
17 Look up and return a handler for the given page, or raise an error |
104 We found the file that we looked for, now get its handler |
18 """ |
105 """ |
19 |
106 |
20 return handle_html |
107 # find appropriate handler |
|
108 for handler_ext, handler in TYPE_HANDLERS : |
|
109 # match against file extension? |
|
110 if handler_ext == extension : |
|
111 # found handler, return instance |
|
112 return handler(url, path, basename, tail) |
21 |
113 |
|
114 # no handler found |
|
115 raise PageError("No handler found for page %r of type %r" % (url, extension)) |
|
116 |
|
117 def lookup (name) : |
|
118 """ |
|
119 Look up and return a Page object for the given page, or raise an error |
|
120 """ |
|
121 |
|
122 # inital path |
|
123 path = PAGE_DIR |
|
124 url_segments = [] |
|
125 |
|
126 # name segments |
|
127 segments = name.split('/') |
|
128 |
|
129 # iterate through the parts of the page segments |
|
130 while segments : |
|
131 # pop segment |
|
132 segment = segments.pop(0) |
|
133 |
|
134 # add to page url |
|
135 url_segments.append(segment) |
|
136 |
|
137 # translate empty -> index |
|
138 if not segment : |
|
139 segment = 'index' |
|
140 |
|
141 # look for it in the dir |
|
142 for filename in os.listdir(path) : |
|
143 # build full file path |
|
144 file_path = os.path.join(path, filename) |
|
145 |
|
146 # stat, recurse into subdirectory? |
|
147 if os.path.isdir(file_path) and filename == segment : |
|
148 # use new dir |
|
149 path = file_path |
|
150 |
|
151 # break for-loop to look at next segment |
|
152 break |
|
153 |
|
154 # split into basename + extension |
|
155 basename, extension = os.path.splitext(filename) |
|
156 |
|
157 # ...remove that dot |
|
158 extension = extension.lstrip('.') |
|
159 |
|
160 # match against requested page name? |
|
161 if basename == segment : |
|
162 # found the file we wanted |
|
163 return _lookup_handler('/'.join(url_segments), file_path, filename, basename, extension, '/'.join(segments)) |
|
164 |
|
165 else : |
|
166 # inspect next file in dir |
|
167 continue |
|
168 |
|
169 # did not find the filename we were looking for in os.listdir |
|
170 raise PageError("Page not found: %s" % name, status='404 Not Found') |
|
171 |