Show recent forum threads on the front page. Sucks, but.
[zzz-spline-forum.git] / splinext / forum / frontpage_sources.py
1 from collections import namedtuple
2 import datetime
3
4 from sqlalchemy.orm import contains_eager, joinedload
5 from sqlalchemy.sql import func
6 from pylons import tmpl_context as c, url
7
8 from spline.model import meta
9
10 from splinext.forum import model as forum_model
11 from splinext.frontpage.sources import Source
12
13 FrontPageThread = namedtuple('FrontPageThread', ['source', 'time', 'post'])
14 class ForumSource(Source):
15 """Represents a forum whose threads are put on the front page.
16
17 ``link``, ``title``, and ``icon`` are all optional; the link and title
18 default to the forum's thread list and name, and the icon defaults to a
19 newspaper.
20
21 Extra properties:
22
23 ``forum_id``
24 id of the forum to check for new threads.
25 """
26
27 template = '/forum/front_page.mako'
28
29 def __init__(self, forum_id, **kwargs):
30 forum = meta.Session.query(forum_model.Forum).get(forum_id)
31
32 # Link is tricky. Needs url(), which doesn't exist when this class is
33 # loaded. Lazy-load it in poll() below, instead
34 kwargs.setdefault('link', None)
35 kwargs.setdefault('title', forum.name)
36 kwargs.setdefault('icon', 'newspapers')
37 super(ForumSource, self).__init__(**kwargs)
38
39 self.forum_id = forum_id
40
41 def _poll(self, limit, max_age):
42 if not self.link:
43 self.link = url(
44 controller='forum', action='threads', forum_id=self.forum_id)
45
46 thread_q = meta.Session.query(forum_model.Thread) \
47 .filter_by(forum_id=self.forum_id) \
48 .join((forum_model.Post, forum_model.Thread.first_post)) \
49 .options(
50 contains_eager(forum_model.Thread.first_post, alias=forum_model.Post),
51 contains_eager(forum_model.Thread.first_post, forum_model.Post.thread, alias=forum_model.Thread),
52 joinedload(forum_model.Thread.first_post, forum_model.Post.author),
53 )
54
55 if max_age:
56 thread_q = thread_q.filter(forum_model.Post.posted_time >= max_age)
57
58 threads = thread_q \
59 .order_by(forum_model.Post.posted_time.desc()) \
60 [:limit]
61
62 updates = []
63 for thread in threads:
64 update = FrontPageThread(
65 source = self,
66 time = thread.first_post.posted_time,
67 post = thread.first_post,
68 )
69 updates.append(update)
70
71 return updates
72
73 FrontPageActivity = namedtuple('FrontPageActivity', ['template', 'threads'])
74 def forum_activity(*args, **kwargs):
75 """Show recently-active threads on the front page.
76
77 Note that this isn't the most recent X threads; it's threads that are more
78 recent than X, sorted by their activity since X.
79 """
80 # XXX this should be configurable probably
81 cutoff = datetime.datetime.now() - datetime.timedelta(days=7)
82
83 # TODO some sort of dropoff here idk
84 active_threads_subq = meta.Session.query(
85 forum_model.Post.thread_id.label('thread_id'),
86 func.count('*').label('ranking'),
87 ) \
88 .filter(forum_model.Post.posted_time >= cutoff) \
89 .group_by(forum_model.Post.thread_id) \
90 .subquery()
91
92 threads_q = meta.Session.query(forum_model.Thread) \
93 .join((active_threads_subq,
94 active_threads_subq.c.thread_id == forum_model.Thread.id)) \
95 .order_by(active_threads_subq.c.ranking.desc()) \
96 .limit(10)
97
98 return FrontPageActivity(
99 template='/forum/front_page_activity.mako',
100 threads=threads_q.all(),
101 )