Skip to content

Commit 8be1bb2

Browse files
committed
Fixed #11625: added comment moderation via admin actions.
This is BACKWARDS INCOMPATIBLE if you were using the completely undocumented moderation view from 1.1. That view's been removed in favor of the admin actions. Thanks, Thejaswi Puthraya. git-svn-id: http://code.djangoproject.com/svn/django/trunk@11639 bcc190cf-cafb-0310-a4f2-bffc1f526a37
1 parent 162fade commit 8be1bb2

File tree

6 files changed

+131
-211
lines changed

6 files changed

+131
-211
lines changed

django/contrib/comments/admin.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from django.contrib import admin
22
from django.contrib.comments.models import Comment
3-
from django.utils.translation import ugettext_lazy as _
3+
from django.utils.translation import ugettext_lazy as _, ungettext
44
from django.contrib.comments import get_model
5+
from django.contrib.comments.views.moderation import perform_flag, perform_approve, perform_delete
56

67
class CommentsAdmin(admin.ModelAdmin):
78
fieldsets = (
@@ -22,6 +23,44 @@ class CommentsAdmin(admin.ModelAdmin):
2223
ordering = ('-submit_date',)
2324
raw_id_fields = ('user',)
2425
search_fields = ('comment', 'user__username', 'user_name', 'user_email', 'user_url', 'ip_address')
26+
actions = ["flag_comments", "approve_comments", "remove_comments"]
27+
28+
def get_actions(self, request):
29+
actions = super(CommentsAdmin, self).get_actions(request)
30+
# Only superusers should be able to delete the comments from the DB.
31+
if not request.user.is_superuser:
32+
actions.pop('delete_selected')
33+
if not request.user.has_perm('comments.can_moderate'):
34+
actions.pop('approve_comments')
35+
actions.pop('remove_comments')
36+
return actions
37+
38+
def flag_comments(self, request, queryset):
39+
self._bulk_flag(request, queryset, perform_flag, _("flagged"))
40+
flag_comments.short_description = _("Flag selected comments")
41+
42+
def approve_comments(self, request, queryset):
43+
self._bulk_flag(request, queryset, perform_approve, _('approved'))
44+
approve_comments.short_description = _("Approve selected comments")
45+
46+
def remove_comments(self, request, queryset):
47+
self._bulk_flag(request, queryset, perform_delete, _('removed'))
48+
remove_comments.short_description = _("Remove selected comments")
49+
50+
def _bulk_flag(self, request, queryset, action, description):
51+
"""
52+
Flag, approve, or remove some comments from an admin action. Actually
53+
calls the `action` argument to perform the heavy lifting.
54+
"""
55+
n_comments = 0
56+
for comment in queryset:
57+
action(request, comment)
58+
n_comments += 1
59+
60+
msg = ungettext(u'1 comment was successfully %(action)s.',
61+
u'%(count)s comments were successfully %(action)s.',
62+
n_comments)
63+
self.message_user(request, msg % {'count': n_comments, 'action': description})
2564

2665
# Only register the default admin if the model is the built-in comment model
2766
# (this won't be true if there's a custom comment app).

django/contrib/comments/templates/comments/moderation_queue.html

Lines changed: 0 additions & 75 deletions
This file was deleted.

django/contrib/comments/urls.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
url(r'^flagged/$', 'moderation.flag_done', name='comments-flag-done'),
88
url(r'^delete/(\d+)/$', 'moderation.delete', name='comments-delete'),
99
url(r'^deleted/$', 'moderation.delete_done', name='comments-delete-done'),
10-
url(r'^moderate/$', 'moderation.moderation_queue', name='comments-moderation-queue'),
1110
url(r'^approve/(\d+)/$', 'moderation.approve', name='comments-approve'),
1211
url(r'^approved/$', 'moderation.approve_done', name='comments-approve-done'),
1312
)

django/contrib/comments/views/moderation.py

