gremmie@1: """ gremmie@1: Views for the comments application. bgneal@693: gremmie@1: """ gremmie@1: from django.contrib.auth.decorators import login_required gremmie@1: from django.core.exceptions import ObjectDoesNotExist gremmie@1: from django.http import HttpResponse gremmie@1: from django.http import HttpResponseBadRequest gremmie@1: from django.http import HttpResponseForbidden gremmie@1: from django.db.models import get_model bgneal@1032: from django.shortcuts import render gremmie@1: from django.utils.html import escape gremmie@1: from django.views.decorators.http import require_POST gremmie@1: gremmie@1: from core.functions import email_admins bgneal@974: from core.html import image_check, ImageCheckError bgneal@136: from core.markup import site_markup gremmie@1: from comments.forms import CommentForm gremmie@1: from comments.models import Comment gremmie@1: from comments.models import CommentFlag bgneal@215: import antispam bgneal@215: import antispam.utils bgneal@215: gremmie@1: bgneal@974: PREVIEW_UNAVAILABLE = """ bgneal@974:

Error: {}

bgneal@974:

Sorry, preview is unavailable.

bgneal@974:

There is an image in your post which failed our image check. We can only bgneal@1021: accept images from a small number of sources for security reasons.

bgneal@1021:

If there are forms below this post box, you may use them to safely hot-link bgneal@1021: to images hosted elsewhere on the Internet or upload from your computer or bgneal@1021: device.

bgneal@1021:

If there are no image forms on this page, you can upload a photo from your bgneal@1021: computer or device from your user profile. Copy the image code you receive bgneal@1021: into the post box here.

bgneal@974: """ bgneal@974: bgneal@974: gremmie@1: @login_required gremmie@1: @require_POST gremmie@1: def post_comment(request): gremmie@1: """ gremmie@1: This function handles the posting of comments. If successful, returns bgneal@215: the comment text as the response. This function is meant to be the target gremmie@1: of an AJAX post. gremmie@1: """ gremmie@1: # Look up the object we're trying to comment about gremmie@1: ctype = request.POST.get('content_type', None) gremmie@1: object_pk = request.POST.get('object_pk', None) gremmie@1: if ctype is None or object_pk is None: gremmie@1: return HttpResponseBadRequest('Missing content_type or object_pk field.') gremmie@1: gremmie@1: try: gremmie@1: model = get_model(*ctype.split('.', 1)) gremmie@1: target = model.objects.get(pk=object_pk) gremmie@1: except TypeError: gremmie@1: return HttpResponseBadRequest( gremmie@1: "Invalid content_type value: %r" % escape(ctype)) gremmie@1: except AttributeError: gremmie@1: return HttpResponseBadRequest( gremmie@1: "The given content-type %r does not resolve to a valid model." % \ gremmie@1: escape(ctype)) gremmie@1: except ObjectDoesNotExist: gremmie@1: return HttpResponseBadRequest( gremmie@1: "No object matching content-type %r and object PK %r exists." % \ gremmie@1: (escape(ctype), escape(object_pk))) gremmie@1: gremmie@1: # Can we comment on the target object? gremmie@1: if hasattr(target, 'can_comment_on'): gremmie@1: if callable(target.can_comment_on): gremmie@1: can_comment_on = target.can_comment_on() gremmie@1: else: gremmie@1: can_comment_on = target.can_comment_on gremmie@1: else: gremmie@1: can_comment_on = True gremmie@1: gremmie@1: if not can_comment_on: gremmie@1: return HttpResponseForbidden('Cannot comment on this item.') gremmie@1: gremmie@1: # Check form validity gremmie@1: gremmie@1: form = CommentForm(target, request.POST) gremmie@1: if not form.is_valid(): bgneal@963: # The client side javascript is pretty simplistic right now and we don't bgneal@963: # want to change it yet. It is expecting a single error string. Just grab bgneal@963: # the first error message and use that. bgneal@963: errors = form.errors.as_data() bgneal@963: msg = errors.values()[0][0].message if errors else 'Unknown error' bgneal@963: return HttpResponseBadRequest(msg) gremmie@1: bgneal@215: comment = form.get_comment_object(request.user, request.META.get("REMOTE_ADDR", None)) gremmie@1: bgneal@693: # Check for spam bgneal@215: bgneal@215: if antispam.utils.spam_check(request, comment.comment): bgneal@215: return HttpResponseForbidden(antispam.BUSTED_MESSAGE) bgneal@215: bgneal@963: comment.save(html=form.comment_html) gremmie@1: gremmie@1: # return the rendered comment bgneal@1032: return render(request, 'comments/comment.html', { gremmie@1: 'comment': comment, bgneal@1032: }) bgneal@693: gremmie@1: gremmie@1: @require_POST gremmie@1: def flag_comment(request): gremmie@1: """ gremmie@1: This function handles the flagging of comments by users. This function should gremmie@1: be the target of an AJAX post. gremmie@1: """ gremmie@1: if not request.user.is_authenticated(): gremmie@1: return HttpResponse('Please login or register to flag a comment.') gremmie@1: gremmie@1: id = request.POST.get('id', None) gremmie@1: if id is None: gremmie@1: return HttpResponseBadRequest('No id') gremmie@1: gremmie@1: try: gremmie@1: comment = Comment.objects.get(pk=id) gremmie@1: except Comment.DoesNotExist: gremmie@1: return HttpResponseBadRequest('No comment with id %s' % id) gremmie@1: gremmie@1: flag = CommentFlag(user=request.user, comment=comment) gremmie@1: flag.save() gremmie@1: email_admins('A Comment Has Been Flagged', """Hello, gremmie@1: gremmie@1: A user has flagged a comment for review. gremmie@1: """) gremmie@1: return HttpResponse('The comment was flagged. A moderator will review the comment shortly. ' \ gremmie@1: 'Thanks for helping to improve the discussions on this site.') gremmie@1: gremmie@1: gremmie@1: @require_POST gremmie@1: def markdown_preview(request): gremmie@1: """ gremmie@1: This function should be the target of an AJAX POST. It takes the 'data' parameter gremmie@1: from the POST parameters and returns a rendered HTML page from the data, which bgneal@693: is assumed to be in markdown format. The HTML page is suitable for the preview gremmie@1: function for a javascript editor such as markItUp. gremmie@1: """ gremmie@1: if not request.user.is_authenticated(): bgneal@1094: return HttpResponseForbidden('This service is only available to logged-in users.') gremmie@1: gremmie@1: data = request.POST.get('data', None) gremmie@1: if data is None: gremmie@1: return HttpResponseBadRequest('No data') gremmie@1: bgneal@974: html = site_markup(data) bgneal@978: if html: bgneal@978: try: bgneal@978: image_check(html) bgneal@978: except ImageCheckError as ex: bgneal@978: html = PREVIEW_UNAVAILABLE.format(ex) bgneal@974: bgneal@1032: return render(request, 'comments/markdown_preview.html', { bgneal@974: 'data': html, bgneal@1032: }) bgneal@1094: bgneal@1094: bgneal@1094: @require_POST bgneal@1094: def markdown_preview_v3(request): bgneal@1094: if not request.user.is_authenticated(): bgneal@1094: return HttpResponseForbidden( bgneal@1094: 'This service is only available to logged-in users.') bgneal@1094: bgneal@1094: data = request.POST.get('data', None) bgneal@1094: html = site_markup(data) if data else '' bgneal@1094: if html: bgneal@1094: try: bgneal@1094: image_check(html) bgneal@1094: except ImageCheckError as ex: bgneal@1094: html = PREVIEW_UNAVAILABLE.format(ex) bgneal@1094: bgneal@1094: return HttpResponse(html)