comments.py 5.2 KB

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