1 """ |
|
2 Our URL action handlers |
|
3 """ |
|
4 |
|
5 import datetime, calendar, pytz |
|
6 |
|
7 from qmsk.web import http, template |
|
8 |
|
9 import urls, channels, helpers |
|
10 import preferences as prefs |
|
11 from preferences import preferences |
|
12 import config, log_search |
|
13 |
|
14 # load templates from here |
|
15 templates = template.TemplateLoader("templates", |
|
16 _helper_class = helpers.Helpers, |
|
17 urls = urls, |
|
18 channel_list = config.LOG_CHANNELS, |
|
19 config = config, |
|
20 ) |
|
21 |
|
22 # return a http.Response for the given text in the given format |
|
23 def _render_type (request, channel, lines, type, full_timestamps=False) : |
|
24 """ |
|
25 Render the given LogLines as a http.Response in the given format, which is one of: |
|
26 html - XXX: not supported |
|
27 txt - Plaintext |
|
28 png - PNG image |
|
29 rss - RSS feed |
|
30 """ |
|
31 |
|
32 # load related preferences |
|
33 formatter = request.prefs['formatter'] |
|
34 |
|
35 kwargs = dict( |
|
36 full_timestamps = full_timestamps |
|
37 ) |
|
38 |
|
39 # we can render in various modes... |
|
40 if type in ('html', None) : |
|
41 xxx |
|
42 |
|
43 elif type == 'txt' : |
|
44 # plaintext |
|
45 lines = formatter.format_txt(lines, **kwargs) |
|
46 |
|
47 # build data |
|
48 data = '\n'.join(data for line, data in lines) |
|
49 |
|
50 return http.Response(data, 'text/plain') |
|
51 |
|
52 elif type == 'png' : |
|
53 # PNG image |
|
54 png_data = formatter.format_png(lines, **kwargs) |
|
55 |
|
56 return http.Response(png_data, 'image/png', charset=None) |
|
57 |
|
58 elif type == 'rss' : |
|
59 # RSS feed |
|
60 rss_data = formatter.format_rss(lines, **kwargs) |
|
61 |
|
62 # XXX: fix to render as unicode? |
|
63 return http.Response(rss_data, 'application/rss+xml', charset=None) |
|
64 |
|
65 else : |
|
66 raise http.ResponseError("Unrecognized type: %r" % (type, )) |
|
67 |
|
68 def _render_date (request, channel, date, lines, type, count, page, max) : |
|
69 """ |
|
70 Render the given LogLines as a http.Response for channel_date |
|
71 """ |
|
72 |
|
73 # type? |
|
74 if type : |
|
75 # special type |
|
76 return _render_type(request, channel, lines, type) |
|
77 |
|
78 else : |
|
79 # format HTML |
|
80 lines = request.prefs['formatter'].format_html(lines) |
|
81 |
|
82 # render |
|
83 return templates.render_to_response("channel_date", |
|
84 req = request, |
|
85 prefs = request.prefs, |
|
86 channel = channel, |
|
87 date = date, |
|
88 count = count, |
|
89 page = page, |
|
90 max = max, |
|
91 lines = lines, |
|
92 |
|
93 # for prev/next date |
|
94 date_next = channel.source.get_next_date(date), |
|
95 date_prev = channel.source.get_prev_date(date), |
|
96 ) |
|
97 |
|
98 @preferences.handler() |
|
99 def index (request) : |
|
100 """ |
|
101 The topmost index page, display a list of available channels, perhaps some general stats |
|
102 """ |
|
103 |
|
104 return templates.render_to_response("index", |
|
105 req = request, |
|
106 prefs = request.prefs, |
|
107 ) |
|
108 |
|
109 # XXX: fix this namespace crap |
|
110 @preferences.handler() |
|
111 def preferences_ (request) : |
|
112 """ |
|
113 Preferences editor |
|
114 """ |
|
115 |
|
116 # POST? |
|
117 if request.is_post() : |
|
118 # update any modified preferences |
|
119 for pref in preferences.pref_list : |
|
120 # get the POST'd value, default = None |
|
121 post_value = request.get_post(pref.name, None) |
|
122 |
|
123 # skip non-specified values |
|
124 # XXX: this is to not clobber timezone_offset to None |
|
125 if post_value is None : |
|
126 continue |
|
127 |
|
128 # parse the POST'd value, None -> default |
|
129 new_value = request.prefs.parse(pref, post_value) |
|
130 |
|
131 # update if given and changed |
|
132 if new_value != request.prefs[pref] : |
|
133 request.prefs.set(pref.name, new_value) |
|
134 |
|
135 # render |
|
136 return templates.render_to_response("preferences", |
|
137 req = request, |
|
138 prefs = request.prefs, |
|
139 preferences = prefs, |
|
140 ) |
|
141 |
|
142 def channel_select (request, channel) : |
|
143 """ |
|
144 Redirect to the appropriate channel_view |
|
145 """ |
|
146 |
|
147 return http.Redirect(urls.channel.build(request, channel=channel)) |
|
148 |
|
149 @preferences.handler(prefs.formatter) |
|
150 def channel_last (request, channel, count, formatter, type=None) : |
|
151 """ |
|
152 The main channel view page, displaying the most recent lines |
|
153 """ |
|
154 |
|
155 # get latest events |
|
156 lines = channel.source.get_latest(count) |
|
157 |
|
158 # type? |
|
159 if type : |
|
160 # other format |
|
161 return _render_type(request, channel, lines, type) |
|
162 |
|
163 else : |
|
164 # format HTML |
|
165 lines = formatter.format_html(lines) |
|
166 |
|
167 # render page |
|
168 return templates.render_to_response("channel_last", |
|
169 req = request, |
|
170 prefs = request.prefs, |
|
171 channel = channel, |
|
172 count = count, |
|
173 lines = lines, |
|
174 ) |
|
175 |
|
176 @preferences.handler(prefs.formatter, prefs.timezone, prefs.count) |
|
177 def channel_link (request, channel, timestamp, formatter, timezone, count, type=None) : |
|
178 """ |
|
179 Display channel_date for specific UTC timestamp |
|
180 """ |
|
181 |
|
182 # convert timestamp to user's timezone |
|
183 timestamp = timestamp.astimezone(timezone) |
|
184 |
|
185 # get correct day's correct page of lines |
|
186 page, max, lines = channel.source.get_date_paged(timestamp, count) |
|
187 |
|
188 # render channel_date |
|
189 return _render_date (request, channel, timestamp, lines, type, count, page, max) |
|
190 |
|
191 @preferences.handler(prefs.timezone) |
|
192 def channel_calendar (request, channel, year, month, timezone) : |
|
193 """ |
|
194 Display a list of avilable logs for some month |
|
195 """ |
|
196 |
|
197 # current date as default |
|
198 now = timezone.localize(datetime.datetime.now()) |
|
199 |
|
200 # target year/month |
|
201 target = timezone.localize(datetime.datetime( |
|
202 year = year if year else now.year, |
|
203 month = month if month else now.month, |
|
204 day = 1 |
|
205 )) |
|
206 |
|
207 # display calendar |
|
208 return templates.render_to_response("channel_calendar", |
|
209 req = request, |
|
210 prefs = request.prefs, |
|
211 channel = channel, |
|
212 month = target, |
|
213 ) |
|
214 |
|
215 @preferences.handler(prefs.count, prefs.timezone) |
|
216 def channel_date (request, channel, date, count, timezone, page=1, type=None) : |
|
217 """ |
|
218 Display all log data for the given date |
|
219 """ |
|
220 |
|
221 # convert date to user's timezone |
|
222 date = timezone.localize(date) |
|
223 |
|
224 # print |
|
225 # print "channel_date: date=%s" % date |
|
226 |
|
227 # get that day's events, either paged or not |
|
228 if page : |
|
229 page, max, lines = channel.source.get_date_paged(date, count, page) |
|
230 |
|
231 else : |
|
232 lines = channel.source.get_date(date) |
|
233 max = None |
|
234 |
|
235 # render channel_date |
|
236 return _render_date (request, channel, date, lines, type, count, page, max) |
|
237 |
|
238 @preferences.handler(prefs.formatter, prefs.count) |
|
239 def channel_search (request, channel, formatter, count, q=None, page=1, max=1, type=None, t=None) : |
|
240 """ |
|
241 Display the search form for the channel for GET, or do the search for POST. |
|
242 """ |
|
243 |
|
244 # calculate skip offset from page/count |
|
245 skip = (page - 1) * count |
|
246 |
|
247 # got a search query? |
|
248 if q : |
|
249 # attribute targets |
|
250 targets = dict(('search_%s' % target, True) for target in t if target in ('msg', 'nick')) if t else {} |
|
251 |
|
252 try : |
|
253 # do search |
|
254 lines = log_search.get_index().search_simple(channel, q, count, skip, **targets) |
|
255 |
|
256 # update max? |
|
257 if max and page > max : |
|
258 max = page |
|
259 |
|
260 except log_search.NoResultsFound : |
|
261 # no results |
|
262 lines = None |
|
263 |
|
264 else : |
|
265 # just display the search form |
|
266 lines = None |
|
267 |
|
268 # type? |
|
269 if type and lines : |
|
270 # special type |
|
271 return _render_type(request, channel, lines, type, full_timestamps=True) |
|
272 |
|
273 else : |
|
274 # format lines to HTML if any |
|
275 if lines : |
|
276 # format |
|
277 lines = formatter.format_html(lines, full_timestamps=True) |
|
278 |
|
279 # render page |
|
280 return templates.render_to_response("channel_search", |
|
281 req = request, |
|
282 prefs = request.prefs, |
|
283 channel = channel, |
|
284 search_query = q, |
|
285 search_targets = t, |
|
286 count = count, |
|
287 page = page, |
|
288 skip = skip, |
|
289 max = max, |
|
290 lines = lines, |
|
291 ) |
|
292 |
|