annotate gpp/forums/unread.py @ 143:1ed461fd2030

Podcast enhancements for #39. Provide channel level keyword support. Provide an alternate download URL so we can support both m4a and mp3 formats.
author Brian Neal <bgneal@gmail.com>
date Sun, 06 Dec 2009 21:28:31 +0000
parents 535d02d1c017
children 35a0e6345815
rev   line source
bgneal@113 1 """
bgneal@113 2 This file contains routines for implementing the "has unread" feature.
bgneal@113 3 Forums, topics, and posts are displayed with a visual indication if they have
bgneal@113 4 been read or not.
bgneal@113 5 """
bgneal@113 6 import datetime
bgneal@113 7
bgneal@113 8 from forums.models import ForumLastVisit, TopicLastVisit, Topic
bgneal@113 9
bgneal@113 10
bgneal@113 11 THRESHOLD = datetime.timedelta(days=7)
bgneal@113 12
bgneal@114 13 #######################################################################
bgneal@113 14
bgneal@113 15 def get_forum_unread_status(qs, user):
bgneal@113 16 if not user.is_authenticated():
bgneal@113 17 for forum in qs:
bgneal@113 18 forum.has_unread = False
bgneal@113 19 return
bgneal@113 20
bgneal@113 21 now = datetime.datetime.now()
bgneal@113 22 min_date = now - THRESHOLD
bgneal@113 23
bgneal@113 24 # retrieve ForumLastVisit records in one SQL query
bgneal@113 25 forum_ids = [forum.id for forum in qs]
bgneal@113 26 flvs = ForumLastVisit.objects.filter(user=user,
bgneal@113 27 forum__in=forum_ids).select_related()
bgneal@113 28 flvs = dict([(flv.forum.id, flv) for flv in flvs])
bgneal@113 29
bgneal@113 30 for forum in qs:
bgneal@113 31 # Edge case: forum has no posts
bgneal@113 32 if forum.last_post is None:
bgneal@113 33 forum.has_unread = False
bgneal@113 34 continue
bgneal@113 35
bgneal@113 36 # Get the ForumLastVisit record
bgneal@113 37 if forum.id in flvs:
bgneal@113 38 flv = flvs[forum.id]
bgneal@113 39 else:
bgneal@113 40 # One doesn't exist, create a default one for next time,
bgneal@113 41 # mark it as having no unread topics, and bail.
bgneal@113 42 flv = ForumLastVisit(user=user, forum=forum)
bgneal@113 43 flv.begin_date = now
bgneal@113 44 flv.end_date = now
bgneal@113 45 flv.save()
bgneal@113 46 forum.has_unread = False
bgneal@113 47 continue
bgneal@113 48
bgneal@113 49 # If the last visit record was too far in the past,
bgneal@113 50 # catch that user up and mark as no unreads.
bgneal@113 51 if now - flv.end_date > THRESHOLD:
bgneal@113 52 forum.catchup(user, flv)
bgneal@113 53 forum.has_unread = False
bgneal@113 54 continue
bgneal@113 55
bgneal@113 56 # Check the easy cases first. Check the last_post in the
bgneal@113 57 # forum. If created after the end_date in our window, there
bgneal@113 58 # are new posts. Likewise, if before the begin_date in our window,
bgneal@113 59 # there are no new posts.
bgneal@113 60 if forum.last_post.creation_date > flv.end_date:
bgneal@113 61 forum.has_unread = True
bgneal@113 62 elif forum.last_post.creation_date < flv.begin_date:
bgneal@113 63 if not flv.is_caught_up():
bgneal@113 64 forum.catchup(user, flv)
bgneal@113 65 forum.has_unread = False
bgneal@113 66 else:
bgneal@113 67 # Going to have to examine the topics in our window.
bgneal@113 68 # First adjust our window if it is too old.
bgneal@113 69 if now - flv.begin_date > THRESHOLD:
bgneal@113 70 flv.begin_date = min_date
bgneal@113 71 flv.save()
bgneal@113 72 TopicLastVisit.objects.filter(user=user, topic__forum=forum,
bgneal@113 73 last_visit__lt=min_date).delete()
bgneal@113 74
bgneal@113 75 topics = Topic.objects.filter(creation_date__gt=flv.begin_date)
bgneal@113 76 tracked_topics = TopicLastVisit.objects.filter(user=user,
bgneal@113 77 topic__forum=forum, last_visit__gt=flv.begin_date)
bgneal@113 78
bgneal@113 79 # If the number of topics created since our window was started
bgneal@113 80 # is greater than the tracked topic records, then there are new
bgneal@113 81 # posts.
bgneal@113 82 if topics.count() > tracked_topics.count():
bgneal@113 83 forum.has_unread = True
bgneal@113 84 continue
bgneal@113 85
bgneal@113 86 tracked_dict = dict([(t.id, t) for t in tracked_topics])
bgneal@113 87
bgneal@113 88 for topic in topics:
bgneal@113 89 if topic.id in tracked_dict:
bgneal@113 90 if topic.update_date > tracked_dict[topic.id].last_visit:
bgneal@113 91 forum.has_unread = True
bgneal@113 92 continue
bgneal@113 93 else:
bgneal@113 94 forum.has_unread = True
bgneal@113 95 continue
bgneal@113 96
bgneal@113 97 # If we made it through the above loop without continuing, then
bgneal@113 98 # we are all caught up.
bgneal@113 99 forum.catchup(user, flv)
bgneal@113 100 forum.has_unread = False
bgneal@114 101
bgneal@114 102 #######################################################################
bgneal@114 103
bgneal@114 104 def get_topic_unread_status(forum, topics, user):
bgneal@114 105
bgneal@114 106 # Edge case: no topics
bgneal@114 107 if forum.last_post is None:
bgneal@114 108 return
bgneal@114 109
bgneal@114 110 # This service isn't provided to unauthenticated users
bgneal@114 111 if not user.is_authenticated():
bgneal@114 112 for topic in topics:
bgneal@114 113 topic.has_unread = False
bgneal@114 114 return
bgneal@114 115
bgneal@114 116 now = datetime.datetime.now()
bgneal@114 117
bgneal@114 118 # Get the ForumLastVisit record
bgneal@114 119 try:
bgneal@114 120 flv = ForumLastVisit.objects.get(forum=forum, user=user)
bgneal@114 121 except ForumLastVisit.DoesNotExist:
bgneal@114 122 # One doesn't exist, create a default one for next time,
bgneal@114 123 # mark it as having no unread topics, and bail.
bgneal@114 124 flv = ForumLastVisit(user=user, forum=forum)
bgneal@114 125 flv.begin_date = now
bgneal@114 126 flv.end_date = now
bgneal@114 127 flv.save()
bgneal@114 128 for topic in topics:
bgneal@114 129 topic.has_unread = False
bgneal@114 130 return
bgneal@114 131
bgneal@114 132 # Are all the posts before our window? If so, all have been read.
bgneal@114 133 if forum.last_post.creation_date < flv.begin_date:
bgneal@114 134 for topic in topics:
bgneal@114 135 topic.has_unread = False
bgneal@114 136 return
bgneal@114 137
bgneal@114 138 topic_ids = [topic.id for topic in topics]
bgneal@114 139 tlvs = TopicLastVisit.objects.filter(user=user, topic__id__in=topic_ids)
bgneal@114 140 tlvs = dict([(tlv.topic.id, tlv) for tlv in tlvs])
bgneal@114 141
bgneal@114 142 # Otherwise we have to go through the topics one by one:
bgneal@114 143 for topic in topics:
bgneal@114 144 if topic.update_date < flv.begin_date:
bgneal@114 145 topic.has_unread = False
bgneal@114 146 elif topic.update_date > flv.end_date:
bgneal@114 147 topic.has_unread = True
bgneal@114 148 elif topic.id in tlvs:
bgneal@114 149 topic.has_unread = topic.update_date > tlvs[topic.id].last_visit
bgneal@114 150 else:
bgneal@114 151 topic.has_unread = True
bgneal@114 152
bgneal@114 153 #######################################################################
bgneal@114 154
bgneal@114 155 def get_post_unread_status(topic, posts, user):
bgneal@114 156 # This service isn't provided to unauthenticated users
bgneal@114 157 if not user.is_authenticated():
bgneal@114 158 for post in posts:
bgneal@114 159 post.unread = False
bgneal@114 160 return
bgneal@114 161
bgneal@114 162 # Get the ForumLastVisit record
bgneal@114 163 try:
bgneal@114 164 flv = ForumLastVisit.objects.get(forum=topic.forum, user=user)
bgneal@114 165 except ForumLastVisit.DoesNotExist:
bgneal@114 166 # One doesn't exist, all posts are old.
bgneal@114 167 for post in posts:
bgneal@114 168 post.unread = False
bgneal@114 169 return
bgneal@114 170
bgneal@114 171 # Are all the posts before our window? If so, all have been read.
bgneal@114 172 if topic.last_post.creation_date < flv.begin_date:
bgneal@114 173 for post in posts:
bgneal@114 174 post.unread = False
bgneal@114 175 return
bgneal@114 176
bgneal@114 177 # Do we have a topic last visit record for this topic?
bgneal@114 178
bgneal@114 179 try:
bgneal@114 180 tlv = TopicLastVisit.objects.get(user=user, topic=topic)
bgneal@114 181 except TopicLastVisit.DoesNotExist:
bgneal@114 182 # No we don't, we could be all caught up, or all are new
bgneal@114 183 for post in posts:
bgneal@114 184 post.unread = post.creation_date > flv.end_date
bgneal@114 185 else:
bgneal@114 186 for post in posts:
bgneal@114 187 post.unread = post.creation_date > tlv.last_visit