|
0
|
1 |
from django import http |
|
|
2 |
from django.conf import settings |
|
|
3 |
from utils import next_redirect, confirmation_view |
|
29
|
4 |
from django.core.exceptions import ObjectDoesNotExist, ValidationError |
|
0
|
5 |
from django.db import models |
|
|
6 |
from django.shortcuts import render_to_response |
|
|
7 |
from django.template import RequestContext |
|
|
8 |
from django.template.loader import render_to_string |
|
|
9 |
from django.utils.html import escape |
|
|
10 |
from django.views.decorators.http import require_POST |
|
|
11 |
from django.contrib import comments |
|
|
12 |
from django.contrib.comments import signals |
|
29
|
13 |
from django.views.decorators.csrf import csrf_protect |
|
0
|
14 |
|
|
|
15 |
class CommentPostBadRequest(http.HttpResponseBadRequest): |
|
|
16 |
""" |
|
|
17 |
Response returned when a comment post is invalid. If ``DEBUG`` is on a |
|
|
18 |
nice-ish error message will be displayed (for debugging purposes), but in |
|
|
19 |
production mode a simple opaque 400 page will be displayed. |
|
|
20 |
""" |
|
|
21 |
def __init__(self, why): |
|
|
22 |
super(CommentPostBadRequest, self).__init__() |
|
|
23 |
if settings.DEBUG: |
|
|
24 |
self.content = render_to_string("comments/400-debug.html", {"why": why}) |
|
|
25 |
|
|
29
|
26 |
@csrf_protect |
|
|
27 |
@require_POST |
|
|
28 |
def post_comment(request, next=None, using=None): |
|
0
|
29 |
""" |
|
|
30 |
Post a comment. |
|
|
31 |
|
|
|
32 |
HTTP POST is required. If ``POST['submit'] == "preview"`` or if there are |
|
|
33 |
errors a preview template, ``comments/preview.html``, will be rendered. |
|
|
34 |
""" |
|
|
35 |
# Fill out some initial data fields from an authenticated user, if present |
|
|
36 |
data = request.POST.copy() |
|
|
37 |
if request.user.is_authenticated(): |
|
|
38 |
if not data.get('name', ''): |
|
|
39 |
data["name"] = request.user.get_full_name() or request.user.username |
|
|
40 |
if not data.get('email', ''): |
|
|
41 |
data["email"] = request.user.email |
|
|
42 |
|
|
|
43 |
# Check to see if the POST data overrides the view's next argument. |
|
|
44 |
next = data.get("next", next) |
|
|
45 |
|
|
|
46 |
# Look up the object we're trying to comment about |
|
|
47 |
ctype = data.get("content_type") |
|
|
48 |
object_pk = data.get("object_pk") |
|
|
49 |
if ctype is None or object_pk is None: |
|
|
50 |
return CommentPostBadRequest("Missing content_type or object_pk field.") |
|
|
51 |
try: |
|
|
52 |
model = models.get_model(*ctype.split(".", 1)) |
|
29
|
53 |
target = model._default_manager.using(using).get(pk=object_pk) |
|
0
|
54 |
except TypeError: |
|
|
55 |
return CommentPostBadRequest( |
|
|
56 |
"Invalid content_type value: %r" % escape(ctype)) |
|
|
57 |
except AttributeError: |
|
|
58 |
return CommentPostBadRequest( |
|
|
59 |
"The given content-type %r does not resolve to a valid model." % \ |
|
|
60 |
escape(ctype)) |
|
|
61 |
except ObjectDoesNotExist: |
|
|
62 |
return CommentPostBadRequest( |
|
|
63 |
"No object matching content-type %r and object PK %r exists." % \ |
|
|
64 |
(escape(ctype), escape(object_pk))) |
|
29
|
65 |
except (ValueError, ValidationError), e: |
|
|
66 |
return CommentPostBadRequest( |
|
|
67 |
"Attempting go get content-type %r and object PK %r exists raised %s" % \ |
|
|
68 |
(escape(ctype), escape(object_pk), e.__class__.__name__)) |
|
0
|
69 |
|
|
|
70 |
# Do we want to preview the comment? |
|
|
71 |
preview = "preview" in data |
|
|
72 |
|
|
|
73 |
# Construct the comment form |
|
|
74 |
form = comments.get_form()(target, data=data) |
|
|
75 |
|
|
|
76 |
# Check security information |
|
|
77 |
if form.security_errors(): |
|
|
78 |
return CommentPostBadRequest( |
|
|
79 |
"The comment form failed security verification: %s" % \ |
|
|
80 |
escape(str(form.security_errors()))) |
|
|
81 |
|
|
|
82 |
# If there are errors or if we requested a preview show the comment |
|
|
83 |
if form.errors or preview: |
|
|
84 |
template_list = [ |
|
29
|
85 |
# These first two exist for purely historical reasons. |
|
|
86 |
# Django v1.0 and v1.1 allowed the underscore format for |
|
|
87 |
# preview templates, so we have to preserve that format. |
|
|
88 |
"comments/%s_%s_preview.html" % (model._meta.app_label, model._meta.module_name), |
|
0
|
89 |
"comments/%s_preview.html" % model._meta.app_label, |
|
29
|
90 |
# Now the usual directory based template heirarchy. |
|
|
91 |
"comments/%s/%s/preview.html" % (model._meta.app_label, model._meta.module_name), |
|
|
92 |
"comments/%s/preview.html" % model._meta.app_label, |
|
0
|
93 |
"comments/preview.html", |
|
|
94 |
] |
|
|
95 |
return render_to_response( |
|
|
96 |
template_list, { |
|
|
97 |
"comment" : form.data.get("comment", ""), |
|
|
98 |
"form" : form, |
|
|
99 |
"next": next, |
|
|
100 |
}, |
|
|
101 |
RequestContext(request, {}) |
|
|
102 |
) |
|
|
103 |
|
|
|
104 |
# Otherwise create the comment |
|
|
105 |
comment = form.get_comment_object() |
|
|
106 |
comment.ip_address = request.META.get("REMOTE_ADDR", None) |
|
|
107 |
if request.user.is_authenticated(): |
|
|
108 |
comment.user = request.user |
|
|
109 |
|
|
|
110 |
# Signal that the comment is about to be saved |
|
|
111 |
responses = signals.comment_will_be_posted.send( |
|
|
112 |
sender = comment.__class__, |
|
|
113 |
comment = comment, |
|
|
114 |
request = request |
|
|
115 |
) |
|
|
116 |
|
|
|
117 |
for (receiver, response) in responses: |
|
|
118 |
if response == False: |
|
|
119 |
return CommentPostBadRequest( |
|
|
120 |
"comment_will_be_posted receiver %r killed the comment" % receiver.__name__) |
|
|
121 |
|
|
|
122 |
# Save the comment and signal that it was saved |
|
|
123 |
comment.save() |
|
|
124 |
signals.comment_was_posted.send( |
|
|
125 |
sender = comment.__class__, |
|
|
126 |
comment = comment, |
|
|
127 |
request = request |
|
|
128 |
) |
|
|
129 |
|
|
|
130 |
return next_redirect(data, next, comment_done, c=comment._get_pk_val()) |
|
|
131 |
|
|
|
132 |
comment_done = confirmation_view( |
|
|
133 |
template = "comments/posted.html", |
|
|
134 |
doc = """Display a "comment was posted" success page.""" |
|
|
135 |
) |
|
|
136 |
|