diff -r dcb67a8f24be -r 8103d18907a0 preferences.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/preferences.py Mon Feb 09 03:05:43 2009 +0200 @@ -0,0 +1,277 @@ +""" + Handling user preferences +""" + +import functools +import Cookie + +from qmsk.web import urltree + +class Preference (urltree.URLType) : + """ + A specific preference + """ + + # the name to use + name = None + + # the default value + default = None + + def process (self, preferences, value) : + """ + Post-process this preference value. This can access the values of other preferences or the request via + the given RequestPreferences. Note that the other items will not be post-processed here. + + Defaults to just return value. + """ + + return value + +class RequestPreferences (object) : + """ + Represents the specific preferences for some request + """ + + def __init__ (self, preferences, request, value_map=None) : + """ + Initialize with the given Preferences object, http Request, and list of mapping of raw preference values + """ + + # store + self.preferences = preferences + self.request = request + + # initialize + self.values = {} + self.set_cookies = {} + + # load preferences + for pref in preferences.pref_list : + # got a value for it? + if value_map and pref.name in value_map : + # get value + value = value_map[pref.name] + + # parse it + value = pref.parse(value) + + else : + # use default value + value = pref.default + + # add + self.values[pref.name] = value + + # then post-process using the Preferences + self.values = dict( + (name, self.preferences.pref_map[name].process(self, value)) for name, value in self.values.iteritems() + ) + + def get (self, pref) : + """ + Return the value for the given Preference + """ + + return self.values[pref.name] + + def set (self, name, value_obj) : + """ + Set a new value for the given preference + """ + + # sanity-check to make sure we're not setting it twice... + assert name not in self.set_cookies + + # encode using the Preference object + value_str = self.preferences.pref_map[name].build(value_obj) + + # update in our dict + self.values[name] = value_obj + + # add to set_cookies + self.set_cookies[name] = value_str + +class Preferences (object) : + """ + Handle user preferences using cookies + """ + + def __init__ (self, pref_list) : + """ + Use the given list of Preference objects + """ + + # store + self.pref_list = pref_list + + # translate to mapping as well + self.pref_map = dict((pref.name, pref) for pref in pref_list) + + def load (self, request, ) : + """ + Load the set of preferences for the given request, and return as a { name -> value } dict + """ + + # the dict of values + values = {} + + # load the cookies + cookie_data = request.env.get('HTTP_COOKIE') + + # got any? + if cookie_data : + # parse into a SimpleCookie + cookies = Cookie.SimpleCookie(cookie_data) + + # update the the values + values.update((morsel.key, morsel.value) for morsel in cookies.itervalues()) + + else : + cookies = None + + # apply any query parameters + for pref in self.pref_list : + # look for a query param + value = request.get_arg(pref.name) + + if value : + # override + values[pref.name] = value + + # build the RequestPreferences object + return cookies, RequestPreferences(self, request, values) + + def handler (self, *pref_list) : + """ + Intended to be used as a decorator for a request handler, this will load the give Preferences and pass + them to the wrapped handler as keyword arguments, in addition to any others given. + """ + + def _decorator (func) : + @functools.wraps(func) + def _handler (request, **args) : + # load preferences + cookies, prefs = self.load(request) + + # update args with new ones + args.update(((pref.name, prefs.get(pref)) for pref in pref_list)) + + # handle to get response + response = func(request, **args) + + # set cookies? + if prefs.set_cookies : + # update cookies + for key, value in prefs.set_cookies.iteritems() : + cookies[key] = value + + # add headers + for morsel in cookies.itervalues() : + response.add_header('Set-cookie', morsel.OutputString()) + + return response + + # return wrapped handler + return _handler + + # return decorator... + return _decorator + +# now for our defined preferences.... +import pytz + +class TimeFormat (urltree.URLStringType, Preference) : + """ + Time format + """ + + # set name + name = 'time_format' + + # default value + default = "%H:%M:%S" + +class DateFormat (urltree.URLStringType, Preference) : + """ + Date format + """ + + # set name + name = 'date_format' + + # default value + default = "%Y-%m%d" + +class Timezone (Preference) : + """ + Timezone + """ + + # set name + name = 'timezone' + + # default value is UTC... + default = pytz.utc + + def parse (self, name) : + """ + tz_name -> pytz.timezone + """ + + return pytz.timezone(name) + + def build (self, tz) : + """ + pytz.timezone -> tz_name + """ + + return tz.zone + +class Formatter (Preference) : + """ + LogFormatter to use + """ + + # set name + name = 'formatter' + + def __init__ (self, formatters, default) : + """ + Use the given { name -> class LogFormatter } dict and default (a LogFormatter class) + """ + + self.formatters = formatters + self.default = default + + def parse (self, fmt_name) : + """ + fmt_name -> class LogFormatter + """ + + return self.formatters[fmt_name] + + def build (self, fmt_cls) : + """ + class LogFormatter -> fmt_name + """ + + return fmt.name + + def process (self, prefs, fmt_cls) : + """ + class LogFormatter -> LogFormatter(tz, time_fmt) + """ + + return fmt_cls(prefs.get(Timezone), prefs.get(TimeFormat)) + +# and then build the Preferences object +import log_formatter + +preferences = Preferences([ + TimeFormat(), + DateFormat(), + Timezone(), + Formatter(log_formatter.FORMATTERS, log_formatter.IrssiFormatter), +]) +