def on_comment_will_be_posted(sender, comment, request, **kwargs):
    """
    Make sure both the Ajax and regular comments are checked for moderation.
    This signal is also used to link moderators to the comment posting.
    """
    content_object = comment.content_object
    moderator = moderation.get_model_moderator(content_object.__class__)
    if moderator and comment.__class__ is not CommentModel:
        # Help with some hard to diagnose problems. The default Django moderator connects
        # to the configured comment model. When this model differs from the signal sender,
        # the the form stores a different model then COMMENTS_APP provides.
        moderator = None
        logger.warning(
            "Comment of type '%s' was not moderated by '%s', "
            "because the parent '%s' has a moderator installed for '%s' instead",
            comment.__class__.__name__, moderator.__class__.__name__,
            content_object.__class__.__name__, CommentModel.__name__
        )

    if moderator is None:
        logger.info(
            "Using default moderator for comment '%s' on parent '%s'",
            comment.__class__.__name__, content_object.__class__.__name__
        )
        _run_default_moderator(comment, content_object, request)
Esempio n. 2
0
def on_comment_will_be_posted(sender, comment, request, **kwargs):
    """
    Make sure both the Ajax and regular comments are checked for moderation.
    This signal is also used to link moderators to the comment posting.
    """
    content_object = comment.content_object
    moderator = moderation.get_model_moderator(content_object.__class__)
    if moderator and comment.__class__ is not CommentModel:
        # Help with some hard to diagnose problems. The default Django moderator connects
        # to the configured comment model. When this model differs from the signal sender,
        # the the form stores a different model then COMMENTS_APP provides.
        moderator = None
        logger.warning(
            "Comment of type '%s' was not moderated by '%s', "
            "because the parent '%s' has a moderator installed for '%s' instead",
            comment.__class__.__name__,
            moderator.__class__.__name__,
            content_object.__class__.__name__,
            CommentModel.__name__,
        )

    if moderator is None:
        logger.info(
            "Using default moderator for comment '%s' on parent '%s'",
            comment.__class__.__name__,
            content_object.__class__.__name__,
        )
        _run_default_moderator(comment, content_object, request)
Esempio n. 3
0
    def test_comment_post_moderated(self):
        """
        See that soft delete works properly.
        """
        # Double check preconditions for moderation
        self.assertIsNotNone(get_model_moderator(Article))
        self.assertTrue(len(signals.comment_will_be_posted.receivers))
        self.assertEqual(id(get_comment_model()),
                         signals.comment_will_be_posted.receivers[0][0][1])

        content_type = "article.article"
        timestamp = str(int(time.time()))
        article = factories.create_article()

        form = CommentForm(article)
        security_hash = form.generate_security_hash(content_type,
                                                    str(article.pk), timestamp)
        post_data = {
            "content_type": content_type,
            "object_pk": article.pk,
            "name": "Testing name",
            "email": "*****@*****.**",
            "comment": "Testing comment",
            "timestamp": timestamp,
            "security_hash": security_hash,
        }

        for url, is_ajax in [
            (reverse("comments-post-comment-ajax"), True),
            (reverse("comments-post-comment"), False),
        ]:
            with patch.object(Akismet,
                              "_request",
                              return_value=MockedResponse(True)) as m:
                response = self.client.post(
                    url, post_data, HTTP_X_REQUESTED_WITH="XMLHttpRequest")
            self.assertEqual(m.call_count, 1, "Moderator not called by " + url)

            if is_ajax:
                self.assertContains(response,
                                    "Testing comment",
                                    status_code=200)
                self.assertEqual(response.status_code, 200)

                json_response = json.loads(response.content.decode("utf-8"))
                self.assertTrue(json_response["success"])
                self.assertEqual(json_response["errors"], {})
            else:
                self.assertRedirects(response,
                                     reverse("comments-comment-done") + "?c=1")

            comment = get_comment_model().objects.filter(
                user_email="*****@*****.**")[0]
            self.assertFalse(comment.is_public, "Not moderated by " + url)
            self.assertTrue(comment.is_removed)
