478c367c998e17d902e72e2d89bacb8c87adb511
[zzz-spline-frontpage.git] / splinext / frontpage / controllers / frontpage.py
1 from collections import defaultdict
2 import logging
3 import re
4
5 from pylons import config, request, response, session, tmpl_context as c, url
6 from pylons.controllers.util import abort, redirect_to
7 from routes import request_config
8 from sqlalchemy.orm.exc import NoResultFound
9
10 from spline.lib import helpers as h
11 from spline.lib.base import BaseController, render
12 from spline.lib.plugin.load import run_hooks
13
14 log = logging.getLogger(__name__)
15
16 class FrontPageController(BaseController):
17
18 def index(self):
19 """Magicaltastic front page.
20
21 Plugins can register a hook called 'frontpage_updates_<type>' to add
22 updates to the front page. `<type>` is an arbitrary string indicating
23 the sort of update the plugin knows how to handle; for example,
24 spline-forum has a `frontpage_updates_forum` hook for posting news from
25 a specific forum.
26
27 Hook handlers should return a list of FrontPageUpdate objects.
28
29 Standard hook parameters are `limit`, the maximum number of items that
30 should ever be returned.
31
32 Updates are configured in the .ini like so:
33
34 spline-frontpage.sources.foo = updatetype
35 spline-frontpage.sources.foo.opt1 = val1
36 spline-frontpage.sources.foo.opt2 = val2
37
38 Note that the 'foo' name is completely arbitrary and is only used for
39 grouping options together. This will result in a call to:
40
41 run_hooks('frontpage_updates_updatetype', opt1=val1, opt2=val2)
42
43 Standard options are not shown and take precedence over whatever's in
44 the config file.
45
46 Local plugins can override the fairly simple index.mako template to
47 customize the front page layout.
48 """
49 # XXX no reason to do this on the fly; cache it on server startup
50 update_config = defaultdict(dict) # source_name => config
51 key_rx = re.compile(
52 '(?x) ^ spline-frontpage [.] sources [.] (\w+) (?: [.] (\w+) )? $')
53 for key, val in config.iteritems():
54 match = key_rx.match(key)
55 if not match:
56 continue
57
58 source_name, subkey = match.groups()
59 if not subkey:
60 # This is the type declaration; use a special key
61 subkey = '__type__'
62
63 update_config[source_name][subkey] = val
64
65
66 global_config = dict(
67 limit = 10,
68 )
69
70 # Ask plugins to deal with this stuff for us!
71 updates = []
72 for source, source_config in update_config.iteritems():
73 source_config2 = source_config.copy()
74 hook_name = 'frontpage_updates_' + source_config2.pop('__type__')
75 source_config2.update(global_config)
76
77 # Hooks should return a list of FrontPageUpdate objects, making this
78 # return value a list of lists
79 updates_lol = run_hooks(hook_name, **source_config2)
80 updates += sum(updates_lol, [])
81
82 # Sort everything by descending time, then crop to the right number of
83 # items
84 updates.sort(key=lambda obj: obj.time)
85 updates.reverse()
86 c.updates = updates[:global_config['limit']]
87
88 return render('/index.mako')