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