split defined configuration constants into config, and implement search result pagination
--- a/channels.py Mon Feb 09 22:17:10 2009 +0200
+++ b/channels.py Mon Feb 09 23:49:57 2009 +0200
@@ -2,65 +2,37 @@
Our list of LogChannels
"""
-import pytz
-
-# for relpath
-import os.path
-
-from log_channel import LogChannel
-from log_source import LogDirectory
-from log_parser import IrssiParser
-
-relpath = lambda path : os.path.join(os.path.dirname(__file__), path)
-
class ChannelList (object) :
"""
The list of channels, and related methods
"""
- # timezone to use
- TIMEZONE = pytz.timezone('Europe/Helsinki')
- # the parser that we use
- PARSER = IrssiParser(TIMEZONE, "%H:%M:%S")
-
- # the statically defined channel list
- CHANNELS = {
- 'tycoon': LogChannel('tycoon', "OFTC", "#tycoon",
- LogDirectory(relpath('logs/tycoon'), TIMEZONE, PARSER)
- ),
- 'openttd': LogChannel('openttd', "OFTC", "#openttd",
- LogDirectory(relpath('logs/openttd'), TIMEZONE, PARSER)
- ),
- }
-
- def __init__ (self, channels) :
+ def __init__ (self, channel_list) :
"""
Initialize with the given channel dict
"""
-
- self.channels = channels
+
+ self.channel_list = channel_list
+ self.channel_dict = dict((channel.id, channel) for channel in channel_list)
def lookup (self, channel_name) :
"""
Looks up the LogChannel for the given name
"""
- return self.channels[channel_name]
+ return self.channel_dict[channel_name]
def dict (self) :
"""
Returns a { name: LogChannel } dict
"""
- return self.channels
+ return self.channel_dict
def __iter__ (self) :
"""
Iterate over our defined LogChannel objects
"""
- return self.channels.itervalues()
+ return iter(self.channel_list)
-# the global singletone ChannelList...
-channel_list = ChannelList(ChannelList.CHANNELS)
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/config.py Mon Feb 09 23:49:57 2009 +0200
@@ -0,0 +1,69 @@
+"""
+ Configureable defaults
+"""
+
+import os.path, pytz
+from log_parser import IrssiParser
+from log_channel import LogChannel
+from log_source import LogDirectory
+from log_formatter import IrssiFormatter
+from channels import ChannelList
+import log_formatter
+
+# build relative paths
+relpath = lambda path : os.path.join(os.path.dirname(__file__), path)
+
+# timezone to use for logs
+LOG_TIMEZONE = pytz.timezone('Europe/Helsinki')
+
+# timestamp format for logfiles
+LOG_TIMESTAMP_FMT = '%H:%M:%S'
+
+# character set used for logfiles
+LOG_CHARSET = 'utf-8'
+
+# log filename format
+LOG_FILENAME_FMT = '%Y-%m-%d'
+
+# the log parser that we use
+LOG_PARSER = IrssiParser(LOG_TIMEZONE, LOG_TIMESTAMP_FMT)
+
+# the statically defined channel list
+LOG_CHANNELS = ChannelList([
+ LogChannel('tycoon', "OFTC", "#tycoon",
+ LogDirectory(relpath('logs/tycoon'), LOG_TIMEZONE, LOG_PARSER, LOG_CHARSET, LOG_FILENAME_FMT)
+ ),
+
+ LogChannel('openttd', "OFTC", "#openttd",
+ LogDirectory(relpath('logs/openttd'), LOG_TIMEZONE, LOG_PARSER, LOG_CHARSET, LOG_FILENAME_FMT)
+ ),
+])
+
+# date format for URLs
+URL_DATE_FMT = '%Y-%m-%d'
+
+# month name format
+MONTH_FMT = '%B %Y'
+
+# timezone name format
+TIMEZONE_FMT = '%Z %z'
+
+# available formatters
+LOG_FORMATTERS = log_formatter.FORMATTERS
+
+# default preferences
+PREF_TIME_FMT_DEFAULT = '%H:%M:%S'
+PREF_DATE_FMT_DEFAULT = '%Y-%m-%d'
+PREF_TIMEZONE_DEFAULT = pytz.utc
+PREF_FORMATTER_DEFAULT = IrssiFormatter
+PREF_COUNT_DEFAULT = 200
+PREF_COUNT_MAX = None
+
+# search line count options
+SEARCH_LINE_COUNT_OPTIONS = (
+ (50, 50),
+ (100, 100),
+ (200, 200),
+ (None, "∞"),
+)
+
--- a/handlers.py Mon Feb 09 22:17:10 2009 +0200
+++ b/handlers.py Mon Feb 09 23:49:57 2009 +0200
@@ -9,12 +9,14 @@
import urls, channels, helpers
import preferences as prefs
from preferences import preferences
+import config
# load templates from here
templates = template.TemplateLoader("templates",
_helper_class = helpers.Helpers,
urls = urls,
- channel_list = channels.channel_list,
+ channel_list = config.LOG_CHANNELS,
+ config = config,
)
# our LogSearch thing
@@ -162,8 +164,8 @@
lines = lines,
)
-@preferences.handler(prefs.formatter)
-def channel_search (request, channel, formatter, q=None, count=None, skip=None) :
+@preferences.handler(prefs.formatter, prefs.count)
+def channel_search (request, channel, formatter, count, q=None, skip=0, max=None) :
"""
Display the search form for the channel for GET, or do the search for POST
"""
@@ -185,6 +187,9 @@
prefs = request.prefs,
channel = channel,
search_query = q,
+ count = count,
+ skip = skip,
+ max = max,
lines = lines,
)
--- a/helpers.py Mon Feb 09 22:17:10 2009 +0200
+++ b/helpers.py Mon Feb 09 23:49:57 2009 +0200
@@ -6,7 +6,7 @@
import qmsk.web.helpers
-import preferences, urls
+import preferences, urls, config
class Helpers (qmsk.web.helpers.Helpers) :
"""
@@ -18,14 +18,14 @@
Returns a string describing the given timezone
"""
- return self.now().strftime("%Z%z")
+ return self.now().strftime(config.TIMEZONE_FMT)
def fmt_month (self, date) :
"""
Formats a month
"""
- return date.strftime('%B %Y')
+ return date.strftime(config.MONTH_FMT)
def fmt_weekday (self, wday) :
"""
@@ -151,4 +151,40 @@
"""
return urls.types['ts'].build(dtz)
+
+ def skip_next (self, count, skip) :
+ """
+ Return skip offset for next page
+ """
+ return count + skip
+
+ def skip_page (self, count, page) :
+ """
+ Skip to page
+ """
+
+ if page :
+ return count * page
+
+ else :
+ return None
+
+ def skip_prev (self, count, skip) :
+ """
+ Return skip offset for previous page, None for first page
+ """
+
+ if skip > count :
+ return skip - count
+
+ else :
+ return None
+
+ def max (self, *values) :
+ """
+ Returns the largest of the given values
+ """
+
+ return max(values)
+
--- a/log_formatter.py Mon Feb 09 22:17:10 2009 +0200
+++ b/log_formatter.py Mon Feb 09 23:49:57 2009 +0200
@@ -42,7 +42,7 @@
# full timestamps?
if full_timestamp :
- # XXX: ugly
+ # XXX: ugly hack
timestamp_fmt = '%Y-%m-%d ' + self.timestamp_fmt
else :
--- a/log_source.py Mon Feb 09 22:17:10 2009 +0200
+++ b/log_source.py Mon Feb 09 23:49:57 2009 +0200
@@ -39,7 +39,7 @@
XXX: modify to implement LogSource?
"""
- def __init__ (self, path, parser, start_date=None, charset='utf-8', sep='\n') :
+ def __init__ (self, path, parser, charset, start_date=None, sep='\n') :
"""
Open the file at the given path, which contains data with the given charset, as lines separated by the
given separator. Lines are parsed using the given parser, using the given date as an initial date, see
@@ -204,7 +204,7 @@
A directory containing a series of timestamped LogFiles
"""
- def __init__ (self, path, tz, parser, charset='utf-8', filename_fmt='%Y-%m-%d') :
+ def __init__ (self, path, tz, parser, charset, filename_fmt) :
"""
Load the logfiles at the given path.
@@ -247,7 +247,7 @@
try :
if load :
# open+return the LogFile
- return LogFile(path, self.parser, d, self.charset)
+ return LogFile(path, self.parser, self.charset, d)
else :
# test
--- a/preferences.py Mon Feb 09 22:17:10 2009 +0200
+++ b/preferences.py Mon Feb 09 23:49:57 2009 +0200
@@ -195,6 +195,7 @@
# now for our defined preferences....
import pytz
+import config
class TimeFormat (urltree.URLStringType, Preference) :
"""
@@ -205,7 +206,7 @@
name = 'time_format'
# default value
- default = "%H:%M:%S"
+ default = config.PREF_TIME_FMT_DEFAULT
class DateFormat (urltree.URLStringType, Preference) :
"""
@@ -216,7 +217,7 @@
name = 'date_format'
# default value
- default = "%Y-%m-%d"
+ default = config.PREF_DATE_FMT_DEFAULT
class Timezone (Preference) :
"""
@@ -227,7 +228,7 @@
name = 'timezone'
# default value is UTC...
- default = pytz.utc
+ default = config.PREF_TIMEZONE_DEFAULT
def parse (self, name) :
"""
@@ -280,18 +281,32 @@
return fmt_cls(prefs[timezone], prefs[time_format])
-# and then build the Preferences object
-import log_formatter
+class Count (urltree.URLIntegerType, Preference) :
+ """
+ Number of lines of log data to display per page
+ """
-time_format = TimeFormat()
-date_format = DateFormat()
-timezone = Timezone()
-formatter = Formatter(log_formatter.FORMATTERS, log_formatter.IrssiFormatter)
+ # set name
+ name = "count"
+
+ # default
+ default = config.PREF_COUNT_DEFAULT
+
+ def __init__ (self) :
+ super(Count, self).__init__(allow_negative=False, allow_zero=False, max=config.PREF_COUNT_MAX)
+
+# and then build the Preferences object
+time_format = TimeFormat()
+date_format = DateFormat()
+timezone = Timezone()
+formatter = Formatter(config.LOG_FORMATTERS, config.PREF_FORMATTER_DEFAULT)
+count = Count()
preferences = Preferences([
time_format,
date_format,
timezone,
formatter,
+ count,
])
--- a/static/irclogs.css Mon Feb 09 22:17:10 2009 +0200
+++ b/static/irclogs.css Mon Feb 09 23:49:57 2009 +0200
@@ -307,3 +307,45 @@
color: #000000;
}
+/* Pagination */
+div.paginate {
+ height: 50px;
+
+ padding-top: 20px;
+
+ text-align: center;
+}
+
+div.paginate ul {
+ margin: 0px;
+ padding: 0px;
+
+ line-height: 30px;
+
+ border: 1px solid #aaa;
+
+ white-space: nowrap;
+}
+
+div.paginate li {
+ list-style-type: none;
+ display: inline;
+}
+
+div.paginate li * {
+ padding: 7px 10px;
+}
+
+div.paginate li a {
+ color: black;
+ text-decoration: none;
+}
+
+div.paginate li span {
+ color: #d5d5d5;
+}
+
+div.paginate li a:hover {
+ background-color: #d0d0d0;
+}
+
--- a/templates/channel_search.tmpl Mon Feb 09 22:17:10 2009 +0200
+++ b/templates/channel_search.tmpl Mon Feb 09 23:49:57 2009 +0200
@@ -1,5 +1,35 @@
<%inherit file="channel.tmpl" />
+<%def name="paginate(url, count, skip, max, **args)">
+ ## update max?
+ <% max = h.max(max, skip) %>
+ ## number of pages
+ <% page_count = max / count + 1 %>
+ <div class="paginate">
+ <ul>
+ <li>
+ % if skip :
+ <a href="${h.build_url(url, count=count, skip=h.skip_prev(count, skip), max=max, **args)}">« Prev</a>
+ % else :
+ <span>« Prev</span>
+ %endif
+ </li>
+ % for page in xrange(page_count) :
+ <li>
+ % if page == skip / count :
+ <strong>${page + 1}</strong>
+ % else :
+ <a href="${h.build_url(url, count=count, skip=h.skip_page(count, page), max=max, **args)}">${page + 1}</a>
+ % endif
+ </li>
+ % endfor
+ <li>
+ <a href="${h.build_url(url, count=count, skip=h.skip_next(count, max), **args)}">More »</a>
+ </li>
+ </ul>
+ </div>
+</%def>
+
% if not search_query :
<div id="title">${channel.title} :: Search</div>
@@ -9,10 +39,9 @@
<input type="submit" value="Search" />
Results/page: <select name="count">
- <option value="50">50</option>
- <option value="100">100</option>
- <option value="200">200</option>
- <option value="">∞</option>
+ % for cc, cc_label in config.SEARCH_LINE_COUNT_OPTIONS :
+ <option value="${cc if cc else ''}"${' selected="selected"' if cc == count else ''}>${cc_label}</option>
+ % endfor
</select>
</form>
@@ -32,5 +61,7 @@
% else :
<div id="title">${channel.title} :: Search '${search_query}'</div>
+${paginate(urls.channel_search, count, skip, max, channel=channel, q=search_query)}
<%include file="lines.tmpl" />
+${paginate(urls.channel_search, count, skip, max, channel=channel, q=search_query)}
% endif
--- a/templates/preferences.tmpl Mon Feb 09 22:17:10 2009 +0200
+++ b/templates/preferences.tmpl Mon Feb 09 23:49:57 2009 +0200
@@ -41,6 +41,12 @@
% endfor
</select>
</p>
+
+ <p>
+ <label for="count">Lines / Page:</label>
+ <input type="text" name="count" value="${prefs['count']}" />
+ <span class="example">(Blank for infinite)</span>
+ </p>
</fieldset>
<input type="submit" value="Save" />
--- a/urls.py Mon Feb 09 22:17:10 2009 +0200
+++ b/urls.py Mon Feb 09 23:49:57 2009 +0200
@@ -13,15 +13,15 @@
import utils
# for configuration
-import channels
+import config
# our URLTypes
types = dict(
# LogChannel
- cid = utils.URLChannelName(channels.channel_list.dict()),
+ cid = utils.URLChannelName(config.LOG_CHANNELS.dict()),
# datetime
- date = utils.URLDateType('%Y-%m-%d'),
+ date = utils.URLDateType(config.URL_DATE_FMT),
# UTC timestamp
ts = utils.URLTimestampType(),
@@ -39,7 +39,7 @@
channel_link = url('/channels/{channel:cid}/link/{timestamp:ts}', handlers.channel_link )
channel_calendar = url('/channels/{channel:cid}/calendar/{year:int=0}/{month:int=0}', handlers.channel_calendar )
channel_date = url('/channels/{channel:cid}/date/{date:date}', handlers.channel_date )
-channel_search = url('/channels/{channel:cid}/search/?q=&count:int=&skip:int=', handlers.channel_search )
+channel_search = url('/channels/{channel:cid}/search/?q=&skip:int=0&max:int=', handlers.channel_search )
# mapper
mapper = urltree.URLTree(urls)
--- a/utils.py Mon Feb 09 22:17:10 2009 +0200
+++ b/utils.py Mon Feb 09 23:49:57 2009 +0200
@@ -37,7 +37,7 @@
Handle dates in URLs as naive datetime objects (with indeterminate time info)
"""
- def __init__ (self, date_fmt="%Y-%m-%d") :
+ def __init__ (self, date_fmt) :
"""
Format/parse dates using the given format
"""