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)
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)
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 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)
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)