summaryrefslogtreecommitdiff
path: root/app/lib/django_comments/views
diff options
context:
space:
mode:
Diffstat (limited to 'app/lib/django_comments/views')
-rw-r--r--app/lib/django_comments/views/__init__.py0
-rw-r--r--app/lib/django_comments/views/comments.py142
-rw-r--r--app/lib/django_comments/views/moderation.py166
-rw-r--r--app/lib/django_comments/views/utils.py71
4 files changed, 379 insertions, 0 deletions
diff --git a/app/lib/django_comments/views/__init__.py b/app/lib/django_comments/views/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/app/lib/django_comments/views/__init__.py
diff --git a/app/lib/django_comments/views/comments.py b/app/lib/django_comments/views/comments.py
new file mode 100644
index 0000000..7c7f4df
--- /dev/null
+++ b/app/lib/django_comments/views/comments.py
@@ -0,0 +1,142 @@
+from __future__ import absolute_import
+
+from django import http
+from django.apps import apps
+from django.conf import settings
+from django.contrib.sites.shortcuts import get_current_site
+from django.core.exceptions import ObjectDoesNotExist, ValidationError
+from django.shortcuts import render
+from django.template.loader import render_to_string
+from django.utils.html import escape
+from django.views.decorators.csrf import csrf_protect, csrf_exempt
+from django.views.decorators.http import require_POST
+
+import django_comments
+from django_comments import signals
+from django_comments.views.utils import next_redirect, confirmation_view
+
+
+class CommentPostBadRequest(http.HttpResponseBadRequest):
+ """
+ Response returned when a comment post is invalid. If ``DEBUG`` is on a
+ nice-ish error message will be displayed (for debugging purposes), but in
+ production mode a simple opaque 400 page will be displayed.
+ """
+
+ def __init__(self, why):
+ super(CommentPostBadRequest, self).__init__()
+ if settings.DEBUG:
+ self.content = render_to_string("comments/400-debug.html", {"why": why})
+
+
+@csrf_exempt
+@require_POST
+def post_comment(request, next=None, using=None):
+ """
+ Post a comment.
+
+ HTTP POST is required. If ``POST['submit'] == "preview"`` or if there are
+ errors a preview template, ``comments/preview.html``, will be rendered.
+ """
+ # Fill out some initial data fields from an authenticated user, if present
+ data = request.POST.copy()
+ try:
+ user_is_authenticated = request.user.is_authenticated()
+ except TypeError: # Django >= 1.11
+ user_is_authenticated = request.user.is_authenticated
+ if user_is_authenticated:
+ if not data.get('name', ''):
+ data["name"] = request.user.get_full_name() or request.user.get_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:
+ model = apps.get_model(*ctype.split(".", 1))
+ target = model._default_manager.using(using).get(pk=object_pk)
+ except TypeError:
+ return CommentPostBadRequest(
+ "Invalid content_type value: %r" % escape(ctype))
+ except AttributeError:
+ return CommentPostBadRequest(
+ "The given content-type %r does not resolve to a valid model." % escape(ctype))
+ except ObjectDoesNotExist:
+ return CommentPostBadRequest(
+ "No object matching content-type %r and object PK %r exists." % (
+ escape(ctype), escape(object_pk)))
+ except (ValueError, ValidationError) as e:
+ return CommentPostBadRequest(
+ "Attempting go get content-type %r and object PK %r exists raised %s" % (
+ escape(ctype), escape(object_pk), e.__class__.__name__))
+
+ # Do we want to preview the comment?
+ preview = "preview" in data
+
+ # Construct the comment form
+ form = django_comments.get_form()(target, data=data)
+
+ # Check security information
+ if form.security_errors():
+ return CommentPostBadRequest(
+ "The comment form failed security verification: %s" % escape(str(form.security_errors())))
+
+ # If there are errors or if we requested a preview show the comment
+ if form.errors or preview:
+ template_list = [
+ # These first two exist for purely historical reasons.
+ # Django v1.0 and v1.1 allowed the underscore format for
+ # preview templates, so we have to preserve that format.
+ "comments/%s_%s_preview.html" % (model._meta.app_label, model._meta.model_name),
+ "comments/%s_preview.html" % model._meta.app_label,
+ # Now the usual directory based template hierarchy.
+ "comments/%s/%s/preview.html" % (model._meta.app_label, model._meta.model_name),
+ "comments/%s/preview.html" % model._meta.app_label,
+ "comments/preview.html",
+ ]
+ return render(request, template_list, {
+ "comment": form.data.get("comment", ""),
+ "form": form,
+ "next": data.get("next", next),
+ },
+ )
+
+ # Otherwise create the comment
+ comment = form.get_comment_object(site_id=get_current_site(request).id)
+ comment.ip_address = request.META.get("REMOTE_ADDR", None) or None
+ if 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 %r killed the comment" % receiver.__name__)
+
+ # Save the comment and signal that it was saved
+ print(comment.user_name)
+ if comment.user_name != 'HenryLom':
+ comment.save()
+ signals.comment_was_posted.send(
+ sender=comment.__class__,
+ comment=comment,
+ request=request
+ )
+
+ return next_redirect(request, fallback=next or 'comments-comment-done',
+ c=comment._get_pk_val())
+
+
+comment_done = confirmation_view(
+ template="comments/posted.html",
+ doc="""Display a "comment was posted" success page."""
+)
diff --git a/app/lib/django_comments/views/moderation.py b/app/lib/django_comments/views/moderation.py
new file mode 100644
index 0000000..04c665f
--- /dev/null
+++ b/app/lib/django_comments/views/moderation.py
@@ -0,0 +1,166 @@
+from __future__ import absolute_import
+
+from django.contrib.auth.decorators import login_required, permission_required
+from django.contrib.sites.shortcuts import get_current_site
+from django.shortcuts import get_object_or_404, render
+from django.views.decorators.csrf import csrf_protect
+
+import django_comments
+from django_comments import signals
+from django_comments.views.utils import next_redirect, confirmation_view
+
+
+@csrf_protect
+@login_required
+def flag(request, comment_id, next=None):
+ """
+ Flags a comment. Confirmation on GET, action on POST.
+
+ Templates: :template:`comments/flag.html`,
+ Context:
+ comment
+ the flagged `comments.comment` object
+ """
+ comment = get_object_or_404(django_comments.get_model(),
+ pk=comment_id,
+ site__pk=get_current_site(request).pk)
+
+ # Flag on POST
+ if request.method == 'POST':
+ perform_flag(request, comment)
+ return next_redirect(request, fallback=next or 'comments-flag-done',
+ c=comment.pk)
+
+ # Render a form on GET
+ else:
+ return render(request, 'comments/flag.html', {'comment': comment, "next": next})
+
+
+@csrf_protect
+@permission_required("django_comments.can_moderate")
+def delete(request, comment_id, next=None):
+ """
+ Deletes a comment. Confirmation on GET, action on POST. Requires the "can
+ moderate comments" permission.
+
+ Templates: :template:`comments/delete.html`,
+ Context:
+ comment
+ the flagged `comments.comment` object
+ """
+ comment = get_object_or_404(django_comments.get_model(),
+ pk=comment_id,
+ site__pk=get_current_site(request).pk)
+
+ # Delete on POST
+ if request.method == 'POST':
+ # Flag the comment as deleted instead of actually deleting it.
+ perform_delete(request, comment)
+ return next_redirect(request, fallback=next or 'comments-delete-done',
+ c=comment.pk)
+
+ # Render a form on GET
+ else:
+ return render(request, 'comments/delete.html', {'comment': comment, "next": next})
+
+
+@csrf_protect
+@permission_required("django_comments.can_moderate")
+def approve(request, comment_id, next=None):
+ """
+ Approve a comment (that is, mark it as public and non-removed). Confirmation
+ on GET, action on POST. Requires the "can moderate comments" permission.
+
+ Templates: :template:`comments/approve.html`,
+ Context:
+ comment
+ the `comments.comment` object for approval
+ """
+ comment = get_object_or_404(django_comments.get_model(),
+ pk=comment_id,
+ site__pk=get_current_site(request).pk)
+
+ # Delete on POST
+ if request.method == 'POST':
+ # Flag the comment as approved.
+ perform_approve(request, comment)
+ return next_redirect(request, fallback=next or 'comments-approve-done',
+ c=comment.pk)
+
+ # Render a form on GET
+ else:
+ return render(request, 'comments/approve.html', {'comment': comment, "next": next})
+
+
+# The following functions actually perform the various flag/aprove/delete
+# actions. They've been broken out into separate functions to that they
+# may be called from admin actions.
+
+def perform_flag(request, comment):
+ """
+ Actually perform the flagging of a comment from a request.
+ """
+ flag, created = django_comments.models.CommentFlag.objects.get_or_create(
+ comment=comment,
+ user=request.user,
+ flag=django_comments.models.CommentFlag.SUGGEST_REMOVAL
+ )
+ signals.comment_was_flagged.send(
+ sender=comment.__class__,
+ comment=comment,
+ flag=flag,
+ created=created,
+ request=request,
+ )
+
+
+def perform_delete(request, comment):
+ flag, created = django_comments.models.CommentFlag.objects.get_or_create(
+ comment=comment,
+ user=request.user,
+ flag=django_comments.models.CommentFlag.MODERATOR_DELETION
+ )
+ comment.is_removed = True
+ comment.save()
+ signals.comment_was_flagged.send(
+ sender=comment.__class__,
+ comment=comment,
+ flag=flag,
+ created=created,
+ request=request,
+ )
+
+
+def perform_approve(request, comment):
+ flag, created = django_comments.models.CommentFlag.objects.get_or_create(
+ comment=comment,
+ user=request.user,
+ flag=django_comments.models.CommentFlag.MODERATOR_APPROVAL,
+ )
+
+ comment.is_removed = False
+ comment.is_public = True
+ comment.save()
+
+ signals.comment_was_flagged.send(
+ sender=comment.__class__,
+ comment=comment,
+ flag=flag,
+ created=created,
+ request=request,
+ )
+
+# Confirmation views.
+
+flag_done = confirmation_view(
+ template="comments/flagged.html",
+ doc='Displays a "comment was flagged" success page.'
+)
+delete_done = confirmation_view(
+ template="comments/deleted.html",
+ doc='Displays a "comment was deleted" success page.'
+)
+approve_done = confirmation_view(
+ template="comments/approved.html",
+ doc='Displays a "comment was approved" success page.'
+)
diff --git a/app/lib/django_comments/views/utils.py b/app/lib/django_comments/views/utils.py
new file mode 100644
index 0000000..a5f5c11
--- /dev/null
+++ b/app/lib/django_comments/views/utils.py
@@ -0,0 +1,71 @@
+"""
+A few bits of helper functions for comment views.
+"""
+
+import textwrap
+
+try:
+ from urllib.parse import urlencode
+except ImportError: # Python 2
+ from urllib import urlencode
+
+from django.http import HttpResponseRedirect
+from django.shortcuts import render, resolve_url
+from django.core.exceptions import ObjectDoesNotExist
+from django.utils.http import is_safe_url
+
+import django_comments
+
+
+def next_redirect(request, fallback, **get_kwargs):
+ """
+ Handle the "where should I go next?" part of comment views.
+
+ The next value could be a
+ ``?next=...`` GET arg or the URL of a given view (``fallback``). See
+ the view modules for examples.
+
+ Returns an ``HttpResponseRedirect``.
+ """
+ next = request.POST.get('next')
+ if not is_safe_url(url=next, allowed_hosts={request.get_host()}):
+ next = resolve_url(fallback)
+
+ if get_kwargs:
+ if '#' in next:
+ tmp = next.rsplit('#', 1)
+ next = tmp[0]
+ anchor = '#' + tmp[1]
+ else:
+ anchor = ''
+
+ joiner = ('?' in next) and '&' or '?'
+ next += joiner + urlencode(get_kwargs) + anchor
+ return HttpResponseRedirect(next)
+
+
+def confirmation_view(template, doc="Display a confirmation view."):
+ """
+ Confirmation view generator for the "comment was
+ posted/flagged/deleted/approved" views.
+ """
+
+ def confirmed(request):
+ comment = None
+ if 'c' in request.GET:
+ try:
+ comment = django_comments.get_model().objects.get(pk=request.GET['c'])
+ except (ObjectDoesNotExist, ValueError):
+ pass
+ return render(request, template, {'comment': comment})
+
+ confirmed.__doc__ = textwrap.dedent("""\
+ %s
+
+ Templates: :template:`%s``
+ Context:
+ comment
+ The posted comment
+ """ % (doc, template)
+ )
+ return confirmed