diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0d20b64
diff --git a/django/contrib/comments/views/moderation.py b/django/contrib/comments/views/moderation.py
index 3334b09..13e08ff 100644
a
|
b
|
def flag(request, comment_id, next=None):
|
34 | 34 | created = created, |
35 | 35 | request = request, |
36 | 36 | ) |
37 | | return next_redirect(request.POST.copy(), next, flag_done, c=comment.pk) |
| 37 | if request.POST.has_key('next'): |
| 38 | next = request.POST.get('next') |
| 39 | elif request.GET.has_key('next'): |
| 40 | next = request.GET.get('next') |
| 41 | return next_redirect(request.POST.copy(),next, flag_done, c=comment.pk) |
38 | 42 | |
39 | 43 | # Render a form on GET |
40 | 44 | else: |
| 45 | next = request.GET.get('next',next) |
41 | 46 | return render_to_response('comments/flag.html', |
42 | 47 | {'comment': comment, "next": next}, |
43 | 48 | template.RequestContext(request) |
… |
… |
def delete(request, comment_id, next=None):
|
74 | 79 | created = created, |
75 | 80 | request = request, |
76 | 81 | ) |
| 82 | if request.POST.has_key('next'): |
| 83 | next = request.POST.get('next') |
| 84 | elif request.GET.has_key('next'): |
| 85 | next = request.GET.get('next') |
77 | 86 | return next_redirect(request.POST.copy(), next, delete_done, c=comment.pk) |
78 | 87 | |
79 | 88 | # Render a form on GET |
80 | 89 | else: |
| 90 | next = request.GET.get('next',next) |
81 | 91 | return render_to_response('comments/delete.html', |
82 | 92 | {'comment': comment, "next": next}, |
83 | 93 | template.RequestContext(request) |
… |
… |
def approve(request, comment_id, next=None):
|
117 | 127 | created = created, |
118 | 128 | request = request, |
119 | 129 | ) |
| 130 | if request.POST.has_key('next'): |
| 131 | next = request.POST.get('next') |
| 132 | elif request.GET.has_key('next'): |
| 133 | next = request.GET.get('next') |
120 | 134 | return next_redirect(request.POST.copy(), next, approve_done, c=comment.pk) |
121 | 135 | |
122 | 136 | # Render a form on GET |
123 | 137 | else: |
| 138 | next = request.GET.get('next',next) |
124 | 139 | return render_to_response('comments/approve.html', |
125 | 140 | {'comment': comment, "next": next}, |
126 | 141 | template.RequestContext(request) |
diff --git a/docs/ref/contrib/comments/index.txt b/docs/ref/contrib/comments/index.txt
index f6e1553..4bfedcd 100644
a
|
b
|
Quick start guide
|
24 | 24 | |
25 | 25 | To get started using the ``comments`` app, follow these steps: |
26 | 26 | |
27 | | #. Install the comments framework by adding ``'django.contrib.comments'`` to |
| 27 | #. Install the comments framework by adding ``'django.contrib.comments'`` to |
28 | 28 | :setting:`INSTALLED_APPS`. |
29 | 29 | |
30 | 30 | #. Run ``manage.py syncdb`` so that Django will create the comment tables. |
31 | 31 | |
32 | 32 | #. Add the comment app's URLs to your project's ``urls.py``: |
33 | | |
| 33 | |
34 | 34 | .. code-block:: python |
35 | 35 | |
36 | 36 | urlpatterns = patterns('', |
… |
… |
To get started using the ``comments`` app, follow these steps:
|
41 | 41 | |
42 | 42 | #. Use the `comment template tags`_ below to embed comments in your |
43 | 43 | templates. |
44 | | |
| 44 | |
45 | 45 | You might also want to examine :ref:`ref-contrib-comments-settings`. |
46 | | |
| 46 | |
47 | 47 | Comment template tags |
48 | 48 | ===================== |
49 | 49 | |
… |
… |
different ways you can specify which object to attach to:
|
67 | 67 | #. Refer to the object directly -- the more common method. Most of the |
68 | 68 | time, you'll have some object in the template's context you want |
69 | 69 | to attach the comment to; you can simply use that object. |
70 | | |
71 | | For example, in a blog entry page that has a variable named ``entry``, |
| 70 | |
| 71 | For example, in a blog entry page that has a variable named ``entry``, |
72 | 72 | you could use the following to load the number of comments:: |
73 | | |
| 73 | |
74 | 74 | {% get_comment_count for entry as comment_count %}. |
75 | | |
| 75 | |
76 | 76 | #. Refer to the object by content-type and object id. You'd use this method |
77 | 77 | if you, for some reason, don't actually have direct access to the object. |
78 | | |
| 78 | |
79 | 79 | Following the above example, if you knew the object ID was ``14`` but |
80 | 80 | didn't have access to the actual object, you could do something like:: |
81 | | |
| 81 | |
82 | 82 | {% get_comment_count for blog.entry 14 as comment_count %} |
83 | | |
| 83 | |
84 | 84 | In the above, ``blog.entry`` is the app label and (lower-cased) model |
85 | 85 | name of the model class. |
86 | 86 | |
… |
… |
For example::
|
99 | 99 | {% for comment in comment_list %} |
100 | 100 | ... |
101 | 101 | {% endfor %} |
102 | | |
| 102 | |
103 | 103 | This returns a list of :class:`~django.contrib.comments.models.Comment` objects; |
104 | 104 | see :ref:`the comment model documentation <ref-contrib-comments-models>` for |
105 | 105 | details. |
… |
… |
To count comments attached to an object, use :ttag:`get_comment_count`::
|
116 | 116 | For example:: |
117 | 117 | |
118 | 118 | {% get_comment_count for event as comment_count %} |
119 | | |
| 119 | |
120 | 120 | <p>This event has {{ comment_count }} comments.</p> |
121 | | |
| 121 | |
122 | 122 | |
123 | 123 | Displaying the comment post form |
124 | 124 | -------------------------------- |
… |
… |
If you want more control over the look and feel of the comment form, you use use
|
153 | 153 | you can use in the template:: |
154 | 154 | |
155 | 155 | {% get_comment_form for [object] as [varname] %} |
156 | | |
| 156 | |
157 | 157 | A complete form might look like:: |
158 | 158 | |
159 | 159 | {% get_comment_form for event as form %} |
… |
… |
A complete form might look like::
|
164 | 164 | <td><input type="submit" name="preview" class="submit-post" value="Preview"></td> |
165 | 165 | </tr> |
166 | 166 | </form> |
167 | | |
| 167 | |
168 | 168 | Be sure to read the `notes on the comment form`_, below, for some special |
169 | 169 | considerations you'll need to make if you're using this approach. |
170 | 170 | |
… |
… |
Redirecting after the comment post
|
185 | 185 | |
186 | 186 | To specify the URL you want to redirect to after the comment has been posted, |
187 | 187 | you can include a hidden form input called ``next`` in your comment form. For example:: |
188 | | |
| 188 | |
189 | 189 | <input type="hidden" name="next" value="{% url my_comment_was_posted %}" /> |
190 | 190 | |
| 191 | The ``next`` parameter can be passed into the comment system in a variety of ways, |
| 192 | but POST will always be preferred over GET and the named parameter is always overridden. |
| 193 | |
| 194 | A ``next`` parameter can be specified in ``urls.py`` with the following line:: |
| 195 | |
| 196 | (r'^flag/(\d+)/$', flag, {'next': '/I/am/done/'}) |
| 197 | |
191 | 198 | .. _notes-on-the-comment-form: |
192 | 199 | |
193 | 200 | Notes on the comment form |
… |
… |
should know about:
|
198 | 205 | |
199 | 206 | * It contains a number of hidden fields that contain timestamps, information |
200 | 207 | about the object the comment should be attached to, and a "security hash" |
201 | | used to validate this information. If someone tampers with this data -- |
| 208 | used to validate this information. If someone tampers with this data -- |
202 | 209 | something comment spammers will try -- the comment submission will fail. |
203 | | |
| 210 | |
204 | 211 | If you're rendering a custom comment form, you'll need to make sure to |
205 | 212 | pass these values through unchanged. |
206 | | |
| 213 | |
207 | 214 | * The timestamp is used to ensure that "reply attacks" can't continue very |
208 | 215 | long. Users who wait too long between requesting the form and posting a |
209 | 216 | comment will have their submissions refused. |
210 | | |
| 217 | |
211 | 218 | * The comment form includes a "honeypot_" field. It's a trap: if any data is |
212 | 219 | entered in that field, the comment will be considered spam (spammers often |
213 | 220 | automatically fill in all fields in an attempt to make valid submissions). |
214 | | |
| 221 | |
215 | 222 | The default form hides this field with a piece of CSS and further labels |
216 | 223 | it with a warning field; if you use the comment form with a custom |
217 | 224 | template you should be sure to do the same. |
218 | | |
| 225 | |
219 | 226 | .. _honeypot: http://en.wikipedia.org/wiki/Honeypot_(computing) |
220 | 227 | |
221 | 228 | More information |
diff --git a/tests/regressiontests/comment_tests/tests/moderation_view_tests.py b/tests/regressiontests/comment_tests/tests/moderation_view_tests.py
index b9eadd7..c79c006 100644
a
|
b
|
from django.contrib.auth.models import User, Permission
|
3 | 3 | from django.contrib.contenttypes.models import ContentType |
4 | 4 | from regressiontests.comment_tests.tests import CommentTestCase |
5 | 5 | from django.contrib.comments import signals |
6 | | |
| 6 | from django.contrib.comments.views.moderation import delete |
| 7 | import re |
7 | 8 | class FlagViewTests(CommentTestCase): |
8 | 9 | |
9 | 10 | def testFlagGet(self): |
… |
… |
class DeleteViewTests(CommentTestCase):
|
92 | 93 | self.client.login(username="normaluser", password="normaluser") |
93 | 94 | response = self.client.post("/delete/%d/" % pk) |
94 | 95 | self.assertEqual(response["Location"], "http://testserver/deleted/?c=%d" % pk) |
| 96 | |
| 97 | response = self.client.post("/delete/%d/" % pk,{"next":"/somewhere/else/"}) |
| 98 | location = response["Location"] |
| 99 | match = re.search(r"^http://testserver/somewhere/else/\?c=\d+$", location) |
| 100 | self.failUnless(match != None, "Unexpected redirect location: %s" % location) |
95 | 101 | c = Comment.objects.get(pk=pk) |
96 | 102 | self.failUnless(c.is_removed) |
97 | 103 | self.assertEqual(c.flags.filter(flag=CommentFlag.MODERATOR_DELETION, user__username="normaluser").count(), 1) |
… |
… |
class DeleteViewTests(CommentTestCase):
|
106 | 112 | |
107 | 113 | # Post a comment and check the signals |
108 | 114 | self.testDeletePost() |
109 | | self.assertEqual(received_signals, [signals.comment_was_flagged]) |
| 115 | self.assertEqual(received_signals, [signals.comment_was_flagged,signals.comment_was_flagged]) |
110 | 116 | |
111 | 117 | def testDeletedView(self): |
112 | 118 | comments = self.createSomeComments() |
113 | 119 | pk = comments[0].pk |
114 | 120 | response = self.client.get("/deleted/", data={"c":pk}) |
115 | 121 | self.assertTemplateUsed(response, "comments/deleted.html") |
| 122 | |
| 123 | def testDeletedViewNextGet(self): |
| 124 | comments = self.createSomeComments() |
| 125 | pk = comments[0].pk |
| 126 | makeModerator("normaluser") |
| 127 | self.client.login(username="normaluser", password="normaluser") |
| 128 | response = self.client.get("/delete/%d/" % pk, data={"next":"/somewhere/else"}) |
| 129 | self.assertEqual(response.context[1]['next'],"/somewhere/else") |
| 130 | self.assertTemplateUsed(response, "comments/delete.html") |
| 131 | |
116 | 132 | |
117 | 133 | class ApproveViewTests(CommentTestCase): |
118 | 134 | |
diff --git a/tests/regressiontests/comment_tests/urls.py b/tests/regressiontests/comment_tests/urls.py
index 0058689..c183102 100644
a
|
b
|
urlpatterns = patterns('regressiontests.comment_tests.custom_comments.views',
|
5 | 5 | url(r'^flag/(\d+)/$', 'custom_flag_comment'), |
6 | 6 | url(r'^delete/(\d+)/$', 'custom_delete_comment'), |
7 | 7 | url(r'^approve/(\d+)/$', 'custom_approve_comment'), |
| 8 | |
8 | 9 | ) |
9 | | |