annotate gpp/forums/views/subscriptions.py @ 329:000c006fee97

Various small changes to reduce database hits.
author Brian Neal <bgneal@gmail.com>
date Wed, 23 Feb 2011 03:40:18 +0000
parents ee451ad46af1
children b2b37cdd020a
rev   line source
bgneal@232 1 """This module handles the subscriptions of users to forum topics."""
bgneal@301 2 import datetime
bgneal@301 3
bgneal@232 4 from django.conf import settings
bgneal@232 5 from django.contrib.auth.decorators import login_required
bgneal@232 6 from django.contrib.sites.models import Site
bgneal@232 7 from django.core.paginator import InvalidPage
bgneal@232 8 from django.core.urlresolvers import reverse
bgneal@232 9 from django.http import HttpResponseRedirect
bgneal@232 10 from django.http import Http404
bgneal@232 11 from django.template.loader import render_to_string
bgneal@232 12 from django.shortcuts import get_object_or_404
bgneal@232 13 from django.shortcuts import render_to_response
bgneal@232 14 from django.template import RequestContext
bgneal@232 15 from django.views.decorators.http import require_POST
bgneal@232 16
bgneal@301 17 from forums.models import Topic, TopicLastVisit, Subscription
bgneal@232 18 from core.functions import send_mail
bgneal@232 19 from core.paginator import DiggPaginator
bgneal@232 20
bgneal@232 21
bgneal@301 22 # This constant is the minimum amount of time a user will be
bgneal@301 23 # notified of new posts in a topic. Currently it is set to 1 day.
bgneal@301 24 # Thus a user will be notified at most once per day of new posts.
bgneal@301 25 TOPIC_NOTIFY_DELAY = datetime.timedelta(days=1)
bgneal@301 26
bgneal@301 27
bgneal@232 28 def notify_topic_subscribers(post):
bgneal@301 29 """
bgneal@301 30 The argument post is a newly created post. Send out an email
bgneal@301 31 notification to all subscribers of the post's parent Topic.
bgneal@301 32 The emails are throttled such that unless the user visits the topic,
bgneal@301 33 only 1 email will be sent per TOPIC_NOTIFY_DELAY period.
bgneal@301 34 Visiting the topic will reset this delay.
bgneal@301 35
bgneal@301 36 """
bgneal@301 37 #TODO: consider moving this function of the HTTP request/response cycle.
bgneal@232 38
bgneal@232 39 topic = post.topic
bgneal@301 40 subscriptions = Subscription.objects.filter(topic=post.topic).exclude(
bgneal@301 41 user=post.user).select_related()
bgneal@301 42
bgneal@301 43 if not subscriptions:
bgneal@301 44 return
bgneal@301 45
bgneal@301 46 subscriber_ids = [sub.user.id for sub in subscriptions]
bgneal@301 47 tlvs = dict(TopicLastVisit.objects.filter(topic=topic,
bgneal@301 48 user__in=subscriber_ids).values_list('user', 'last_visit'))
bgneal@301 49
bgneal@301 50 recipients = []
bgneal@301 51 for sub in subscriptions:
bgneal@301 52 if (sub.notify_date is None or
bgneal@301 53 post.creation_date - sub.notify_date > TOPIC_NOTIFY_DELAY or
bgneal@301 54 tlvs.get(sub.user.id, datetime.datetime.min) > sub.notify_date):
bgneal@301 55
bgneal@301 56 recipients.append(sub.user.email)
bgneal@301 57 sub.notify_date = post.creation_date
bgneal@301 58 sub.save()
bgneal@232 59
bgneal@232 60 if recipients:
bgneal@232 61 site = Site.objects.get_current()
bgneal@232 62 subject = "[%s] Topic Reply: %s" % (site.name, topic.name)
bgneal@232 63 url_prefix = "http://%s" % site.domain
bgneal@232 64 post_url = url_prefix + post.get_absolute_url()
bgneal@232 65 unsubscribe_url = url_prefix + reverse("forums-manage_subscriptions")
bgneal@232 66 msg = render_to_string("forums/topic_notify_email.txt", {
bgneal@232 67 'poster': post.user.username,
bgneal@232 68 'topic_name': topic.name,
bgneal@232 69 'message': post.body,
bgneal@232 70 'post_url': post_url,
bgneal@232 71 'unsubscribe_url': unsubscribe_url,
bgneal@232 72 })
bgneal@232 73 for recipient in recipients:
bgneal@232 74 send_mail(subject, msg, settings.DEFAULT_FROM_EMAIL, [recipient])
bgneal@232 75
bgneal@232 76
bgneal@232 77 @login_required
bgneal@232 78 @require_POST
bgneal@232 79 def subscribe_topic(request, topic_id):
bgneal@232 80 """Subscribe the user to the requested topic."""
bgneal@232 81 topic = get_object_or_404(Topic.objects.select_related(), id=topic_id)
bgneal@232 82 if topic.forum.category.can_access(request.user):
bgneal@301 83 sub = Subscription(topic=topic, user=request.user)
bgneal@301 84 sub.save()
bgneal@232 85 return HttpResponseRedirect(
bgneal@232 86 reverse("forums-subscription_status", args=[topic.id]))
bgneal@232 87 raise Http404 # TODO return HttpResponseForbidden instead
bgneal@232 88
bgneal@232 89
bgneal@232 90 @login_required
bgneal@232 91 @require_POST
bgneal@232 92 def unsubscribe_topic(request, topic_id):
bgneal@232 93 """Unsubscribe the user to the requested topic."""
bgneal@232 94 topic = get_object_or_404(Topic, id=topic_id)
bgneal@301 95 try:
bgneal@301 96 sub = Subscription.objects.get(topic=topic, user=request.user)
bgneal@301 97 except Subscriptions.DoesNotExist:
bgneal@301 98 pass
bgneal@301 99 else:
bgneal@301 100 sub.delete()
bgneal@232 101 return HttpResponseRedirect(
bgneal@232 102 reverse("forums-subscription_status", args=[topic.id]))
bgneal@232 103
bgneal@232 104
bgneal@232 105 @login_required
bgneal@232 106 def subscription_status(request, topic_id):
bgneal@232 107 """Display the subscription status for the given topic."""
bgneal@232 108 topic = get_object_or_404(Topic.objects.select_related(), id=topic_id)
bgneal@232 109 is_subscribed = request.user in topic.subscribers.all()
bgneal@232 110 return render_to_response('forums/subscription_status.html', {
bgneal@232 111 'topic': topic,
bgneal@232 112 'is_subscribed': is_subscribed,
bgneal@232 113 },
bgneal@232 114 context_instance=RequestContext(request))
bgneal@232 115
bgneal@232 116
bgneal@232 117 @login_required
bgneal@232 118 def manage_subscriptions(request):
bgneal@232 119 """Display a user's topic subscriptions, and allow them to be deleted."""
bgneal@232 120
bgneal@232 121 user = request.user
bgneal@232 122 if request.method == "POST":
bgneal@232 123 if request.POST.get('delete_all'):
bgneal@232 124 user.subscriptions.clear()
bgneal@232 125 else:
bgneal@232 126 delete_ids = request.POST.getlist('delete_ids')
bgneal@232 127 try:
bgneal@232 128 delete_ids = [int(id) for id in delete_ids]
bgneal@232 129 except ValueError:
bgneal@232 130 raise Http404
bgneal@232 131 for topic in user.subscriptions.filter(id__in=delete_ids):
bgneal@232 132 user.subscriptions.remove(topic)
bgneal@232 133
bgneal@232 134 page_num = request.POST.get('page', 1)
bgneal@232 135 else:
bgneal@232 136 page_num = request.GET.get('page', 1)
bgneal@232 137
bgneal@232 138 topics = user.subscriptions.select_related().order_by('-update_date')
bgneal@232 139 paginator = DiggPaginator(topics, 20, body=5, tail=2, margin=3, padding=2)
bgneal@232 140 try:
bgneal@232 141 page_num = int(page_num)
bgneal@232 142 except ValueError:
bgneal@232 143 page_num = 1
bgneal@232 144 try:
bgneal@232 145 page = paginator.page(page_num)
bgneal@232 146 except InvalidPage:
bgneal@232 147 raise Http404
bgneal@232 148
bgneal@232 149 return render_to_response('forums/manage_topics.html', {
bgneal@232 150 'page_title': 'Topic Subscriptions',
bgneal@232 151 'description': 'The forum topics you are currently subscribed to are listed below.',
bgneal@232 152 'page': page,
bgneal@232 153 },
bgneal@232 154 context_instance=RequestContext(request))