+def forum_activity_score(forum):
+ """Returns a number representing how active a forum is, based on the past
+ week.
+
+ The calculation is arbitrary, but 0 is supposed to mean "dead" and 1 is
+ supposed to mean "healthy".
+ """
+ cutoff = datetime.datetime.now() - datetime.timedelta(days=7)
+
+ post_count = meta.Session.query(forum_model.Post) \
+ .join(forum_model.Post.thread) \
+ .filter(forum_model.Thread.forum == forum) \
+ .filter(forum_model.Post.posted_time >= cutoff) \
+ .count()
+
+ # Avoid domain errors!
+ if not post_count:
+ return 0.0
+
+ # The log is to scale 0 posts to 0.0, and 168 posts to 1.0.
+ # The square is really just to take the edge off the log curve; it
+ # accelerates to 1 very quickly, then slows considerably after that.
+ # Squaring helps both of these problems.
+ score = (math.log(post_count) / math.log(168)) ** 2
+
+ # TODO more threads and more new threads should boost the score slightly
+
+ return score
+
+def get_forum_activity():
+ """Returns a hash mapping forum ids to their level of 'activity'."""
+ forums_q = meta.Session.query(forum_model.Forum)
+
+ activity = {}
+ for forum in forums_q:
+ activity[forum.id] = forum_activity_score(forum)
+
+ return activity
+
+def get_forum_volume():
+ """Returns a hash mapping forum ids to the percentage of all posts that
+ reside in that forum.
+ """
+ # Do a complicated-ass subquery to get a list of forums and postcounts
+ volume_q = meta.Session.query(
+ forum_model.Forum.id.label('forum_id'),
+ func.count(forum_model.Post.id).label('post_count'),
+ ) \
+ .outerjoin(forum_model.Thread) \
+ .outerjoin(forum_model.Post) \
+ .group_by(forum_model.Forum.id)
+
+ # Stick this into a hash, and count the number of total posts
+ total_posts = 0
+ volume = {}
+ for forum_id, post_count in volume_q:
+ post_count = float(post_count or 0)
+ volume[forum_id] = post_count
+ total_posts += post_count
+
+ # Divide, to get a percentage
+ if total_posts:
+ for forum_id, post_count in volume.iteritems():
+ volume[forum_id] /= total_posts
+
+ return volume
+
+