-
Notifications
You must be signed in to change notification settings - Fork 88
/
Copy pathviews.py
167 lines (140 loc) · 6.29 KB
/
views.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import models
from django.http import HttpResponse, HttpResponseBadRequest
from django.template.loader import render_to_string
from django.template import RequestContext
from django.contrib import comments
from django.contrib.comments import signals
from django.contrib.comments.views.comments import CommentPostBadRequest
from django.utils.html import escape
from django.views.decorators.csrf import csrf_protect
from django.views.decorators.http import require_POST
from fluent_comments import appsettings
import json
import sys
if sys.version_info[0] >= 3:
long = int
@csrf_protect
@require_POST
def post_comment_ajax(request, using=None):
"""
Post a comment, via an Ajax call.
"""
if not request.is_ajax():
return HttpResponseBadRequest("Expecting Ajax call")
# This is copied from django.contrib.comments.
# Basically that view does too much, and doesn't offer a hook to change the rendering.
# The request object is not passed to next_redirect for example.
#
# This is a separate view to integrate both features. Previously this used django-ajaxcomments
# which is unfortunately not thread-safe (it it changes the comment view per request).
# Fill out some initial data fields from an authenticated user, if present
data = request.POST.copy()
if request.user.is_authenticated():
if not data.get('name', ''):
data["name"] = request.user.get_full_name() or request.user.username
if not data.get('email', ''):
data["email"] = request.user.email
# Look up the object we're trying to comment about
ctype = data.get("content_type")
object_pk = data.get("object_pk")
if ctype is None or object_pk is None:
return CommentPostBadRequest("Missing content_type or object_pk field.")
try:
object_pk = long(object_pk)
model = models.get_model(*ctype.split(".", 1))
target = model._default_manager.using(using).get(pk=object_pk)
except ValueError:
return CommentPostBadRequest("Invalid object_pk value: {0}".format(escape(object_pk)))
except TypeError:
return CommentPostBadRequest("Invalid content_type value: {0}".format(escape(ctype)))
except AttributeError:
return CommentPostBadRequest("The given content-type {0} does not resolve to a valid model.".format(escape(ctype)))
except ObjectDoesNotExist:
return CommentPostBadRequest("No object matching content-type {0} and object PK {1} exists.".format(escape(ctype), escape(object_pk)))
except (ValueError, ValidationError) as e:
return CommentPostBadRequest("Attempting go get content-type {0!r} and object PK {1!r} exists raised {2}".format(escape(ctype), escape(object_pk), e.__class__.__name__))
# Do we want to preview the comment?
preview = "preview" in data
# Construct the comment form
form = comments.get_form()(target, data=data)
# Check security information
if form.security_errors():
return CommentPostBadRequest("The comment form failed security verification: {0}".format)
# If there are errors or if we requested a preview show the comment
if preview:
comment = form.get_comment_object() if not form.errors else None
return _ajax_result(request, form, "preview", comment, object_id=object_pk)
if form.errors:
return _ajax_result(request, form, "post", object_id=object_pk)
# Otherwise create the comment
comment = form.get_comment_object()
comment.ip_address = request.META.get("REMOTE_ADDR", None)
if request.user.is_authenticated():
comment.user = request.user
# Signal that the comment is about to be saved
responses = signals.comment_will_be_posted.send(
sender = comment.__class__,
comment = comment,
request = request
)
for (receiver, response) in responses:
if response is False:
return CommentPostBadRequest("comment_will_be_posted receiver {0} killed the comment".format(receiver.__name__))
# Save the comment and signal that it was saved
comment.save()
signals.comment_was_posted.send(
sender = comment.__class__,
comment = comment,
request = request
)
return _ajax_result(request, form, "post", comment, object_id=object_pk)
def _ajax_result(request, form, action, comment=None, object_id=None):
# Based on django-ajaxcomments, BSD licensed.
# Copyright (c) 2009 Brandon Konkle and individual contributors.
#
# This code was extracted out of django-ajaxcomments because
# django-ajaxcomments is not threadsafe, and it was refactored afterwards.
success = True
json_errors = {}
if form.errors:
for field_name in form.errors:
field = form[field_name]
json_errors[field_name] = _render_errors(field)
success = False
json_return = {
'success': success,
'action': action,
'errors': json_errors,
'object_id': object_id,
'use_threadedcomments': bool(appsettings.USE_THREADEDCOMMENTS),
'order_reversed': bool(appsettings.FLUENT_COMMENTS_ORDER_REVERSED),
}
if comment is not None:
context = {
'comment': comment,
'action': action,
'preview': (action == 'preview'),
'USE_THREADEDCOMMENTS': appsettings.USE_THREADEDCOMMENTS,
'ORDER_REVERSED': appsettings.FLUENT_COMMENTS_ORDER_REVERSED,
}
comment_html = render_to_string('comments/comment.html', context, context_instance=RequestContext(request))
json_return.update({
'html': comment_html,
'comment_id': comment.id,
'parent_id': None,
'is_moderated': not comment.is_public, # is_public flags changes in comment_will_be_posted
})
if appsettings.USE_THREADEDCOMMENTS:
json_return['parent_id'] = comment.parent_id
json_response = json.dumps(json_return)
return HttpResponse(json_response, content_type="application/json")
def _render_errors(field):
"""
Render form errors in crispy-forms style.
"""
template = '{0}/layout/field_errors.html'.format(appsettings.CRISPY_TEMPLATE_PACK)
return render_to_string(template, {
'field': field,
'form_show_errors': True,
})