handlers.py
author Tero Marttila <terom@fixme.fi>
Sun, 15 Feb 2009 23:55:48 +0200
changeset 130 4212fd69d671
parent 129 67a30d680f60
child 131 67f5d2fdca1d
permissions -rw-r--r--
remove debug crap and fix Timezone.is_default to detect config.PREF_TIMEZONE_DEFAULT as well
"""
    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 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,
        )