Code

Ticket #11625: 11625.diff

File 11625.diff, 7.4 KB (added by wayla, 5 years ago)

Added permission checks to action methods.

Line 
1diff --git a/django/contrib/comments/admin.py b/django/contrib/comments/admin.py
2index 3b1fb14..4ce2fca 100644
3--- a/django/contrib/comments/admin.py
4+++ b/django/contrib/comments/admin.py
5@@ -1,7 +1,8 @@
6 from django.contrib import admin
7-from django.contrib.comments.models import Comment
8+from django.contrib.comments.models import Comment, CommentFlag
9 from django.utils.translation import ugettext_lazy as _
10-from django.contrib.comments import get_model
11+from django.contrib.comments import get_model, signals
12+from django.core.exceptions import PermissionDenied
13 
14 class CommentsAdmin(admin.ModelAdmin):
15     fieldsets = (
16@@ -21,6 +22,72 @@ class CommentsAdmin(admin.ModelAdmin):
17     date_hierarchy = 'submit_date'
18     ordering = ('-submit_date',)
19     search_fields = ('comment', 'user__username', 'user_name', 'user_email', 'user_url', 'ip_address')
20+    actions = ['approve_selected', 'remove_selected']
21+
22+    def approve_selected(self, request, queryset):
23+        """ Approve comments through moderation. """
24+
25+        if not request.user.has_perm('comments.can_moderate')
26+            raise PermissionDenied
27+
28+        for comment in queryset:
29+            # Flag the comment as approved.
30+            flag, created = CommentFlag.objects.get_or_create(
31+                comment = comment,
32+                user    = request.user,
33+                flag    = CommentFlag.MODERATOR_APPROVAL
34+            )
35+
36+            comment.is_removed = False
37+            comment.is_public = True
38+            comment.save()
39+
40+            signals.comment_was_flagged.send(
41+                sender  = comment.__class__,
42+                comment = comment,
43+                flag    = flag,
44+                created = created,
45+                request = request
46+            )
47+       
48+        self.message_user(request, '%s successfully approved.' % self._get_message_bit(queryset.count()))
49+
50+    approve_selected.short_description = 'Approve selected comments'
51+
52+    def remove_selected(self, request, queryset):
53+        """ Remove comments through moderation. """
54+
55+        if not request.user.has_perm('comments.can_moderate')
56+            raise PermissionDenied
57+
58+        for comment in queryset:
59+            # Flag the comment as removed.
60+            flag, created = CommentFlag.objects.get_or_create(
61+                comment = comment,
62+                user    = request.user,
63+                flag    = CommentFlag.MODERATOR_DELETION
64+            )
65+
66+            comment.is_removed = True
67+            comment.save()
68+
69+            signals.comment_was_flagged.send(
70+                sender  = comment.__class__,
71+                comment = comment,
72+                flag    = flag,
73+                created = created,
74+                request = request
75+            )
76+
77+        self.message_user(request, '%s successfully removed.' % self._get_message_bit(queryset.count()))
78+   
79+    remove_selected.short_description = 'Remove selected comments'
80+
81+    def _get_message_bit(self, rows_updated):
82+        if rows_updated == 1:
83+            return '1 comment was'
84+        else:
85+            return '%s comments were' % rows_updated
86 
87 # Only register the default admin if the model is the built-in comment model
88 # (this won't be true if there's a custom comment app).
89diff --git a/tests/regressiontests/comment_tests/tests/__init__.py b/tests/regressiontests/comment_tests/tests/__init__.py
90index 449fea4..b2ead81 100644
91--- a/tests/regressiontests/comment_tests/tests/__init__.py
92+++ b/tests/regressiontests/comment_tests/tests/__init__.py
93@@ -87,3 +87,4 @@ from regressiontests.comment_tests.tests.templatetag_tests import *
94 from regressiontests.comment_tests.tests.comment_view_tests import *
95 from regressiontests.comment_tests.tests.moderation_view_tests import *
96 from regressiontests.comment_tests.tests.comment_utils_moderators_tests import *
97+from regressiontests.comment_tests.tests.admin_moderation_tests import *
98diff --git a/tests/regressiontests/comment_tests/tests/admin_moderation_tests.py b/tests/regressiontests/comment_tests/tests/admin_moderation_tests.py
99new file mode 100644
100index 0000000..3106dd1
101--- /dev/null
102+++ b/tests/regressiontests/comment_tests/tests/admin_moderation_tests.py
103@@ -0,0 +1,66 @@
104+from django.contrib.comments.models import Comment, CommentFlag
105+from regressiontests.comment_tests.tests import CommentTestCase
106+from django.contrib.comments import signals
107+from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME
108+
109+class AdminModerationTests(CommentTestCase):
110+    fixtures = ['comment_tests', 'admin-views-users.xml']
111+
112+    def setUp(self):
113+        self.client.login(username='super', password='secret')
114+
115+    def tearDown(self):
116+        self.client.logout()
117+
118+    def test_comment_admin_approve_action(self):
119+        "Tests the builtin aprove action defined as an admin method."
120+        c1, c2, c3, c4 = self.createSomeComments()
121+        c1.is_public = False
122+        c1.is_removed = True
123+        c1.save()
124+        action_data = {
125+            ACTION_CHECKBOX_NAME: [1],
126+            'action' : 'approve_selected',
127+            'index' : c1.pk,
128+        }
129+        response = self.client.post('/admin/comments/comment', action_data)
130+        c = Comment.objects.get(pk=c1.pk)
131+        self.assertTrue(c.is_public)
132+        self.assertFalse(c.is_removed)
133+        self.assertEqual(c.flags.filter(flag=CommentFlag.MODERATOR_APPROVAL, user__username="super").count(), 1)
134+
135+    def test_approve_action_signals(self):
136+        "Test signal is received upon aprove action."
137+        def receive(sender, **kwargs):
138+            received_signals.append(kwargs.get('signal'))
139+
140+        received_signals = []
141+        signals.comment_was_flagged.connect(receive)
142+
143+        self.test_comment_admin_approve_action()
144+        self.assertEqual(received_signals, [signals.comment_was_flagged])
145+   
146+    def test_comment_admin_remove_action(self):
147+        "Tests the builtin remove action defined as an admin method."
148+        c1, c2, c3, c4 = self.createSomeComments()
149+        action_data = {
150+            ACTION_CHECKBOX_NAME: [1],
151+            'action' : 'remove_selected',
152+            'index' : c1.pk,
153+        }
154+        response = self.client.post('/admin/comments/comment/', action_data)
155+        c = Comment.objects.get(pk=c1.pk)
156+        self.assertTrue(c.is_removed)
157+        self.assertEqual(c.flags.filter(flag=CommentFlag.MODERATOR_DELETION, user__username="super").count(), 1)
158+
159+    def test_remove_action_signals(self):
160+        "Test signal is received upon remove action."
161+        def receive(sender, **kwargs):
162+            received_signals.append(kwargs.get('signal'))
163+
164+        received_signals = []
165+        signals.comment_was_flagged.connect(receive)
166+
167+        self.test_comment_admin_remove_action()
168+        self.assertEqual(received_signals, [signals.comment_was_flagged])
169+
170diff --git a/tests/regressiontests/comment_tests/urls.py b/tests/regressiontests/comment_tests/urls.py
171index 0058689..76ca4b9 100644
172--- a/tests/regressiontests/comment_tests/urls.py
173+++ b/tests/regressiontests/comment_tests/urls.py
174@@ -1,4 +1,5 @@
175 from django.conf.urls.defaults import *
176+from django.contrib import admin
177 
178 urlpatterns = patterns('regressiontests.comment_tests.custom_comments.views',
179     url(r'^post/$',          'custom_submit_comment'),
180@@ -7,3 +8,7 @@ urlpatterns = patterns('regressiontests.comment_tests.custom_comments.views',
181     url(r'^approve/(\d+)/$', 'custom_approve_comment'),
182 )
183 
184+urlpatterns += patterns('',
185+    url(r'^admin/', include(admin.site.urls)),
186+)
187+