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
|