4 from pylons
import config
, request
, response
, session
, tmpl_context
as c
, url
5 from pylons
.controllers
.util
import abort
, redirect
6 from routes
import request_config
7 from sqlalchemy
.orm
.exc
import NoResultFound
9 from spline
.lib
import helpers
as h
10 from spline
.lib
.base
import BaseController
, render
11 from spline
.lib
.plugin
.load
import run_hooks
12 from spline
.model
import meta
13 from splinext
.frontpage
.sources
import max_age_to_datetime
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 Plugins may also respond to the `frontpage_extras` hook with other
50 interesting things to put on the front page. There's no way to
51 customize the order of these extras or which appear and which don't, at
52 the moment. Such hooks should return an object with at least a
53 `template` attribute; the template will be called with the object
54 passed in as its `obj` argument.
56 Local plugins can override the fairly simple index.mako template to
57 customize the front page layout.
61 global_limit
= config
['spline-frontpage.limit']
62 global_max_age
= max_age_to_datetime(
63 config
['spline-frontpage.max_age'])
65 c
.sources
= config
['spline-frontpage.sources']
66 for source
in c
.sources
:
67 new_updates
= source
.poll(global_limit
, global_max_age
)
68 updates
.extend(new_updates
)
70 # Little optimization: once there are global_limit items, anything
71 # older than the oldest cannot possibly make it onto the list. So,
72 # bump global_max_age to that oldest time if this is ever the case.
73 updates
.sort(key
=lambda obj
: obj
.time
, reverse
=True)
74 del updates
[global_limit
:]
76 if updates
and len(updates
) == global_limit
:
77 global_max_age
= updates
[-1].time
79 # Find the oldest unseen item, to draw a divider after it.
80 # If this stays as None, the divider goes at the top
81 c
.last_seen_item
= None
82 # Could have a timestamp in the stash if this is a user, or in a cookie
83 # if this session has ever been logged out...
85 for source
in (c
.user
.stash
, request
.cookies
):
87 times
.append( int(source
['frontpage-last-seen-time']) )
88 except (KeyError, ValueError):
92 last_seen_time
= datetime
.datetime
.fromtimestamp(max(times
))
93 for update
in updates
:
94 if update
.time
> last_seen_time
:
95 c
.last_seen_item
= update
99 # Save ~now~ as the last-seen time
100 now
= datetime
.datetime
.now().strftime('%s')
102 c
.user
.stash
['frontpage-last-seen-time'] = now
103 meta
.Session
.add(c
.user
)
105 response
.set_cookie('frontpage-last-seen-time', now
)
107 # Done! Feed to template
110 # Hook for non-update interesting things to put on the front page.
111 # This hook should return objects with a 'template' attribute, and
112 # whatever else they need
113 c
.extras
= run_hooks('frontpage_extras')
115 ret
= render('/index.mako')
117 # Commit AFTER rendering the template! Committing invalidates
118 # everything in the session, undoing any eagerloading that may have
119 # been done by sources
120 meta
.Session
.commit()