view gpp/forums/unread.py @ 113:d97ceb95ce02

Forums: ForumLastVisit logic in place. Need to add code for topics and posts next.
author Brian Neal <bgneal@gmail.com>
date Sun, 11 Oct 2009 19:10:54 +0000
parents
children 535d02d1c017
line wrap: on
line source
"""
This file contains routines for implementing the "has unread" feature. 
Forums, topics, and posts are displayed with a visual indication if they have
been read or not.
"""
import datetime

from forums.models import ForumLastVisit, TopicLastVisit, Topic


THRESHOLD = datetime.timedelta(days=7)


def get_forum_unread_status(qs, user):
    if not user.is_authenticated():
        for forum in qs:
            forum.has_unread = False
        return

    now = datetime.datetime.now()
    min_date = now - THRESHOLD

    # retrieve ForumLastVisit records in one SQL query
    forum_ids = [forum.id for forum in qs]
    flvs = ForumLastVisit.objects.filter(user=user, 
            forum__in=forum_ids).select_related()
    flvs = dict([(flv.forum.id, flv) for flv in flvs])

    for forum in qs:
        # Edge case: forum has no posts
        if forum.last_post is None:
            forum.has_unread = False
            continue

        # Get the ForumLastVisit record
        if forum.id in flvs:
            flv = flvs[forum.id]
        else:
            # One doesn't exist, create a default one for next time,
            # mark it as having no unread topics, and bail.
            flv = ForumLastVisit(user=user, forum=forum)
            flv.begin_date = now
            flv.end_date = now
            flv.save()
            forum.has_unread = False
            continue

        # If the last visit record was too far in the past,
        # catch that user up and mark as no unreads.
        if now - flv.end_date > THRESHOLD:
            forum.catchup(user, flv)
            forum.has_unread = False
            continue

        # Check the easy cases first. Check the last_post in the
        # forum. If created after the end_date in our window, there
        # are new posts. Likewise, if before the begin_date in our window,
        # there are no new posts.
        if forum.last_post.creation_date > flv.end_date:
            forum.has_unread = True
        elif forum.last_post.creation_date < flv.begin_date:
            if not flv.is_caught_up():
                forum.catchup(user, flv)
            forum.has_unread = False
        else:
            # Going to have to examine the topics in our window.
            # First adjust our window if it is too old.
            if now - flv.begin_date > THRESHOLD:
                flv.begin_date = min_date
                flv.save()
                TopicLastVisit.objects.filter(user=user, topic__forum=forum,
                        last_visit__lt=min_date).delete()

            topics = Topic.objects.filter(creation_date__gt=flv.begin_date)
            tracked_topics = TopicLastVisit.objects.filter(user=user,
                    topic__forum=forum, last_visit__gt=flv.begin_date)

            # If the number of topics created since our window was started 
            # is greater than the tracked topic records, then there are new
            # posts.
            if topics.count() > tracked_topics.count():
                forum.has_unread = True
                continue

            tracked_dict = dict([(t.id, t) for t in tracked_topics])

            for topic in topics:
                if topic.id in tracked_dict:
                    if topic.update_date > tracked_dict[topic.id].last_visit:
                        forum.has_unread = True
                        continue
                else:
                    forum.has_unread = True
                    continue

            # If we made it through the above loop without continuing, then
            # we are all caught up.
            forum.catchup(user, flv)
            forum.has_unread = False