diff -r 9c7769850195 -r 6db2527b67cf qmsk/irclogs/handlers.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/irclogs/handlers.py Sun Sep 13 01:15:56 2009 +0300 @@ -0,0 +1,292 @@ +""" + Our URL action handlers +""" + +import datetime, calendar, pytz + +from qmsk.web import http, template + +import urls, channels, helpers +import preferences as prefs +from preferences import preferences +import config, log_search + +# load templates from here +templates = template.TemplateLoader("templates", + _helper_class = helpers.Helpers, + urls = urls, + channel_list = config.LOG_CHANNELS, + config = config, +) + +# return a http.Response for the given text in the given format +def _render_type (request, channel, lines, type, full_timestamps=False) : + """ + Render the given LogLines as a http.Response in the given format, which is one of: + html - XXX: not supported + txt - Plaintext + png - PNG image + rss - RSS feed + """ + + # load related preferences + formatter = request.prefs['formatter'] + + kwargs = dict( + full_timestamps = full_timestamps + ) + + # we can render in various modes... + if type in ('html', None) : + xxx + + elif type == 'txt' : + # plaintext + lines = formatter.format_txt(lines, **kwargs) + + # build data + data = '\n'.join(data for line, data in lines) + + return http.Response(data, 'text/plain') + + elif type == 'png' : + # PNG image + png_data = formatter.format_png(lines, **kwargs) + + return http.Response(png_data, 'image/png', charset=None) + + elif type == 'rss' : + # RSS feed + rss_data = formatter.format_rss(lines, **kwargs) + + # XXX: fix to render as unicode? + return http.Response(rss_data, 'application/rss+xml', charset=None) + + else : + raise http.ResponseError("Unrecognized type: %r" % (type, )) + +def _render_date (request, channel, date, lines, type, count, page, max) : + """ + Render the given LogLines as a http.Response for channel_date + """ + + # type? + if type : + # special type + return _render_type(request, channel, lines, type) + + else : + # format HTML + lines = request.prefs['formatter'].format_html(lines) + + # render + return templates.render_to_response("channel_date", + req = request, + prefs = request.prefs, + channel = channel, + date = date, + count = count, + page = page, + max = max, + lines = lines, + + # for prev/next date + date_next = channel.source.get_next_date(date), + date_prev = channel.source.get_prev_date(date), + ) + +@preferences.handler() +def index (request) : + """ + The topmost index page, display a list of available channels, perhaps some general stats + """ + + return templates.render_to_response("index", + req = request, + prefs = request.prefs, + ) + +# XXX: fix this namespace crap +@preferences.handler() +def preferences_ (request) : + """ + Preferences editor + """ + + # POST? + if request.is_post() : + # update any modified preferences + for pref in preferences.pref_list : + # get the POST'd value, default = None + post_value = request.get_post(pref.name, None) + + # skip non-specified values + # XXX: this is to not clobber timezone_offset to None + if post_value is None : + continue + + # parse the POST'd value, None -> default + new_value = request.prefs.parse(pref, post_value) + + # update if given and changed + if new_value != request.prefs[pref] : + request.prefs.set(pref.name, new_value) + + # render + return templates.render_to_response("preferences", + req = request, + prefs = request.prefs, + preferences = prefs, + ) + +def channel_select (request, channel) : + """ + Redirect to the appropriate channel_view + """ + + return http.Redirect(urls.channel.build(request, channel=channel)) + +@preferences.handler(prefs.formatter) +def channel_last (request, channel, count, formatter, type=None) : + """ + The main channel view page, displaying the most recent lines + """ + + # get latest events + lines = channel.source.get_latest(count) + + # type? + if type : + # other format + return _render_type(request, channel, lines, type) + + else : + # format HTML + lines = formatter.format_html(lines) + + # render page + return templates.render_to_response("channel_last", + req = request, + prefs = request.prefs, + channel = channel, + count = count, + lines = lines, + ) + +@preferences.handler(prefs.formatter, prefs.timezone, prefs.count) +def channel_link (request, channel, timestamp, formatter, timezone, count, type=None) : + """ + Display channel_date for specific UTC timestamp + """ + + # convert timestamp to user's timezone + timestamp = timestamp.astimezone(timezone) + + # get correct day's correct page of lines + page, max, lines = channel.source.get_date_paged(timestamp, count) + + # render channel_date + return _render_date (request, channel, timestamp, lines, type, count, page, max) + +@preferences.handler(prefs.timezone) +def channel_calendar (request, channel, year, month, timezone) : + """ + Display a list of avilable logs for some month + """ + + # current date as default + now = timezone.localize(datetime.datetime.now()) + + # target year/month + target = timezone.localize(datetime.datetime( + year = year if year else now.year, + month = month if month else now.month, + day = 1 + )) + + # display calendar + return templates.render_to_response("channel_calendar", + req = request, + prefs = request.prefs, + channel = channel, + month = target, + ) + +@preferences.handler(prefs.count, prefs.timezone) +def channel_date (request, channel, date, count, timezone, page=1, type=None) : + """ + Display all log data for the given date + """ + + # convert date to user's timezone + date = timezone.localize(date) + +# print +# print "channel_date: date=%s" % date + + # get that day's events, either paged or not + if page : + page, max, lines = channel.source.get_date_paged(date, count, page) + + else : + lines = channel.source.get_date(date) + max = None + + # render channel_date + return _render_date (request, channel, date, lines, type, count, page, max) + +@preferences.handler(prefs.formatter, prefs.count) +def channel_search (request, channel, formatter, count, q=None, page=1, max=1, type=None, t=None) : + """ + Display the search form for the channel for GET, or do the search for POST. + """ + + # calculate skip offset from page/count + skip = (page - 1) * count + + # got a search query? + if q : + # attribute targets + targets = dict(('search_%s' % target, True) for target in t if target in ('msg', 'nick')) if t else {} + + try : + # do search + lines = log_search.get_index().search_simple(channel, q, count, skip, **targets) + + # update max? + if max and page > max : + max = page + + except log_search.NoResultsFound : + # no results + lines = None + + else : + # just display the search form + lines = None + + # type? + if type and lines : + # special type + return _render_type(request, channel, lines, type, full_timestamps=True) + + else : + # format lines to HTML if any + if lines : + # format + lines = formatter.format_html(lines, full_timestamps=True) + + # render page + return templates.render_to_response("channel_search", + req = request, + prefs = request.prefs, + channel = channel, + search_query = q, + search_targets = t, + count = count, + page = page, + skip = skip, + max = max, + lines = lines, + ) +