comparison gpp/forums/views/main.py @ 459:9d3bd7304050

Fixing #221. Also combined all permissions checks into a new module, permissions.py. This allows us to cache user, category, and forum groups information since it rarely changes.
author Brian Neal <bgneal@gmail.com>
date Sat, 02 Jul 2011 23:35:45 +0000
parents 72ef6e809f79
children 2ff5f4c1476d
comparison
equal deleted inserted replaced
458:9a4bffdf37c3 459:9d3bd7304050
19 from django.template import RequestContext 19 from django.template import RequestContext
20 from django.views.decorators.http import require_POST 20 from django.views.decorators.http import require_POST
21 from django.utils.text import wrap 21 from django.utils.text import wrap
22 from django.db.models import F 22 from django.db.models import F
23 23
24 import antispam
25 import antispam.utils
26 from bio.models import UserProfile, BadgeOwnership
24 from core.paginator import DiggPaginator 27 from core.paginator import DiggPaginator
25 from core.functions import email_admins 28 from core.functions import email_admins
26 from forums.models import Forum, Topic, Post, FlaggedPost, TopicLastVisit, \ 29
27 ForumLastVisit, Attachment 30 from forums.models import (Forum, Topic, Post, FlaggedPost, TopicLastVisit,
28 from forums.forms import NewTopicForm, NewPostForm, PostForm, MoveTopicForm, \ 31 ForumLastVisit, Attachment)
29 SplitTopicForm 32 from forums.forms import (NewTopicForm, NewPostForm, PostForm, MoveTopicForm,
30 from forums.unread import get_forum_unread_status, get_topic_unread_status, \ 33 SplitTopicForm)
31 get_post_unread_status, get_unread_topics 34 from forums.unread import (get_forum_unread_status, get_topic_unread_status,
32 35 get_post_unread_status, get_unread_topics)
33 from bio.models import UserProfile, BadgeOwnership 36
34 import antispam
35 import antispam.utils
36 from forums.attachments import AttachmentProcessor 37 from forums.attachments import AttachmentProcessor
38 import forums.permissions as perms
37 39
38 ####################################################################### 40 #######################################################################
39 41
40 TOPICS_PER_PAGE = 50 42 TOPICS_PER_PAGE = 50
41 POSTS_PER_PAGE = 20 43 POSTS_PER_PAGE = 20
115 """ 117 """
116 Displays all the topics in a forum. 118 Displays all the topics in a forum.
117 """ 119 """
118 forum = get_object_or_404(Forum.objects.select_related(), slug=slug) 120 forum = get_object_or_404(Forum.objects.select_related(), slug=slug)
119 121
120 if not forum.category.can_access(request.user): 122 if not perms.can_access(forum.category, request.user):
121 return HttpResponseForbidden() 123 return HttpResponseForbidden()
122 124
123 feed = None 125 feed = None
124 if not forum.category.groups.all(): 126 if not forum.category.groups.all():
125 feed = { 127 feed = {
139 attach_topic_page_ranges(page.object_list) 141 attach_topic_page_ranges(page.object_list)
140 142
141 # we do this for the template since it is rendered twice 143 # we do this for the template since it is rendered twice
142 page_nav = render_to_string('forums/pagination.html', {'page': page}) 144 page_nav = render_to_string('forums/pagination.html', {'page': page})
143 145
144 can_moderate = _can_moderate(forum, request.user) 146 can_moderate = perms.can_moderate(forum, request.user)
145 147
146 return render_to_response('forums/forum_index.html', { 148 return render_to_response('forums/forum_index.html', {
147 'forum': forum, 149 'forum': forum,
148 'feed': feed, 150 'feed': feed,
149 'page': page, 151 'page': page,
158 Displays all the posts in a topic. 160 Displays all the posts in a topic.
159 """ 161 """
160 topic = get_object_or_404(Topic.objects.select_related( 162 topic = get_object_or_404(Topic.objects.select_related(
161 'forum', 'forum__category', 'last_post'), pk=id) 163 'forum', 'forum__category', 'last_post'), pk=id)
162 164
163 if not topic.forum.category.can_access(request.user): 165 if not perms.can_access(topic.forum.category, request.user):
164 return HttpResponseForbidden() 166 return HttpResponseForbidden()
165 167
166 topic.view_count = F('view_count') + 1 168 topic.view_count = F('view_count') + 1
167 topic.save(force_update=True) 169 topic.save(force_update=True)
168 170
220 _update_last_visit(request.user, topic, visit_time) 222 _update_last_visit(request.user, topic, visit_time)
221 223
222 # we do this for the template since it is rendered twice 224 # we do this for the template since it is rendered twice
223 page_nav = render_to_string('forums/pagination.html', {'page': page}) 225 page_nav = render_to_string('forums/pagination.html', {'page': page})
224 226
225 can_moderate = _can_moderate(topic.forum, request.user) 227 can_moderate = perms.can_moderate(topic.forum, request.user)
226 228
227 can_reply = request.user.is_authenticated() and ( 229 can_reply = request.user.is_authenticated() and (
228 not topic.locked or can_moderate) 230 not topic.locked or can_moderate)
229 231
230 is_favorite = request.user.is_authenticated() and ( 232 is_favorite = request.user.is_authenticated() and (
287 """ 289 """
288 This view handles the creation of new topics. 290 This view handles the creation of new topics.
289 """ 291 """
290 forum = get_object_or_404(Forum.objects.select_related(), slug=slug) 292 forum = get_object_or_404(Forum.objects.select_related(), slug=slug)
291 293
292 if not forum.category.can_access(request.user): 294 if not perms.can_access(forum.category, request.user):
293 return HttpResponseForbidden() 295 return HttpResponseForbidden()
294 296
295 if request.method == 'POST': 297 if request.method == 'POST':
296 form = NewTopicForm(request.user, forum, request.POST) 298 form = NewTopicForm(request.user, forum, request.POST)
297 if form.is_valid(): 299 if form.is_valid():
336 if not request.user.is_authenticated(): 338 if not request.user.is_authenticated():
337 return HttpResponseForbidden('Please login or register to post.') 339 return HttpResponseForbidden('Please login or register to post.')
338 340
339 form = NewPostForm(request.POST) 341 form = NewPostForm(request.POST)
340 if form.is_valid(): 342 if form.is_valid():
341 if not _can_post_in_topic(form.topic, request.user): 343 if not perms.can_post(form.topic, request.user):
342 return HttpResponseForbidden("You don't have permission to post in this topic.") 344 return HttpResponseForbidden("You don't have permission to post in this topic.")
343 if antispam.utils.spam_check(request, form.cleaned_data['body']): 345 if antispam.utils.spam_check(request, form.cleaned_data['body']):
344 return HttpResponseForbidden(antispam.BUSTED_MESSAGE) 346 return HttpResponseForbidden(antispam.BUSTED_MESSAGE)
345 347
346 post = form.save(request.user, request.META.get("REMOTE_ADDR", "")) 348 post = form.save(request.user, request.META.get("REMOTE_ADDR", ""))
350 _bump_post_count(request.user) 352 _bump_post_count(request.user)
351 _update_last_visit(request.user, form.topic, datetime.datetime.now()) 353 _update_last_visit(request.user, form.topic, datetime.datetime.now())
352 354
353 return render_to_response('forums/display_post.html', { 355 return render_to_response('forums/display_post.html', {
354 'post': post, 356 'post': post,
355 'can_moderate': _can_moderate(form.topic.forum, request.user), 357 'can_moderate': perms.can_moderate(form.topic.forum, request.user),
356 'can_reply': True, 358 'can_reply': True,
357 }, 359 },
358 context_instance=RequestContext(request)) 360 context_instance=RequestContext(request))
359 361
360 return HttpResponseBadRequest("Oops, did you forget some text?"); 362 return HttpResponseBadRequest("Oops, did you forget some text?");
417 This view function allows authorized users to edit posts. 419 This view function allows authorized users to edit posts.
418 The superuser, forum moderators, and original author can edit posts. 420 The superuser, forum moderators, and original author can edit posts.
419 """ 421 """
420 post = get_object_or_404(Post.objects.select_related(), pk=id) 422 post = get_object_or_404(Post.objects.select_related(), pk=id)
421 423
422 can_moderate = _can_moderate(post.topic.forum, request.user) 424 can_moderate = perms.can_moderate(post.topic.forum, request.user)
423 can_edit = can_moderate or request.user == post.user 425 can_edit = can_moderate or request.user == post.user
424 426
425 if not can_edit: 427 if not can_edit:
426 return HttpResponseForbidden("You don't have permission to edit that post.") 428 return HttpResponseForbidden("You don't have permission to edit that post.")
427 429
576 """ 578 """
577 This function is the view for creating a normal, non-quick reply 579 This function is the view for creating a normal, non-quick reply
578 to a topic. 580 to a topic.
579 """ 581 """
580 topic = get_object_or_404(Topic.objects.select_related(), pk=topic_id) 582 topic = get_object_or_404(Topic.objects.select_related(), pk=topic_id)
581 can_post = _can_post_in_topic(topic, request.user) 583 can_post = perms.can_post(topic, request.user)
582 584
583 if can_post: 585 if can_post:
584 if request.method == 'POST': 586 if request.method == 'POST':
585 form = PostForm(request.POST) 587 form = PostForm(request.POST)
586 if form.is_valid(): 588 if form.is_valid():
623 def mod_topic_stick(request, id): 625 def mod_topic_stick(request, id):
624 """ 626 """
625 This view function is for moderators to toggle the sticky status of a topic. 627 This view function is for moderators to toggle the sticky status of a topic.
626 """ 628 """
627 topic = get_object_or_404(Topic.objects.select_related(), pk=id) 629 topic = get_object_or_404(Topic.objects.select_related(), pk=id)
628 if _can_moderate(topic.forum, request.user): 630 if perms.can_moderate(topic.forum, request.user):
629 topic.sticky = not topic.sticky 631 topic.sticky = not topic.sticky
630 topic.save() 632 topic.save()
631 return HttpResponseRedirect(topic.get_absolute_url()) 633 return HttpResponseRedirect(topic.get_absolute_url())
632 634
633 return HttpResponseForbidden() 635 return HttpResponseForbidden()
637 def mod_topic_lock(request, id): 639 def mod_topic_lock(request, id):
638 """ 640 """
639 This view function is for moderators to toggle the locked status of a topic. 641 This view function is for moderators to toggle the locked status of a topic.
640 """ 642 """
641 topic = get_object_or_404(Topic.objects.select_related(), pk=id) 643 topic = get_object_or_404(Topic.objects.select_related(), pk=id)
642 if _can_moderate(topic.forum, request.user): 644 if perms.can_moderate(topic.forum, request.user):
643 topic.locked = not topic.locked 645 topic.locked = not topic.locked
644 topic.save() 646 topic.save()
645 return HttpResponseRedirect(topic.get_absolute_url()) 647 return HttpResponseRedirect(topic.get_absolute_url())
646 648
647 return HttpResponseForbidden() 649 return HttpResponseForbidden()
651 def mod_topic_delete(request, id): 653 def mod_topic_delete(request, id):
652 """ 654 """
653 This view function is for moderators to delete an entire topic. 655 This view function is for moderators to delete an entire topic.
654 """ 656 """
655 topic = get_object_or_404(Topic.objects.select_related(), pk=id) 657 topic = get_object_or_404(Topic.objects.select_related(), pk=id)
656 if _can_moderate(topic.forum, request.user): 658 if perms.can_moderate(topic.forum, request.user):
657 forum_url = topic.forum.get_absolute_url() 659 forum_url = topic.forum.get_absolute_url()
658 _delete_topic(topic) 660 _delete_topic(topic)
659 return HttpResponseRedirect(forum_url) 661 return HttpResponseRedirect(forum_url)
660 662
661 return HttpResponseForbidden() 663 return HttpResponseForbidden()
665 def mod_topic_move(request, id): 667 def mod_topic_move(request, id):
666 """ 668 """
667 This view function is for moderators to move a topic to a different forum. 669 This view function is for moderators to move a topic to a different forum.
668 """ 670 """
669 topic = get_object_or_404(Topic.objects.select_related(), pk=id) 671 topic = get_object_or_404(Topic.objects.select_related(), pk=id)
670 if not _can_moderate(topic.forum, request.user): 672 if not perms.can_moderate(topic.forum, request.user):
671 return HttpResponseForbidden() 673 return HttpResponseForbidden()
672 674
673 if request.method == 'POST': 675 if request.method == 'POST':
674 form = MoveTopicForm(request.user, request.POST) 676 form = MoveTopicForm(request.user, request.POST)
675 if form.is_valid(): 677 if form.is_valid():
694 Displays a view to allow moderators to perform various operations 696 Displays a view to allow moderators to perform various operations
695 on topics in a forum in bulk. We currently support mass locking/unlocking, 697 on topics in a forum in bulk. We currently support mass locking/unlocking,
696 stickying and unstickying, moving, and deleting topics. 698 stickying and unstickying, moving, and deleting topics.
697 """ 699 """
698 forum = get_object_or_404(Forum.objects.select_related(), slug=slug) 700 forum = get_object_or_404(Forum.objects.select_related(), slug=slug)
699 if not _can_moderate(forum, request.user): 701 if not perms.can_moderate(forum, request.user):
700 return HttpResponseForbidden() 702 return HttpResponseForbidden()
701 703
702 topics = forum.topics.select_related('user', 'last_post', 'last_post__user') 704 topics = forum.topics.select_related('user', 'last_post', 'last_post__user')
703 paginator = create_topic_paginator(topics) 705 paginator = create_topic_paginator(topics)
704 page_num = get_page_num(request) 706 page_num = get_page_num(request)
768 """ 770 """
769 This view marks all the topics in the forum as being read. 771 This view marks all the topics in the forum as being read.
770 """ 772 """
771 forum = get_object_or_404(Forum.objects.select_related(), slug=slug) 773 forum = get_object_or_404(Forum.objects.select_related(), slug=slug)
772 774
773 if not forum.category.can_access(request.user): 775 if not perms.can_access(forum.category, request.user):
774 return HttpResponseForbidden() 776 return HttpResponseForbidden()
775 777
776 forum.catchup(request.user) 778 forum.catchup(request.user)
777 return HttpResponseRedirect(forum.get_absolute_url()) 779 return HttpResponseRedirect(forum.get_absolute_url())
778 780
781 def mod_topic_split(request, id): 783 def mod_topic_split(request, id):
782 """ 784 """
783 This view function allows moderators to split posts off to a new topic. 785 This view function allows moderators to split posts off to a new topic.
784 """ 786 """
785 topic = get_object_or_404(Topic.objects.select_related(), pk=id) 787 topic = get_object_or_404(Topic.objects.select_related(), pk=id)
786 if not _can_moderate(topic.forum, request.user): 788 if not perms.can_moderate(topic.forum, request.user):
787 return HttpResponseRedirect(topic.get_absolute_url()) 789 return HttpResponseRedirect(topic.get_absolute_url())
788 790
789 if request.method == "POST": 791 if request.method == "POST":
790 form = SplitTopicForm(request.user, request.POST) 792 form = SplitTopicForm(request.user, request.POST)
791 if form.is_valid(): 793 if form.is_valid():
928 @login_required 930 @login_required
929 def post_ip_info(request, post_id): 931 def post_ip_info(request, post_id):
930 """Displays information about the IP address the post was made from.""" 932 """Displays information about the IP address the post was made from."""
931 post = get_object_or_404(Post.objects.select_related(), pk=post_id) 933 post = get_object_or_404(Post.objects.select_related(), pk=post_id)
932 934
933 if not _can_moderate(post.topic.forum, request.user): 935 if not perms.can_moderate(post.topic.forum, request.user):
934 return HttpResponseForbidden("You don't have permission for this post.") 936 return HttpResponseForbidden("You don't have permission for this post.")
935 937
936 ip_users = sorted(set(Post.objects.filter( 938 ip_users = sorted(set(Post.objects.filter(
937 user_ip=post.user_ip).values_list('user__username', flat=True))) 939 user_ip=post.user_ip).values_list('user__username', flat=True)))
938 940
967 'title': page_title, 969 'title': page_title,
968 'page': page, 970 'page': page,
969 'page_nav': page_nav, 971 'page_nav': page_nav,
970 }, 972 },
971 context_instance=RequestContext(request)) 973 context_instance=RequestContext(request))
972
973
974 def _can_moderate(forum, user):
975 """
976 Determines if a user has permission to moderate a given forum.
977 """
978 return user.is_authenticated() and (
979 user.is_superuser or user in forum.moderators.all())
980
981
982 def _can_post_in_topic(topic, user):
983 """
984 This function returns true if the given user can post in the given topic
985 and false otherwise.
986 """
987 return (not topic.locked and topic.forum.category.can_access(user)) or \
988 (user.is_superuser or user in topic.forum.moderators.all())
989 974
990 975
991 def _bump_post_count(user): 976 def _bump_post_count(user):
992 """ 977 """
993 Increments the forum_post_count for the given user. 978 Increments the forum_post_count for the given user.