Lines changed: 61 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@
33
from django.shortcuts import get_object_or_404, render_to_response
44
from django.contrib.auth.decorators import login_required, permission_required
55
from utils import next_redirect, confirmation_view
6-
from django.core.paginator import Paginator, InvalidPage
7-
from django.http import Http404
86
from django.contrib import comments
97
from django.contrib.comments import signals
108

11-
#@login_required
9+
@login_required
1210
def flag(request, comment_id, next=None):
1311
"""
1412
Flags a comment. Confirmation on GET, action on POST.
@@ -22,18 +20,7 @@ def flag(request, comment_id, next=None):
2220

2321
# Flag on POST
2422
if request.method == 'POST':
25-
flag, created = comments.models.CommentFlag.objects.get_or_create(
26-
comment = comment,
27-
user = request.user,
28-
flag = comments.models.CommentFlag.SUGGEST_REMOVAL
29-
)
30-
signals.comment_was_flagged.send(
31-
sender = comment.__class__,
32-
comment = comment,
33-
flag = flag,
34-
created = created,
35-
request = request,
36-
)
23+
perform_flag(request, comment)
3724
return next_redirect(request.POST.copy(), next, flag_done, c=comment.pk)
3825

3926
# Render a form on GET
@@ -42,9 +29,8 @@ def flag(request, comment_id, next=None):
4229
{'comment': comment, "next": next},
4330
template.RequestContext(request)
4431
)
45-
flag = login_required(flag)
4632

47-
#@permission_required("comments.delete_comment")
33+
@permission_required("comments.can_moderate")
4834
def delete(request, comment_id, next=None):
4935
"""
5036
Deletes a comment. Confirmation on GET, action on POST. Requires the "can
@@ -60,20 +46,7 @@ def delete(request, comment_id, next=None):
6046
# Delete on POST
6147
if request.method == 'POST':
6248
# Flag the comment as deleted instead of actually deleting it.
63-
flag, created = comments.models.CommentFlag.objects.get_or_create(
64-
comment = comment,
65-
user = request.user,
66-
flag = comments.models.CommentFlag.MODERATOR_DELETION
67-
)
68-
comment.is_removed = True
69-
comment.save()
70-
signals.comment_was_flagged.send(
71-
sender = comment.__class__,
72-
comment = comment,
73-
flag = flag,
74-
created = created,
75-
request = request,
76-
)
49+
perform_delete(request, comment)
7750
return next_redirect(request.POST.copy(), next, delete_done, c=comment.pk)
7851

7952
# Render a form on GET
@@ -82,9 +55,8 @@ def delete(request, comment_id, next=None):
8255
{'comment': comment, "next": next},
8356
template.RequestContext(request)
8457
)
85-
delete = permission_required("comments.can_moderate")(delete)
8658

