--- /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),
+])
+