1 from collections
import defaultdict
6 from pylons
import config
, request
, response
, session
, tmpl_context
as c
, url
7 from pylons
.controllers
.util
import abort
, redirect_to
8 from routes
import request_config
9 from sqlalchemy
.orm
.exc
import NoResultFound
11 from spline
.lib
import helpers
as h
12 from spline
.lib
.base
import BaseController
, render
13 from spline
.lib
.plugin
.load
import run_hooks
15 log
= logging
.getLogger(__name__
)
17 class FrontPageController(BaseController
):
20 """Magicaltastic front page.
22 Plugins can register a hook called 'frontpage_updates_<type>' to add
23 updates to the front page. `<type>` is an arbitrary string indicating
24 the sort of update the plugin knows how to handle; for example,
25 spline-forum has a `frontpage_updates_forum` hook for posting news from
28 Hook handlers should return a list of FrontPageUpdate objects.
30 Standard hook parameters are:
31 `limit`, the maximum number of items that should ever be returned.
32 `max_age`, the number of seconds after which items expire.
33 `title`, a name for the source.
34 `icon`, an icon to show next to its name.
36 `limit` and `max_age` are also global options.
38 Updates are configured in the .ini like so:
40 spline-frontpage.sources.foo = updatetype
41 spline-frontpage.sources.foo.opt1 = val1
42 spline-frontpage.sources.foo.opt2 = val2
44 Note that the 'foo' name is completely arbitrary and is only used for
45 grouping options together. This will result in a call to:
47 run_hooks('frontpage_updates_updatetype', opt1=val1, opt2=val2)
49 Local plugins can override the fairly simple index.mako template to
50 customize the front page layout.
52 # XXX no reason to do this on the fly; cache it on server startup
53 update_config
= defaultdict(dict) # source_name => config
55 '(?x) ^ spline-frontpage [.] sources [.] (\w+) (?: [.] (\w+) )? $')
56 for key
, val
in config
.iteritems():
57 match
= key_rx
.match(key
)
61 source_name
, subkey
= match
.groups()
63 # This is the type declaration; use a special key
66 if subkey
in ('limit', 'max_age'):
68 update_config
[source_name
][subkey
] = val
70 global_limit
= int(config
.get('spline-frontpage.limit', 10))
71 now
= datetime
.datetime
.now()
73 global_max_age
= now
- datetime
.timedelta(
74 seconds
=int(config
['spline-frontpage.max_age']))
78 # Ask plugins to deal with this stuff for us!
80 for source
, source_config
in update_config
.iteritems():
81 hook_name
= 'frontpage_updates_' + source_config
['__type__']
83 # Merge with the global config
84 merged_config
= source_config
.copy()
85 del merged_config
['__type__']
87 merged_config
['limit'] = min(
88 merged_config
.get('limit', global_limit
),
93 local_max_age
= now
- datetime
.timedelta(
94 seconds
=merged_config
['max_age'])
98 if global_max_age
and local_max_age
:
99 merged_config
['max_age'] = max(global_max_age
, local_max_age
)
101 merged_config
['max_age'] = global_max_age
or local_max_age
103 # Hooks should return a list of FrontPageUpdate-like objects,
104 # making this return value a list of lists
105 updates_lol
= run_hooks(hook_name
, **merged_config
)
106 updates
+= sum(updates_lol
, [])
108 # Little optimization: maximum age effectively becomes the age of
109 # the oldest thing that would still appear on the page, as anything
110 # older would drop off the end no matter what.
111 # So sort by descending time and crop each iteration...
112 updates
.sort(key
=lambda obj
: obj
.time
, reverse
=True)
113 updates
= updates
[:global_limit
]
116 global_max_age
= updates
[-1].time
120 return render('/index.mako')