No need for ellipses on short RSS entries.
[zzz-spline-frontpage.git] / splinext / frontpage / __init__.py
1 from collections import defaultdict, namedtuple
2 from pkg_resources import resource_filename
3 import re
4 import subprocess
5
6 from pylons import config
7
8 from spline.lib import helpers
9 from spline.lib.plugin import PluginBase, PluginLink, Priority
10 from spline.lib.plugin.load import run_hooks
11
12 import splinext.frontpage.controllers.frontpage
13 from splinext.frontpage.sources import FeedSource, GitSource
14
15 def add_routes_hook(map, *args, **kwargs):
16 """Hook to inject some of our behavior into the routes configuration."""
17 map.connect('/', controller='frontpage', action='index')
18
19 def load_sources_hook(config, *args, **kwargs):
20 """Hook to load all the known sources and stuff them in config. Run once,
21 on server startup.
22
23 Frontpage hooks are also passed the `config` hash, as it's not available
24 during setup.
25 """
26 # Extract source definitions from config and store as source_name => config
27 update_config = defaultdict(dict)
28 key_rx = re.compile(
29 '(?x) ^ spline-frontpage [.] sources [.] (\w+) (?: [.] (\w+) )? $')
30 for key, val in config.iteritems():
31 # Match against spline-frontpage.source.(source).(key)
32 match = key_rx.match(key)
33 if not match:
34 continue
35
36 source_name, subkey = match.groups()
37 if not subkey:
38 # This is the type declaration; use a special key
39 subkey = '__type__'
40
41 update_config[source_name][subkey] = val
42
43 # Figure out the global limit and expiration time, with reasonable
44 # defaults. Make sure they're integers.
45 global_limit = int(config.get('spline-frontpage.limit', 10))
46 # max_age is optional and can be None
47 try:
48 global_max_age = int(config['spline-frontpage.max_age'])
49 except KeyError:
50 global_max_age = None
51
52 config['spline-frontpage.limit'] = global_limit
53 config['spline-frontpage.max_age'] = global_max_age
54
55 # Ask plugins to turn configuration into source objects
56 sources = []
57 for source, source_config in update_config.iteritems():
58 hook_name = 'frontpage_updates_' + source_config['__type__']
59 del source_config['__type__'] # don't feed this to constructor!
60
61 # Default to global limit and max age. Source takes care of making
62 # integers and whatnot
63 source_config.setdefault('limit', global_limit)
64 source_config.setdefault('max_age', global_max_age)
65
66 # Hooks return a list of sources; combine with running list
67 sources += run_hooks(hook_name, config=config, **source_config)
68
69 # Save the list of sources, and done
70 config['spline-frontpage.sources'] = sources
71
72 def source_cron_hook(*args, **kwargs):
73 """Hook to pass on cron tics to all sources, should they need it for e.g.
74 caching.
75 """
76 for source in config['spline-frontpage.sources']:
77 source.do_cron(*args, **kwargs)
78
79 class FrontPagePlugin(PluginBase):
80 def controllers(self):
81 return dict(
82 frontpage = splinext.frontpage.controllers.frontpage.FrontPageController,
83 )
84
85 def template_dirs(self):
86 return [
87 (resource_filename(__name__, 'templates'), Priority.FIRST)
88 ]
89
90 def hooks(self):
91 return [
92 ('routes_mapping', Priority.NORMAL, add_routes_hook),
93 ('after_setup', Priority.NORMAL, load_sources_hook),
94 ('cron', Priority.NORMAL, source_cron_hook),
95 ('frontpage_updates_rss', Priority.NORMAL, FeedSource),
96 ('frontpage_updates_git', Priority.NORMAL, GitSource),
97 ]