87-
#@permission_required("comments.can_moderate")
59+
@permission_required("comments.can_moderate")
8860
def approve(request, comment_id, next=None):
8961
"""
9062
Approve a comment (that is, mark it as public and non-removed). Confirmation
@@ -100,23 +72,7 @@ def approve(request, comment_id, next=None):
10072
# Delete on POST
10173
if request.method == 'POST':
10274
# Flag the comment as approved.
103-
flag, created = comments.models.CommentFlag.objects.get_or_create(
104-
comment = comment,
105-
user = request.user,
106-
flag = comments.models.CommentFlag.MODERATOR_APPROVAL,
107-
)
108-
109-
comment.is_removed = False
110-
comment.is_public = True
111-
comment.save()
112-
113-
signals.comment_was_flagged.send(
114-
sender = comment.__class__,
115-
comment = comment,
116-
flag = flag,
117-
created = created,
118-
request = request,
119-
)
75+
perform_approve(request, comment)
12076
return next_redirect(request.POST.copy(), next, approve_done, c=comment.pk)
12177

12278
# Render a form on GET
@@ -126,69 +82,64 @@ def approve(request, comment_id, next=None):
12682
template.RequestContext(request)
12783
)
12884

129-
approve = permission_required("comments.can_moderate")(approve)
130-
85+
# The following functions actually perform the various flag/aprove/delete
86+
# actions. They've been broken out into seperate functions to that they
87+
# may be called from admin actions.
13188

132-
#@permission_required("comments.can_moderate")
133-
def moderation_queue(request):
89+
def perform_flag(request, comment):
13490
"""
135-
Displays a list of unapproved comments to be approved.
136-
137-
Templates: `comments/moderation_queue.html`
138-
Context:
139-
comments
140-
Comments to be approved (paginated).
141-
empty
142-
Is the comment list empty?
143-
is_paginated
144-
Is there more than one page?
145-
results_per_page
146-
Number of comments per page
147-
has_next
148-
Is there a next page?
149-
has_previous
150-
Is there a previous page?
151-
page
152-
The current page number
153-
next
154-
The next page number
155-
pages
156-
Number of pages
157-
hits
158-
Total number of comments
159-
page_range
160-
Range of page numbers
161-
91+
Actually perform the flagging of a comment from a request.
16292
"""
163-
qs = comments.get_model().objects.filter(is_public=False, is_removed=False)
164-
paginator = Paginator(qs, 100)
165-
166-
try:
167-
page = int(request.GET.get("page", 1))
168-
except ValueError:
169-
raise Http404
170-
171-
try:
172-
comments_per_page = paginator.page(page)
173-
except InvalidPage:
174-
raise Http404
175-
176-
return render_to_response("comments/moderation_queue.html", {
177-
'comments' : comments_per_page.object_list,
178-
'empty' : page == 1 and paginator.count == 0,
179-
'is_paginated': paginator.num_pages > 1,
180-
'results_per_page': 100,
181-
'has_next': comments_per_page.has_next(),
182-
'has_previous': comments_per_page.has_previous(),
183-
'page': page,
184-
'next': page + 1,
185-
'previous': page - 1,
186-
'pages': paginator.num_pages,
187-
'hits' : paginator.count,
188-
'page_range' : paginator.page_range
189-
}, context_instance=template.RequestContext(request))
190-
191-
moderation_queue = permission_required("comments.can_moderate")(moderation_queue)
93+
flag, created = comments.models.CommentFlag.objects.get_or_create(
94+
comment = comment,
95+
user = request.user,
96+
flag = comments.models.CommentFlag.SUGGEST_REMOVAL
97+
)
98+
signals.comment_was_flagged.send(
99+
sender = comment.__class__,
100+
comment = comment,
101+
flag = flag,
102+
created = created,
103+
request = request,
104+
)
105+
106+
def perform_delete(request, comment):
107+
flag, created = comments.models.CommentFlag.objects.get_or_create(
108+
comment = comment,
109+
user = request.user,
110+
flag = comments.models.CommentFlag.MODERATOR_DELETION
111+
)
112+
comment.is_removed = True
113+
comment.save()
114+
signals.comment_was_flagged.send(
115+
sender = comment.__class__,
116+
comment = comment,
117+
flag = flag,
118+
created = created,
119+
request = request,
120+
)
121+
122+
123+
def perform_approve(request, comment):
124+
flag, created = comments.models.CommentFlag.objects.get_or_create(
125+
comment = comment,
126+
user = request.user,
127+
flag = comments.models.CommentFlag.MODERATOR_APPROVAL,
128+
)
129+
130+
comment.is_removed = False
131+
comment.is_public = True
132+
comment.save()
133+
134+
signals.comment_was_flagged.send(
135+
sender = comment.__class__,
136+
comment = comment,
137+
flag = flag,
138+
created = created,
139+
request = request,
140+
)
141+
142+
# Confirmation views.
192143

193144
flag_done = confirmation_view(
194145
template = "comments/flagged.html",

0 commit comments

Comments
 (0)