Esempio n. 4
0
def on_comment_posted(sender, comment, request, **kwargs):
    """
    Send email notification of a new comment to site staff when email notifications have been requested.
    """
    content_object = comment.content_object

    moderator = moderation.get_model_moderator(content_object.__class__)
    if moderator is None or comment.__class__ is not CommentModel:
        # No custom moderator means no email would be sent.
        # This still pass the comment to the default moderator.
        default_moderator.email(comment, content_object, request)
def on_comment_posted(sender, comment, request, **kwargs):
    """
    Send email notification of a new comment to site staff when email notifications have been requested.
    """
    content_object = comment.content_object

    moderator = moderation.get_model_moderator(content_object.__class__)
    if moderator is None or comment.__class__ is not CommentModel:
        # No custom moderator means no email would be sent.
        # This still pass the comment to the default moderator.
        default_moderator.email(comment, content_object, request)
    def test_moderator_no_akismet(self, *mocks):
        """
        Testing moderation without akismet
        """
        request = RequestFactory().post(reverse('comments-post-comment-ajax'))
        article = factories.create_article()
        comment = factories.create_comment(article=article)
        moderator = get_model_moderator(Article)  # type: FluentCommentsModerator

        self.assertTrue(article.enable_comments)
        self.assertFalse(moderator.akismet_check)
        self.assertTrue(moderator.allow(comment, article, request), "no akismet, comment should be allowed")
    def test_moderator_no_akismet(self, *mocks):
        """
        Testing moderation without akismet
        """
        request = RequestFactory().post(reverse('comments-post-comment-ajax'))
        article = factories.create_article()
        comment = factories.create_comment(article=article)
        moderator = get_model_moderator(Article)  # type: FluentCommentsModerator

        self.assertTrue(article.enable_comments)
        self.assertFalse(moderator.akismet_check)
        self.assertTrue(moderator.allow(comment, article, request), "no akismet, comment should be allowed")
    def test_bad_words(self, *mocks):
        """
        Test moderation on bad words.
        """
        request = RequestFactory().post(reverse('comments-post-comment-ajax'))
        article = factories.create_article()
        comment = factories.create_comment(article=article, comment='Testing:viagra!!')
        moderator = get_model_moderator(Article)  # type: FluentCommentsModerator

        self.assertTrue(moderator.moderate_bad_words)  # see that settings are correctly patched
        self.assertTrue(moderator.moderate(comment, article, request), "bad_words should reject")

        comment.comment = "Just normal words"
        self.assertFalse(moderator.moderate(comment, article, request), "bad_words should not trigger")
    def test_akismet(self, *mocks):
        """
        Test an akismet call
        """
        request = RequestFactory().post(reverse('comments-post-comment-ajax'))
        article = factories.create_article()
        comment = factories.create_comment(article=article, user_name='viagra-test-123')
        moderator = get_model_moderator(Article)  # type: FluentCommentsModerator

        self.assertTrue(article.enable_comments)
        self.assertTrue(moderator.akismet_check)  # see that settings are correctly patched

        with patch.object(Akismet, '_request', return_value=MockedResponse(True)):
            self.assertTrue(moderator.moderate(comment, article, request), "akismet should reject")
    def test_bad_words(self, *mocks):
        """
        Test moderation on bad words.
        """
        request = RequestFactory().post(reverse('comments-post-comment-ajax'))
        article = factories.create_article()
        comment = factories.create_comment(article=article, comment='Testing:viagra!!')
        moderator = get_model_moderator(Article)  # type: FluentCommentsModerator

        self.assertTrue(moderator.moderate_bad_words)  # see that settings are correctly patched
        self.assertTrue(moderator.moderate(comment, article, request), "bad_words should reject")

        comment.comment = "Just normal words"
        self.assertFalse(moderator.moderate(comment, article, request), "bad_words should not trigger")
    def test_akismet(self, *mocks):
        """
        Test an akismet call
        """
        request = RequestFactory().post(reverse('comments-post-comment-ajax'))
        article = factories.create_article()
        comment = factories.create_comment(article=article, user_name='viagra-test-123')
        moderator = get_model_moderator(Article)  # type: FluentCommentsModerator

        self.assertTrue(article.enable_comments)
        self.assertTrue(moderator.akismet_check)  # see that settings are correctly patched

        with patch.object(Akismet, '_request', return_value=MockedResponse(True)):
            self.assertTrue(moderator.moderate(comment, article, request), "akismet should reject")
    def test_comment_post_moderated(self):
        """
        See that soft delete works properly.
        """
        # Double check preconditions for moderation
        self.assertIsNotNone(get_model_moderator(Article))
        self.assertTrue(len(signals.comment_will_be_posted.receivers))
        self.assertEqual(id(get_comment_model()), signals.comment_will_be_posted.receivers[0][0][1])

        content_type = "article.article"
        timestamp = str(int(time.time()))
        article = factories.create_article()

        form = CommentForm(article)
        security_hash = form.generate_security_hash(content_type, str(article.pk), timestamp)
        post_data = {
            "content_type": content_type,
            "object_pk": article.pk,
            "name": "Testing name",
            "email": "*****@*****.**",
            "comment": "Testing comment",
            "timestamp": timestamp,
            "security_hash": security_hash,
        }

        for url, is_ajax in [
            (reverse("comments-post-comment-ajax"), True),
            (reverse("comments-post-comment"), False),
        ]:
            with patch.object(Akismet, '_request', return_value=MockedResponse(True)) as m:
                response = self.client.post(url, post_data, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
            self.assertEqual(m.call_count, 1, "Moderator not called by " + url)

            if is_ajax:
                self.assertContains(response, "Testing comment", status_code=200)
                self.assertEqual(response.status_code, 200)

                json_response = json.loads(response.content.decode("utf-8"))
                self.assertTrue(json_response['success'])
                self.assertEqual(json_response['errors'], {})
            else:
                self.assertRedirects(response, reverse('comments-comment-done') + "?c=1")

            comment = get_comment_model().objects.filter(user_email="*****@*****.**")[0]
            self.assertFalse(comment.is_public, "Not moderated by " + url)
            self.assertTrue(comment.is_removed)
 def test_get_model_moderator(self, *mocks):
     """
     See if the moderator was registered.
     """
     moderator = get_model_moderator(Article)
     self.assertIsNotNone(moderator)
 def test_get_model_moderator(self, *mocks):
     """
     See if the moderator was registered.
     """
     moderator = get_model_moderator(Article)
     self.assertIsNotNone(moderator)
Esempio n. 15
0
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_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 is_authenticated(request.user):
        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:
        model = apps.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, LookupError):
        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 = django_comments.get_form()(target, data=data)

    # Check security information
    if form.security_errors():
        return CommentPostBadRequest(
            "The comment form failed security verification: {0}".format(
                form.security_errors()))

    # 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 is_authenticated(request.user):
        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)
    if not responses and get_model_moderator(target.__class__) is not None:
        # Help with some hard to diagnose problems. The default Django moderator connects
        # to the configured comment model. When this model differs from the signal sender,
        # the the form stores a different model then COMMENTS_APP provides.
        CommentModel = django_comments.get_model()
        if comment.__class__ is not CommentModel:
            logger.warning(
                "Comment of type '%s' was not moderated, "
                "because the parent '%s' has a moderator installed for '%s'",
                comment.__class__.__name__, target.__class__.__name__,
                CommentModel.__name__)
        else:
            logger.warning(
                "Comment of type '%s' was not moderated, "
                "even though the parent '%s' has a moderator installed",
                comment.__class__.__name__, target.__class__.__name__)

    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)