handlers.py
author Tero Marttila <terom@fixme.fi>
Sat, 14 Feb 2009 20:09:08 +0200
changeset 127 5746705a2719
parent 123 3297596ab606
child 129 67a30d680f60
permissions -rw-r--r--
improve LogSearchIndex error handling, add explicit close() method, and modify get_index to not keep the index open persistently
"""
    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),
        )

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,
    )

# 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+parse new POST'd value
            # XXX: this doesn't postprocess
            new_value = pref.parse(request.get_post(pref.name))

            # update if 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,
        timezones       = pytz.common_timezones,
    )

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,
        )