comparison gpp/forums/views/subscriptions.py @ 301:ee451ad46af1

Fixing #140; limit topic notification emails to at most 1 per day, or more if the user visits the topic.
author Brian Neal <bgneal@gmail.com>
date Thu, 13 Jan 2011 03:27:42 +0000
parents a46788862737
children b2b37cdd020a
comparison
equal deleted inserted replaced
300:58e9b8b2965f 301:ee451ad46af1
1 """This module handles the subscriptions of users to forum topics.""" 1 """This module handles the subscriptions of users to forum topics."""
2 import datetime
3
2 from django.conf import settings 4 from django.conf import settings
3 from django.contrib.auth.decorators import login_required 5 from django.contrib.auth.decorators import login_required
4 from django.contrib.sites.models import Site 6 from django.contrib.sites.models import Site
5 from django.core.paginator import InvalidPage 7 from django.core.paginator import InvalidPage
6 from django.core.urlresolvers import reverse 8 from django.core.urlresolvers import reverse
10 from django.shortcuts import get_object_or_404 12 from django.shortcuts import get_object_or_404
11 from django.shortcuts import render_to_response 13 from django.shortcuts import render_to_response
12 from django.template import RequestContext 14 from django.template import RequestContext
13 from django.views.decorators.http import require_POST 15 from django.views.decorators.http import require_POST
14 16
15 from forums.models import Topic 17 from forums.models import Topic, TopicLastVisit, Subscription
16 from core.functions import send_mail 18 from core.functions import send_mail
17 from core.paginator import DiggPaginator 19 from core.paginator import DiggPaginator
18 20
19 21
22 # This constant is the minimum amount of time a user will be
23 # notified of new posts in a topic. Currently it is set to 1 day.
24 # Thus a user will be notified at most once per day of new posts.
25 TOPIC_NOTIFY_DELAY = datetime.timedelta(days=1)
26
27
20 def notify_topic_subscribers(post): 28 def notify_topic_subscribers(post):
21 """The argument post is a newly created post. Send out an email 29 """
22 notification to all subscribers of the post's parent Topic.""" 30 The argument post is a newly created post. Send out an email
31 notification to all subscribers of the post's parent Topic.
32 The emails are throttled such that unless the user visits the topic,
33 only 1 email will be sent per TOPIC_NOTIFY_DELAY period.
34 Visiting the topic will reset this delay.
35
36 """
37 #TODO: consider moving this function of the HTTP request/response cycle.
23 38
24 topic = post.topic 39 topic = post.topic
25 recipients = topic.subscribers.exclude( 40 subscriptions = Subscription.objects.filter(topic=post.topic).exclude(
26 id=post.user.id).values_list('email', flat=True) 41 user=post.user).select_related()
42
43 if not subscriptions:
44 return
45
46 subscriber_ids = [sub.user.id for sub in subscriptions]
47 tlvs = dict(TopicLastVisit.objects.filter(topic=topic,
48 user__in=subscriber_ids).values_list('user', 'last_visit'))
49
50 recipients = []
51 for sub in subscriptions:
52 if (sub.notify_date is None or
53 post.creation_date - sub.notify_date > TOPIC_NOTIFY_DELAY or
54 tlvs.get(sub.user.id, datetime.datetime.min) > sub.notify_date):
55
56 recipients.append(sub.user.email)
57 sub.notify_date = post.creation_date
58 sub.save()
27 59
28 if recipients: 60 if recipients:
29 site = Site.objects.get_current() 61 site = Site.objects.get_current()
30 subject = "[%s] Topic Reply: %s" % (site.name, topic.name) 62 subject = "[%s] Topic Reply: %s" % (site.name, topic.name)
31 url_prefix = "http://%s" % site.domain 63 url_prefix = "http://%s" % site.domain
46 @require_POST 78 @require_POST
47 def subscribe_topic(request, topic_id): 79 def subscribe_topic(request, topic_id):
48 """Subscribe the user to the requested topic.""" 80 """Subscribe the user to the requested topic."""
49 topic = get_object_or_404(Topic.objects.select_related(), id=topic_id) 81 topic = get_object_or_404(Topic.objects.select_related(), id=topic_id)
50 if topic.forum.category.can_access(request.user): 82 if topic.forum.category.can_access(request.user):
51 topic.subscribers.add(request.user) 83 sub = Subscription(topic=topic, user=request.user)
84 sub.save()
52 return HttpResponseRedirect( 85 return HttpResponseRedirect(
53 reverse("forums-subscription_status", args=[topic.id])) 86 reverse("forums-subscription_status", args=[topic.id]))
54 raise Http404 # TODO return HttpResponseForbidden instead 87 raise Http404 # TODO return HttpResponseForbidden instead
55 88
56 89
57 @login_required 90 @login_required
58 @require_POST 91 @require_POST
59 def unsubscribe_topic(request, topic_id): 92 def unsubscribe_topic(request, topic_id):
60 """Unsubscribe the user to the requested topic.""" 93 """Unsubscribe the user to the requested topic."""
61 topic = get_object_or_404(Topic, id=topic_id) 94 topic = get_object_or_404(Topic, id=topic_id)
62 topic.subscribers.remove(request.user) 95 try:
96 sub = Subscription.objects.get(topic=topic, user=request.user)
97 except Subscriptions.DoesNotExist:
98 pass
99 else:
100 sub.delete()
63 return HttpResponseRedirect( 101 return HttpResponseRedirect(
64 reverse("forums-subscription_status", args=[topic.id])) 102 reverse("forums-subscription_status", args=[topic.id]))
65 103
66 104
67 @login_required 105 @login_required