Code

Ticket #11625: 11625.3.diff

File 11625.3.diff, 16.2 KB (added by thejaswi_puthraya, 5 years ago)

git-patch against the latest checkout

Line 
1diff --git a/django/contrib/comments/admin.py b/django/contrib/comments/admin.py
2index c2f8e56..861db4a 100644
3--- a/django/contrib/comments/admin.py
4+++ b/django/contrib/comments/admin.py
5@@ -2,6 +2,7 @@ from django.contrib import admin
6 from django.contrib.comments.models import Comment
7 from django.utils.translation import ugettext_lazy as _
8 from django.contrib.comments import get_model
9+from django.contrib.comments.views.moderation import base_flag, base_approve, base_delete
10 
11 class CommentsAdmin(admin.ModelAdmin):
12     fieldsets = (
13@@ -22,6 +23,45 @@ class CommentsAdmin(admin.ModelAdmin):
14     ordering = ('-submit_date',)
15     raw_id_fields = ('user',)
16     search_fields = ('comment', 'user__username', 'user_name', 'user_email', 'user_url', 'ip_address')
17+    actions = ["flag_comments", "approve_comments", "remove_comments"]
18+
19+    def get_actions(self, request):
20+        actions = super(CommentsAdmin, self).get_actions(request)
21+        # Only superusers should be able to delete the comments from
22+        # the DB.
23+        if not request.user.is_superuser:
24+            actions.pop('delete_selected')
25+        if not request.user.has_perm('comments.can_moderate'):
26+            actions.pop('approve_comments')
27+            actions.pop('remove_comments')
28+        return actions
29+
30+    def flag_comments(self, request, queryset):
31+        for comment in queryset:
32+            base_flag(request, comment)
33+        self.message_user(request, "%s flagged." %self._get_message_bit(queryset.count()))
34+    flag_comments.short_description = "Flag selected comments"
35+
36+    def approve_comments(self, request, queryset):
37+        for comment in queryset:
38+            base_approve(request, comment)
39+        self.message_user(request, "%s approved." %self._get_message_bit(queryset.count()))
40+    approve_comments.short_description = "Approve selected comments"
41+
42+    def remove_comments(self, request, queryset):
43+        for comment in queryset:
44+            base_delete(request, comment)
45+        self.message_user(request, "%s removed." %self._get_message_bit(queryset.count()))
46+    remove_comments.short_description = "Remove selected comments"
47+
48+    def _get_message_bit(self, rows_updated):
49+        message_bit = ''
50+        if rows_updated == 1:
51+            message_bit += '1 comment was '
52+        else:
53+            message_bit += '%s comments were ' %rows_updated
54+        message_bit += 'successfully'
55+        return message_bit
56 
57 # Only register the default admin if the model is the built-in comment model
58 # (this won't be true if there's a custom comment app).
59diff --git a/django/contrib/comments/templates/comments/moderation_queue.html b/django/contrib/comments/templates/comments/moderation_queue.html
60deleted file mode 100644
61index 73012b3..0000000
62--- a/django/contrib/comments/templates/comments/moderation_queue.html
63+++ /dev/null
64@@ -1,75 +0,0 @@
65-{% extends "admin/change_list.html" %}
66-{% load adminmedia i18n %}
67-
68-{% block title %}{% trans "Comment moderation queue" %}{% endblock %}
69-
70-{% block extrahead %}
71-  {{ block.super }}
72-  <style type="text/css" media="screen">
73-    p#nocomments { font-size: 200%; text-align: center; border: 1px #ccc dashed; padding: 4em; }
74-    td.actions { width: 11em; }
75-    td.actions form { display: inline; }
76-    td.actions form input.submit { width: 5em; padding: 2px 4px; margin-right: 4px;}
77-    td.actions form input.approve { background: green; color: white; }
78-    td.actions form input.remove { background: red; color: white; }
79-  </style>
80-{% endblock %}
81-
82-{% block branding %}
83-<h1 id="site-name">{% trans "Comment moderation queue" %}</h1>
84-{% endblock %}
85-
86-{% block breadcrumbs %}{% endblock %}
87-
88-{% block content %}
89-{% if empty %}
90-<p id="nocomments">{% trans "No comments to moderate" %}.</p>
91-{% else %}
92-<div id="content-main">
93-  <div class="module" id="changelist">
94-    <table cellspacing="0">
95-      <thead>
96-        <tr>
97-          <th>{% trans "Action" %}</th>
98-          <th>{% trans "Name" %}</th>
99-          <th>{% trans "Comment" %}</th>
100-          <th>{% trans "Email" %}</th>
101-          <th>{% trans "URL" %}</th>
102-          <th>{% trans "Authenticated?" %}</th>
103-          <th>{% trans "IP Address" %}</th>
104-          <th class="sorted desc">{% trans "Date posted" %}</th>
105-        </tr>
106-    </thead>
107-    <tbody>
108-      {% for comment in comments %}
109-        <tr class="{% cycle 'row1' 'row2' %}">
110-          <td class="actions">
111-            <form action="{% url comments-approve comment.pk %}" method="post">
112-              <input type="hidden" name="next" value="{% url comments-moderation-queue %}" />
113-              <input class="approve submit" type="submit" name="submit" value="{% trans "Approve" %}" />
114-            </form>
115-            <form action="{% url comments-delete comment.pk %}" method="post">
116-              <input type="hidden" name="next" value="{% url comments-moderation-queue %}" />
117-              <input class="remove submit" type="submit" name="submit" value="{% trans "Remove" %}" />
118-            </form>
119-          </td>
120-          <td>{{ comment.name }}</td>
121-          <td>{{ comment.comment|truncatewords:"50" }}</td>
122-          <td>{{ comment.email }}</td>
123-          <td>{{ comment.url }}</td>
124-          <td>
125-            <img
126-              src="{% admin_media_prefix %}img/admin/icon-{% if comment.user %}yes{% else %}no{% endif %}.gif"
127-              alt="{% if comment.user %}{% trans "yes" %}{% else %}{% trans "no" %}{% endif %}"
128-            />
129-          </td>
130-          <td>{{ comment.ip_address }}</td>
131-          <td>{{ comment.submit_date|date:"F j, P" }}</td>
132-        </tr>
133-      {% endfor %}
134-    </tbody>
135-    </table>
136-  </div>
137-</div>
138-{% endif %}
139-{% endblock %}
140diff --git a/django/contrib/comments/urls.py b/django/contrib/comments/urls.py
141index 5caef9c..2bfefa3 100644
142--- a/django/contrib/comments/urls.py
143+++ b/django/contrib/comments/urls.py
144@@ -7,7 +7,6 @@ urlpatterns = patterns('django.contrib.comments.views',
145     url(r'^flagged/$',       'moderation.flag_done',        name='comments-flag-done'),
146     url(r'^delete/(\d+)/$',  'moderation.delete',           name='comments-delete'),
147     url(r'^deleted/$',       'moderation.delete_done',      name='comments-delete-done'),
148-    url(r'^moderate/$',      'moderation.moderation_queue', name='comments-moderation-queue'),
149     url(r'^approve/(\d+)/$', 'moderation.approve',          name='comments-approve'),
150     url(r'^approved/$',      'moderation.approve_done',     name='comments-approve-done'),
151 )
152diff --git a/django/contrib/comments/views/moderation.py b/django/contrib/comments/views/moderation.py
153index 3334b09..965ee34 100644
154--- a/django/contrib/comments/views/moderation.py
155+++ b/django/contrib/comments/views/moderation.py
156@@ -8,6 +8,20 @@ from django.http import Http404
157 from django.contrib import comments
158 from django.contrib.comments import signals
159 
160+def base_flag(request, comment):
161+    flag, created = comments.models.CommentFlag.objects.get_or_create(
162+        comment = comment,
163+        user    = request.user,
164+        flag    = comments.models.CommentFlag.SUGGEST_REMOVAL
165+        )
166+    signals.comment_was_flagged.send(
167+        sender  = comment.__class__,
168+        comment = comment,
169+        flag    = flag,
170+        created = created,
171+        request = request,
172+        )
173+
174 #@login_required
175 def flag(request, comment_id, next=None):
176     """
177@@ -22,18 +36,7 @@ def flag(request, comment_id, next=None):
178 
179     # Flag on POST
180     if request.method == 'POST':
181-        flag, created = comments.models.CommentFlag.objects.get_or_create(
182-            comment = comment,
183-            user    = request.user,
184-            flag    = comments.models.CommentFlag.SUGGEST_REMOVAL
185-        )
186-        signals.comment_was_flagged.send(
187-            sender  = comment.__class__,
188-            comment = comment,
189-            flag    = flag,
190-            created = created,
191-            request = request,
192-        )
193+        base_flag(request, comment)
194         return next_redirect(request.POST.copy(), next, flag_done, c=comment.pk)
195 
196     # Render a form on GET
197@@ -44,6 +47,22 @@ def flag(request, comment_id, next=None):
198         )
199 flag = login_required(flag)
200 
201+def base_delete(request, comment):
202+    flag, created = comments.models.CommentFlag.objects.get_or_create(
203+        comment = comment,
204+        user    = request.user,
205+        flag    = comments.models.CommentFlag.MODERATOR_DELETION
206+        )
207+    comment.is_removed = True
208+    comment.save()
209+    signals.comment_was_flagged.send(
210+        sender  = comment.__class__,
211+        comment = comment,
212+        flag    = flag,
213+        created = created,
214+        request = request,
215+        )
216+
217 #@permission_required("comments.delete_comment")
218 def delete(request, comment_id, next=None):
219     """
220@@ -60,20 +79,7 @@ def delete(request, comment_id, next=None):
221     # Delete on POST
222     if request.method == 'POST':
223         # Flag the comment as deleted instead of actually deleting it.
224-        flag, created = comments.models.CommentFlag.objects.get_or_create(
225-            comment = comment,
226-            user    = request.user,
227-            flag    = comments.models.CommentFlag.MODERATOR_DELETION
228-        )
229-        comment.is_removed = True
230-        comment.save()
231-        signals.comment_was_flagged.send(
232-            sender  = comment.__class__,
233-            comment = comment,
234-            flag    = flag,
235-            created = created,
236-            request = request,
237-        )
238+        base_delete(request, comment)
239         return next_redirect(request.POST.copy(), next, delete_done, c=comment.pk)
240 
241     # Render a form on GET
242@@ -84,6 +90,25 @@ def delete(request, comment_id, next=None):
243         )
244 delete = permission_required("comments.can_moderate")(delete)
245 
246+def base_approve(request, comment):
247+    flag, created = comments.models.CommentFlag.objects.get_or_create(
248+        comment = comment,
249+        user    = request.user,
250+        flag    = comments.models.CommentFlag.MODERATOR_APPROVAL,
251+        )
252+
253+    comment.is_removed = False
254+    comment.is_public = True
255+    comment.save()
256+
257+    signals.comment_was_flagged.send(
258+        sender  = comment.__class__,
259+        comment = comment,
260+        flag    = flag,
261+        created = created,
262+        request = request,
263+        )
264+   
265 #@permission_required("comments.can_moderate")
266 def approve(request, comment_id, next=None):
267     """
268@@ -100,23 +125,7 @@ def approve(request, comment_id, next=None):
269     # Delete on POST
270     if request.method == 'POST':
271         # Flag the comment as approved.
272-        flag, created = comments.models.CommentFlag.objects.get_or_create(
273-            comment = comment,
274-            user    = request.user,
275-            flag    = comments.models.CommentFlag.MODERATOR_APPROVAL,
276-        )
277-
278-        comment.is_removed = False
279-        comment.is_public = True
280-        comment.save()
281-
282-        signals.comment_was_flagged.send(
283-            sender  = comment.__class__,
284-            comment = comment,
285-            flag    = flag,
286-            created = created,
287-            request = request,
288-        )
289+        base_approve(request, comment)
290         return next_redirect(request.POST.copy(), next, approve_done, c=comment.pk)
291 
292     # Render a form on GET
293@@ -128,68 +137,6 @@ def approve(request, comment_id, next=None):
294 
295 approve = permission_required("comments.can_moderate")(approve)
296 
297-
298-#@permission_required("comments.can_moderate")
299-def moderation_queue(request):
300-    """
301-    Displays a list of unapproved comments to be approved.
302-
303-    Templates: `comments/moderation_queue.html`
304-    Context:
305-        comments
306-            Comments to be approved (paginated).
307-        empty
308-            Is the comment list empty?
309-        is_paginated
310-            Is there more than one page?
311-        results_per_page
312-            Number of comments per page
313-        has_next
314-            Is there a next page?
315-        has_previous
316-            Is there a previous page?
317-        page
318-            The current page number
319-        next
320-            The next page number
321-        pages
322-            Number of pages
323-        hits
324-            Total number of comments
325-        page_range
326-            Range of page numbers
327-
328-    """
329-    qs = comments.get_model().objects.filter(is_public=False, is_removed=False)
330-    paginator = Paginator(qs, 100)
331-
332-    try:
333-        page = int(request.GET.get("page", 1))
334-    except ValueError:
335-        raise Http404
336-
337-    try:
338-        comments_per_page = paginator.page(page)
339-    except InvalidPage:
340-        raise Http404
341-
342-    return render_to_response("comments/moderation_queue.html", {
343-        'comments' : comments_per_page.object_list,
344-        'empty' : page == 1 and paginator.count == 0,
345-        'is_paginated': paginator.num_pages > 1,
346-        'results_per_page': 100,
347-        'has_next': comments_per_page.has_next(),
348-        'has_previous': comments_per_page.has_previous(),
349-        'page': page,
350-        'next': page + 1,
351-        'previous': page - 1,
352-        'pages': paginator.num_pages,
353-        'hits' : paginator.count,
354-        'page_range' : paginator.page_range
355-    }, context_instance=template.RequestContext(request))
356-
357-moderation_queue = permission_required("comments.can_moderate")(moderation_queue)
358-
359 flag_done = confirmation_view(
360     template = "comments/flagged.html",
361     doc = 'Displays a "comment was flagged" success page.'
362diff --git a/tests/regressiontests/comment_tests/tests/moderation_view_tests.py b/tests/regressiontests/comment_tests/tests/moderation_view_tests.py
363index b9eadd7..047317b 100644
364--- a/tests/regressiontests/comment_tests/tests/moderation_view_tests.py
365+++ b/tests/regressiontests/comment_tests/tests/moderation_view_tests.py
366@@ -159,31 +159,29 @@ class ApproveViewTests(CommentTestCase):
367         response = self.client.get("/approved/", data={"c":pk})
368         self.assertTemplateUsed(response, "comments/approved.html")
369 
370+def staff_status_for_user(username):
371+    u = User.objects.get(username=username)
372+    u.is_staff = True
373+    comment_perms = Permission.objects.filter(codename__contains="comment")
374+    for comment_perm in comment_perms:
375+        if comment_perm.codename in ["add_comment", "change_comment", "delete_comment"]:
376+            u.user_permissions.add(comment_perm)
377+    u.save()
378 
379-class ModerationQueueTests(CommentTestCase):
380+class AdminActionsTests(CommentTestCase):
381+    urls = "regressiontests.comment_tests.urls_admin"
382 
383-    def testModerationQueuePermissions(self):
384-        """Only moderators can view the moderation queue"""
385+    def testActionsNonModerator(self):
386+        comments = self.createSomeComments()
387+        staff_status_for_user("normaluser")
388         self.client.login(username="normaluser", password="normaluser")
389-        response = self.client.get("/moderate/")
390-        self.assertEqual(response["Location"], "http://testserver/accounts/login/?next=/moderate/")
391-
392-        makeModerator("normaluser")
393-        response = self.client.get("/moderate/")
394-        self.assertEqual(response.status_code, 200)
395+        response = self.client.get("/admin/comments/comment/")
396+        self.assertEquals("approve_comments" in response.content, False)
397 
398-    def testModerationQueueContents(self):
399-        """Moderation queue should display non-public, non-removed comments."""
400-        c1, c2, c3, c4 = self.createSomeComments()
401+    def testActionsModerator(self):
402+        comments = self.createSomeComments()
403+        staff_status_for_user("normaluser")
404         makeModerator("normaluser")
405         self.client.login(username="normaluser", password="normaluser")
406-
407-        c1.is_public = c2.is_public = False
408-        c1.save(); c2.save()
409-        response = self.client.get("/moderate/")
410-        self.assertEqual(list(response.context[0]["comments"]), [c1, c2])
411-
412-        c2.is_removed = True
413-        c2.save()
414-        response = self.client.get("/moderate/")
415-        self.assertEqual(list(response.context[0]["comments"]), [c1])
416+        response = self.client.get("/admin/comments/comment/")
417+        self.assertEquals("approve_comments" in response.content, True)
418diff --git a/tests/regressiontests/comment_tests/urls_admin.py b/tests/regressiontests/comment_tests/urls_admin.py
419new file mode 100644
420index 0000000..9e43d34
421--- /dev/null
422+++ b/tests/regressiontests/comment_tests/urls_admin.py
423@@ -0,0 +1,8 @@
424+from django.conf.urls.defaults import *
425+from django.contrib import admin
426+
427+admin.autodiscover()
428+
429+urlpatterns = patterns('',
430+    (r'^admin/', include(admin.site.urls)),
431+)