diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 1167c4ed9..e9192abb8 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -314,7 +314,16 @@ class CommentsController < ApplicationController def user_blocked? return false if current_user.blocked_by_count.zero? - UserBlock.blocking?(@comment.commentable.user_id, current_user.id) || - UserBlock.blocking?(@comment.parent&.user_id, current_user.id) + blocked_by_commentable_author = UserBlock.blocking?(@comment.commentable.user_id, current_user.id) + blocked_by_comment_author = @comment.parent && UserBlock.blocking?(@comment.parent.user_id, current_user.id) + + blocked_by_commentable_author || blocked_by_comment_author || blocker_upthread?(@comment.parent) + end + + def blocker_upthread?(comment) + return false unless comment&.parent + + thread_authors_ids = comment.ancestors.pluck(:user_id) + UserBlock.exists?(blocker_id: thread_authors_ids, blocked_id: current_user.id) end end diff --git a/spec/requests/comments_create_spec.rb b/spec/requests/comments_create_spec.rb index ad75f11a5..e040cd348 100644 --- a/spec/requests/comments_create_spec.rb +++ b/spec/requests/comments_create_spec.rb @@ -89,21 +89,42 @@ RSpec.describe "CommentsCreate" do end context "when user is commenting on a comment by an author who has blocked the user" do - let(:third_party_article) { create(:article, user_id: create(:user).id) } - - it "raises a ModerationUnauthorizedError to prevent the comment from saving" do + before do create(:user_block, blocker: blocker, blocked: user, config: "default") # Manually manage the blocked_by_count attribute that counter_culture manages in prod - user.update(blocked_by_count: 1) - blocker_comment = create(:comment, user_id: blocker.id, - commentable_id: third_party_article.id, - commentable_type: "Article") + user.update_column(:blocked_by_count, 1) + end + + let!(:third_party_article) { create(:article, user_id: create(:user).id) } + + it "raises a ModerationUnauthorizedError to prevent the comment from saving" do + blocker_comment = create(:comment, user_id: blocker.id, commentable: third_party_article) expect do post comments_path, params: comment_params(body_markdown: "trolling attempted!", parent_id: blocker_comment.id) - expect(response).to have_http_status(:unprocessable_entity) - expect(response.parsed_body["error"]).to eq("Not allowed due to moderation action") end.not_to change(Comment, :count) + + expect(response).to have_http_status(:unprocessable_entity) + expect(response.parsed_body["error"]).to eq("Not allowed due to moderation action") + end + + it "raises the error when the commenter is downthread of the blocker" do + # Simulate a conversation between the blocking user and two other users who aren't blocking anyone + replier_one = create(:user) + replier_two = create(:user) + blocker_comment = create(:comment, user: blocker, body_markdown: "I just block and then keep it moving", + commentable: third_party_article) + first_reply = create(:comment, user: replier_one, commentable: third_party_article, body_markdown: "+1!", + parent_id: blocker_comment.id) + downthread_reply = create(:comment, user: replier_two, commentable: third_party_article, body_markdown: "<3", + parent_id: first_reply.id) + expect do + post comments_path, + params: comment_params(body_markdown: "I'd love to derail this convo!", parent_id: downthread_reply.id) + end.not_to change(Comment, :count) + + expect(response).to have_http_status(:unprocessable_entity) + expect(response.parsed_body["error"]).to eq("Not allowed due to moderation action") end end