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
.model
import meta
12 from splinext
.frontpage
.sources
import max_age_to_datetime
14 log
= logging
.getLogger(__name__
)
16 class FrontPageController(BaseController
):
19 """Magicaltastic front page.
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
27 Hook handlers should return a list of FrontPageUpdate objects.
29 Standard hook parameters are:
30 `limit`, the maximum number of items that should ever be returned.
31 `max_age`, the number of seconds after which items expire.
32 `title`, a name for the source.
33 `icon`, an icon to show next to its name.
35 `limit` and `max_age` are also global options.
37 Updates are configured in the .ini like so:
39 spline-frontpage.sources.foo = updatetype
40 spline-frontpage.sources.foo.opt1 = val1
41 spline-frontpage.sources.foo.opt2 = val2
43 Note that the 'foo' name is completely arbitrary and is only used for
44 grouping options together. This will result in a call to:
46 run_hooks('frontpage_updates_updatetype', opt1=val1, opt2=val2)
48 Local plugins can override the fairly simple index.mako template to
49 customize the front page layout.
53 global_limit
= config
['spline-frontpage.limit']
54 global_max_age
= max_age_to_datetime(
55 config
['spline-frontpage.max_age'])
57 c
.sources
= config
['spline-frontpage.sources']
58 for source
in c
.sources
:
59 new_updates
= source
.poll(global_limit
, global_max_age
)
60 updates
.extend(new_updates
)
62 # Little optimization: once there are global_limit items, anything
63 # older than the oldest cannot possibly make it onto the list. So,
64 # bump global_max_age to that oldest time if this is ever the case.
65 updates
.sort(key
=lambda obj
: obj
.time
, reverse
=True)
66 del updates
[global_limit
:]
68 if updates
and len(updates
) == global_limit
:
69 global_max_age
= updates
[-1].time
71 # Find the oldest unseen item, to draw a divider after it.
72 # If this stays as None, the divider goes at the top
73 c
.last_seen_item
= None
74 # Could have a timestamp in the stash if this is a user, or in a cookie
75 # if this session has ever been logged out...
77 for source
in (c
.user
.stash
, request
.cookies
):
79 times
.append( int(source
['frontpage-last-seen-time']) )
80 except (KeyError, ValueError):
84 last_seen_time
= datetime
.datetime
.fromtimestamp(max(times
))
85 for update
in updates
:
86 if update
.time
> last_seen_time
:
87 c
.last_seen_item
= update
91 # Save ~now~ as the last-seen time
92 now
= datetime
.datetime
.now().strftime('%s')
94 c
.user
.stash
['frontpage-last-seen-time'] = now
95 meta
.Session
.add(c
.user
)
97 response
.set_cookie('frontpage-last-seen-time', now
)
99 # Done! Feed to template
102 ret
= render('/index.mako')
104 # Commit AFTER rendering the template! Committing invalidates
105 # everything in the session, undoing any eagerloading that may have
106 # been done by sources
107 meta
.Session
.commit()