Ticket #11625: 11625.3.diff
File 11625.3.diff, 16.2 KB (added by , 15 years ago) |
---|
-
django/contrib/comments/admin.py
diff --git a/django/contrib/comments/admin.py b/django/contrib/comments/admin.py index c2f8e56..861db4a 100644
a b from django.contrib import admin 2 2 from django.contrib.comments.models import Comment 3 3 from django.utils.translation import ugettext_lazy as _ 4 4 from django.contrib.comments import get_model 5 from django.contrib.comments.views.moderation import base_flag, base_approve, base_delete 5 6 6 7 class CommentsAdmin(admin.ModelAdmin): 7 8 fieldsets = ( … … class CommentsAdmin(admin.ModelAdmin): 22 23 ordering = ('-submit_date',) 23 24 raw_id_fields = ('user',) 24 25 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 31 # the DB. 32 if not request.user.is_superuser: 33 actions.pop('delete_selected') 34 if not request.user.has_perm('comments.can_moderate'): 35 actions.pop('approve_comments') 36 actions.pop('remove_comments') 37 return actions 38 39 def flag_comments(self, request, queryset): 40 for comment in queryset: 41 base_flag(request, comment) 42 self.message_user(request, "%s flagged." %self._get_message_bit(queryset.count())) 43 flag_comments.short_description = "Flag selected comments" 44 45 def approve_comments(self, request, queryset): 46 for comment in queryset: 47 base_approve(request, comment) 48 self.message_user(request, "%s approved." %self._get_message_bit(queryset.count())) 49 approve_comments.short_description = "Approve selected comments" 50 51 def remove_comments(self, request, queryset): 52 for comment in queryset: 53 base_delete(request, comment) 54 self.message_user(request, "%s removed." %self._get_message_bit(queryset.count())) 55 remove_comments.short_description = "Remove selected comments" 56 57 def _get_message_bit(self, rows_updated): 58 message_bit = '' 59 if rows_updated == 1: 60 message_bit += '1 comment was ' 61 else: 62 message_bit += '%s comments were ' %rows_updated 63 message_bit += 'successfully' 64 return message_bit 25 65 26 66 # Only register the default admin if the model is the built-in comment model 27 67 # (this won't be true if there's a custom comment app). -
deleted file django/contrib/comments/templates/comments/moderation_queue.html
diff --git a/django/contrib/comments/templates/comments/moderation_queue.html b/django/contrib/comments/templates/comments/moderation_queue.html deleted file mode 100644 index 73012b3..0000000
+ - 1 {% extends "admin/change_list.html" %}2 {% load adminmedia i18n %}3 4 {% block title %}{% trans "Comment moderation queue" %}{% endblock %}5 6 {% block extrahead %}7 {{ block.super }}8 <style type="text/css" media="screen">9 p#nocomments { font-size: 200%; text-align: center; border: 1px #ccc dashed; padding: 4em; }10 td.actions { width: 11em; }11 td.actions form { display: inline; }12 td.actions form input.submit { width: 5em; padding: 2px 4px; margin-right: 4px;}13 td.actions form input.approve { background: green; color: white; }14 td.actions form input.remove { background: red; color: white; }15 </style>16 {% endblock %}17 18 {% block branding %}19 <h1 id="site-name">{% trans "Comment moderation queue" %}</h1>20 {% endblock %}21 22 {% block breadcrumbs %}{% endblock %}23 24 {% block content %}25 {% if empty %}26 <p id="nocomments">{% trans "No comments to moderate" %}.</p>27 {% else %}28 <div id="content-main">29 <div class="module" id="changelist">30 <table cellspacing="0">31 <thead>32 <tr>33 <th>{% trans "Action" %}</th>34 <th>{% trans "Name" %}</th>35 <th>{% trans "Comment" %}</th>36 <th>{% trans "Email" %}</th>37 <th>{% trans "URL" %}</th>38 <th>{% trans "Authenticated?" %}</th>39 <th>{% trans "IP Address" %}</th>40 <th class="sorted desc">{% trans "Date posted" %}</th>41 </tr>42 </thead>43 <tbody>44 {% for comment in comments %}45 <tr class="{% cycle 'row1' 'row2' %}">46 <td class="actions">47 <form action="{% url comments-approve comment.pk %}" method="post">48 <input type="hidden" name="next" value="{% url comments-moderation-queue %}" />49 <input class="approve submit" type="submit" name="submit" value="{% trans "Approve" %}" />50 </form>51 <form action="{% url comments-delete comment.pk %}" method="post">52 <input type="hidden" name="next" value="{% url comments-moderation-queue %}" />53 <input class="remove submit" type="submit" name="submit" value="{% trans "Remove" %}" />54 </form>55 </td>56 <td>{{ comment.name }}</td>57 <td>{{ comment.comment|truncatewords:"50" }}</td>58 <td>{{ comment.email }}</td>59 <td>{{ comment.url }}</td>60 <td>61 <img62 src="{% admin_media_prefix %}img/admin/icon-{% if comment.user %}yes{% else %}no{% endif %}.gif"63 alt="{% if comment.user %}{% trans "yes" %}{% else %}{% trans "no" %}{% endif %}"64 />65 </td>66 <td>{{ comment.ip_address }}</td>67 <td>{{ comment.submit_date|date:"F j, P" }}</td>68 </tr>69 {% endfor %}70 </tbody>71 </table>72 </div>73 </div>74 {% endif %}75 {% endblock %} -
django/contrib/comments/urls.py
diff --git a/django/contrib/comments/urls.py b/django/contrib/comments/urls.py index 5caef9c..2bfefa3 100644
a b urlpatterns = patterns('django.contrib.comments.views', 7 7 url(r'^flagged/$', 'moderation.flag_done', name='comments-flag-done'), 8 8 url(r'^delete/(\d+)/$', 'moderation.delete', name='comments-delete'), 9 9 url(r'^deleted/$', 'moderation.delete_done', name='comments-delete-done'), 10 url(r'^moderate/$', 'moderation.moderation_queue', name='comments-moderation-queue'),11 10 url(r'^approve/(\d+)/$', 'moderation.approve', name='comments-approve'), 12 11 url(r'^approved/$', 'moderation.approve_done', name='comments-approve-done'), 13 12 ) -
django/contrib/comments/views/moderation.py
diff --git a/django/contrib/comments/views/moderation.py b/django/contrib/comments/views/moderation.py index 3334b09..965ee34 100644
a b from django.http import Http404 8 8 from django.contrib import comments 9 9 from django.contrib.comments import signals 10 10 11 def base_flag(request, comment): 12 flag, created = comments.models.CommentFlag.objects.get_or_create( 13 comment = comment, 14 user = request.user, 15 flag = comments.models.CommentFlag.SUGGEST_REMOVAL 16 ) 17 signals.comment_was_flagged.send( 18 sender = comment.__class__, 19 comment = comment, 20 flag = flag, 21 created = created, 22 request = request, 23 ) 24 11 25 #@login_required 12 26 def flag(request, comment_id, next=None): 13 27 """ … … def flag(request, comment_id, next=None): 22 36 23 37 # Flag on POST 24 38 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 ) 39 base_flag(request, comment) 37 40 return next_redirect(request.POST.copy(), next, flag_done, c=comment.pk) 38 41 39 42 # Render a form on GET … … def flag(request, comment_id, next=None): 44 47 ) 45 48 flag = login_required(flag) 46 49 50 def base_delete(request, comment): 51 flag, created = comments.models.CommentFlag.objects.get_or_create( 52 comment = comment, 53 user = request.user, 54 flag = comments.models.CommentFlag.MODERATOR_DELETION 55 ) 56 comment.is_removed = True 57 comment.save() 58 signals.comment_was_flagged.send( 59 sender = comment.__class__, 60 comment = comment, 61 flag = flag, 62 created = created, 63 request = request, 64 ) 65 47 66 #@permission_required("comments.delete_comment") 48 67 def delete(request, comment_id, next=None): 49 68 """ … … def delete(request, comment_id, next=None): 60 79 # Delete on POST 61 80 if request.method == 'POST': 62 81 # 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 ) 82 base_delete(request, comment) 77 83 return next_redirect(request.POST.copy(), next, delete_done, c=comment.pk) 78 84 79 85 # Render a form on GET … … def delete(request, comment_id, next=None): 84 90 ) 85 91 delete = permission_required("comments.can_moderate")(delete) 86 92 93 def base_approve(request, comment): 94 flag, created = comments.models.CommentFlag.objects.get_or_create( 95 comment = comment, 96 user = request.user, 97 flag = comments.models.CommentFlag.MODERATOR_APPROVAL, 98 ) 99 100 comment.is_removed = False 101 comment.is_public = True 102 comment.save() 103 104 signals.comment_was_flagged.send( 105 sender = comment.__class__, 106 comment = comment, 107 flag = flag, 108 created = created, 109 request = request, 110 ) 111 87 112 #@permission_required("comments.can_moderate") 88 113 def approve(request, comment_id, next=None): 89 114 """ … … def approve(request, comment_id, next=None): 100 125 # Delete on POST 101 126 if request.method == 'POST': 102 127 # 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 ) 128 base_approve(request, comment) 120 129 return next_redirect(request.POST.copy(), next, approve_done, c=comment.pk) 121 130 122 131 # Render a form on GET … … def approve(request, comment_id, next=None): 128 137 129 138 approve = permission_required("comments.can_moderate")(approve) 130 139 131 132 #@permission_required("comments.can_moderate")133 def moderation_queue(request):134 """135 Displays a list of unapproved comments to be approved.136 137 Templates: `comments/moderation_queue.html`138 Context:139 comments140 Comments to be approved (paginated).141 empty142 Is the comment list empty?143 is_paginated144 Is there more than one page?145 results_per_page146 Number of comments per page147 has_next148 Is there a next page?149 has_previous150 Is there a previous page?151 page152 The current page number153 next154 The next page number155 pages156 Number of pages157 hits158 Total number of comments159 page_range160 Range of page numbers161 162 """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 Http404170 171 try:172 comments_per_page = paginator.page(page)173 except InvalidPage:174 raise Http404175 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_range189 }, context_instance=template.RequestContext(request))190 191 moderation_queue = permission_required("comments.can_moderate")(moderation_queue)192 193 140 flag_done = confirmation_view( 194 141 template = "comments/flagged.html", 195 142 doc = 'Displays a "comment was flagged" success page.' -
tests/regressiontests/comment_tests/tests/moderation_view_tests.py
diff --git a/tests/regressiontests/comment_tests/tests/moderation_view_tests.py b/tests/regressiontests/comment_tests/tests/moderation_view_tests.py index b9eadd7..047317b 100644
a b class ApproveViewTests(CommentTestCase): 159 159 response = self.client.get("/approved/", data={"c":pk}) 160 160 self.assertTemplateUsed(response, "comments/approved.html") 161 161 162 def staff_status_for_user(username): 163 u = User.objects.get(username=username) 164 u.is_staff = True 165 comment_perms = Permission.objects.filter(codename__contains="comment") 166 for comment_perm in comment_perms: 167 if comment_perm.codename in ["add_comment", "change_comment", "delete_comment"]: 168 u.user_permissions.add(comment_perm) 169 u.save() 162 170 163 class ModerationQueueTests(CommentTestCase): 171 class AdminActionsTests(CommentTestCase): 172 urls = "regressiontests.comment_tests.urls_admin" 164 173 165 def testModerationQueuePermissions(self): 166 """Only moderators can view the moderation queue""" 174 def testActionsNonModerator(self): 175 comments = self.createSomeComments() 176 staff_status_for_user("normaluser") 167 177 self.client.login(username="normaluser", password="normaluser") 168 response = self.client.get("/moderate/") 169 self.assertEqual(response["Location"], "http://testserver/accounts/login/?next=/moderate/") 170 171 makeModerator("normaluser") 172 response = self.client.get("/moderate/") 173 self.assertEqual(response.status_code, 200) 178 response = self.client.get("/admin/comments/comment/") 179 self.assertEquals("approve_comments" in response.content, False) 174 180 175 def test ModerationQueueContents(self):176 """Moderation queue should display non-public, non-removed comments."""177 c1, c2, c3, c4 = self.createSomeComments()181 def testActionsModerator(self): 182 comments = self.createSomeComments() 183 staff_status_for_user("normaluser") 178 184 makeModerator("normaluser") 179 185 self.client.login(username="normaluser", password="normaluser") 180 181 c1.is_public = c2.is_public = False 182 c1.save(); c2.save() 183 response = self.client.get("/moderate/") 184 self.assertEqual(list(response.context[0]["comments"]), [c1, c2]) 185 186 c2.is_removed = True 187 c2.save() 188 response = self.client.get("/moderate/") 189 self.assertEqual(list(response.context[0]["comments"]), [c1]) 186 response = self.client.get("/admin/comments/comment/") 187 self.assertEquals("approve_comments" in response.content, True) -
new file tests/regressiontests/comment_tests/urls_admin.py
diff --git a/tests/regressiontests/comment_tests/urls_admin.py b/tests/regressiontests/comment_tests/urls_admin.py new file mode 100644 index 0000000..9e43d34
- + 1 from django.conf.urls.defaults import * 2 from django.contrib import admin 3 4 admin.autodiscover() 5 6 urlpatterns = patterns('', 7 (r'^admin/', include(admin.site.urls)), 8 )