Fix #3351: Mod+: Treat deleted comments as below score threshold.

Comments have three states: visible, hidden, and invisible. Visible
comments are always shown. Hidden comments are not shown until the user
clicks 'Show all comments'. Invisible comments are never shown to the
user. Deleted comments are treated as hidden for moderators and
invisible for normal users. Thresholded comments are treated as hidden
for all users.
This commit is contained in:
evazion
2019-08-31 16:15:31 -05:00
parent 7e2eb7e5a7
commit be36968b6d
6 changed files with 99 additions and 27 deletions

View File

@@ -26,7 +26,7 @@ class PostsController < ApplicationController
@comments = @post.comments @comments = @post.comments
@comments = @comments.includes(:creator) @comments = @comments.includes(:creator)
@comments = @comments.includes(:votes) if CurrentUser.is_member? @comments = @comments.includes(:votes) if CurrentUser.is_member?
@comments = @comments.select { |c| c.visible_by?(CurrentUser.user) } @comments = @comments.visible(CurrentUser.user)
include_deleted = @post.is_deleted? || (@post.parent_id.present? && @post.parent.is_deleted?) || CurrentUser.user.show_deleted_children? include_deleted = @post.is_deleted? || (@post.parent_id.present? && @post.parent.is_deleted?) || CurrentUser.user.show_deleted_children?
@parent_post_set = PostSets::PostRelationship.new(@post.parent_id, :include_deleted => include_deleted) @parent_post_set = PostSets::PostRelationship.new(@post.parent_id, :include_deleted => include_deleted)

View File

@@ -130,10 +130,19 @@ class Comment < ApplicationRecord
user.id.in?(votes.map(&:user_id)) user.id.in?(votes.map(&:user_id))
end end
def visible_by?(user, show_thresholded: false, show_deleted: false) def visibility(user)
return false if is_deleted? && !show_deleted && !user.is_moderator? return :invisible if is_deleted? && !user.is_moderator?
return false if score < user.comment_threshold && !is_sticky? && !show_thresholded return :hidden if is_deleted? && user.is_moderator?
true return :hidden if score < user.comment_threshold && !is_sticky?
return :visible
end
def self.hidden(user)
select { |comment| comment.visibility(user) == :hidden }
end
def self.visible(user)
select { |comment| comment.visibility(user) == :visible }
end end
def hidden_attributes def hidden_attributes

View File

@@ -10,12 +10,12 @@
<% end %> <% end %>
<% @posts.select(&:visible?).each do |post| %> <% @posts.select(&:visible?).each do |post| %>
<% if post.comments.any? { |c| c.visible_by?(CurrentUser.user, show_thresholded: true) } %> <% if post.comments.visible(CurrentUser.user).any? || post.comments.hidden(CurrentUser.user).any? %>
<%= content_tag(:div, { id: "post_#{post.id}", class: ["post", *PostPresenter.preview_class(post)].join(" ") }.merge(PostPresenter.data_attributes(post))) do %> <%= content_tag(:div, { id: "post_#{post.id}", class: ["post", *PostPresenter.preview_class(post)].join(" ") }.merge(PostPresenter.data_attributes(post))) do %>
<div class="preview"> <div class="preview">
<%= link_to(image_tag(post.preview_file_url), post_path(post)) %> <%= link_to(image_tag(post.preview_file_url), post_path(post)) %>
</div> </div>
<%= render "comments/partials/index/list", post: post, comments: post.comments.select { |c| c.visible_by?(CurrentUser.user) }.last(6), page: :comments %> <%= render "comments/partials/index/list", post: post, comments: post.comments.visible(CurrentUser.user).last(6), page: :comments %>
<div class="clearfix"></div> <div class="clearfix"></div>
<% end %> <% end %>
<% end %> <% end %>

View File

@@ -4,7 +4,7 @@
<% end %> <% end %>
<div class="row notices"> <div class="row notices">
<% if post.comments.any? { |c| !c.visible_by?(CurrentUser.user, show_deleted: true) } || (page == :comments && post.comments.size > 6) %> <% if post.comments.hidden(CurrentUser.user).any? || (page == :comments && post.comments.size > 6) %>
<span class="info" id="threshold-comments-notice-for-<%= post.id %>"> <span class="info" id="threshold-comments-notice-for-<%= post.id %>">
<%= link_to "Show all comments", comments_path(post_id: post.id), id: "show-all-comments-link", remote: true %> <%= link_to "Show all comments", comments_path(post_id: post.id), id: "show-all-comments-link", remote: true %>
</span> </span>

View File

@@ -5,15 +5,12 @@ class CommentsControllerTest < ActionDispatch::IntegrationTest
setup do setup do
@mod = FactoryBot.create(:moderator_user) @mod = FactoryBot.create(:moderator_user)
@user = FactoryBot.create(:member_user) @user = FactoryBot.create(:member_user)
@post = create(:post)
CurrentUser.user = @user CurrentUser.user = @user
CurrentUser.ip_addr = "127.0.0.1" CurrentUser.ip_addr = "127.0.0.1"
Danbooru.config.stubs(:member_comment_time_threshold).returns(1.week.from_now) Danbooru.config.stubs(:member_comment_time_threshold).returns(1.week.from_now)
Danbooru.config.stubs(:member_comment_limit).returns(100)
@post = FactoryBot.create(:post)
@comment = FactoryBot.create(:comment, :post => @post)
CurrentUser.scoped(@mod) do
@mod_comment = FactoryBot.create(:comment, :post => @post)
end
end end
teardown do teardown do
@@ -22,14 +19,70 @@ class CommentsControllerTest < ActionDispatch::IntegrationTest
end end
context "index action" do context "index action" do
should "render for post" do context "grouped by post" do
get comments_path(post_id: @post.id, group_by: "post", format: "js"), xhr: true should "render all comments for .js" do
assert_response :success get comments_path(post_id: @post.id, group_by: "post", format: "js"), xhr: true
end assert_response :success
end
should "render by post" do should "show posts with visible comments" do
get comments_path(group_by: "post") @comment = as(@user) { create(:comment, post: @post) }
assert_response :success get comments_path(group_by: "post")
assert_response :success
assert_select "#post_#{@post.id}", 1
assert_select "#post_#{@post.id} .comment", 1
assert_select "#post_#{@post.id} #show-all-comments-link", 0
end
should "show the 'Show all comments' link on posts with thresholded comments" do
as(@user) { create(:comment, post: @post, score: -10) }
get comments_path(group_by: "post")
assert_response :success
assert_select "#post_#{@post.id}", 1
assert_select "#post_#{@post.id} #show-all-comments-link", 1
assert_select "#post_#{@post.id} .comment", 0
assert_select "#post_#{@post.id} .list-of-comments", /There are no visible comments/
end
should "not show the 'Show all comments' link on posts with deleted comments to Members" do
@comment1 = as(@user) { create(:comment, post: @post) }
@comment2 = as(@user) { create(:comment, post: @post, is_deleted: true) }
get comments_path(group_by: "post")
assert_response :success
assert_select "#post_#{@post.id}", 1
assert_select "#post_#{@post.id} .comment", 1
assert_select "#post_#{@post.id} #show-all-comments-link", 0
end
should "show the 'Show all comments' link on posts with deleted comments to Moderators" do
@comment1 = as(@user) { create(:comment, post: @post) }
@comment2 = as(@user) { create(:comment, post: @post, is_deleted: true) }
get_auth comments_path(group_by: "post"), @mod
assert_response :success
assert_select "#post_#{@post.id}", 1
assert_select "#post_#{@post.id} .comment", 1
assert_select "#post_#{@post.id} #show-all-comments-link", 1
end
should "not bump posts with nonbumping comments" do
as(@user) { create(:comment, post: @post, do_not_bump_post: true) }
get comments_path(group_by: "post")
assert_response :success
assert_select "#post_#{@post.id}", 0
end
should "not bump posts with only deleted comments" do
as(@user) { create(:comment, post: @post, is_deleted: true) }
get comments_path(group_by: "post")
assert_response :success
assert_select "#post_#{@post.id}", 0
end
end end
should "render by comment" do should "render by comment" do
@@ -45,6 +98,7 @@ class CommentsControllerTest < ActionDispatch::IntegrationTest
context "search action" do context "search action" do
should "render" do should "render" do
@comment = create(:comment, post: @post)
get search_comments_path get search_comments_path
assert_response :success assert_response :success
end end
@@ -52,6 +106,7 @@ class CommentsControllerTest < ActionDispatch::IntegrationTest
context "show action" do context "show action" do
should "render" do should "render" do
@comment = create(:comment, post: @post)
get comment_path(@comment.id) get comment_path(@comment.id)
assert_response :success assert_response :success
end end
@@ -59,12 +114,17 @@ class CommentsControllerTest < ActionDispatch::IntegrationTest
context "edit action" do context "edit action" do
should "render" do should "render" do
@comment = create(:comment, post: @post)
get_auth edit_comment_path(@comment.id), @user get_auth edit_comment_path(@comment.id), @user
assert_response :success assert_response :success
end end
end end
context "update action" do context "update action" do
setup do
@comment = create(:comment, post: @post)
end
context "when updating another user's comment" do context "when updating another user's comment" do
should "succeed if updater is a moderator" do should "succeed if updater is a moderator" do
put_auth comment_path(@comment.id), @user, params: {comment: {body: "abc"}} put_auth comment_path(@comment.id), @user, params: {comment: {body: "abc"}}
@@ -73,6 +133,7 @@ class CommentsControllerTest < ActionDispatch::IntegrationTest
end end
should "fail if updater is not a moderator" do should "fail if updater is not a moderator" do
@mod_comment = as(@mod) { create(:comment, post: @post) }
put_auth comment_path(@mod_comment.id), @user, params: {comment: {body: "abc"}} put_auth comment_path(@mod_comment.id), @user, params: {comment: {body: "abc"}}
assert_not_equal("abc", @mod_comment.reload.body) assert_not_equal("abc", @mod_comment.reload.body)
assert_response 403 assert_response 403
@@ -141,19 +202,19 @@ class CommentsControllerTest < ActionDispatch::IntegrationTest
context "destroy action" do context "destroy action" do
should "mark comment as deleted" do should "mark comment as deleted" do
@comment = create(:comment, post: @post)
delete_auth comment_path(@comment.id), @user delete_auth comment_path(@comment.id), @user
assert_equal(true, @comment.reload.is_deleted) assert_equal(true, @comment.reload.is_deleted)
assert_redirected_to @comment assert_redirected_to @comment
end end
end end
context "undelete action" do context "undelete action" do
setup do
@comment.delete!
end
should "mark comment as undeleted" do should "mark comment as undeleted" do
@comment = create(:comment, post: @post, is_deleted: true)
post_auth undelete_comment_path(@comment.id), @user post_auth undelete_comment_path(@comment.id), @user
assert_equal(false, @comment.reload.is_deleted) assert_equal(false, @comment.reload.is_deleted)
assert_redirected_to(@comment) assert_redirected_to(@comment)
end end

View File

@@ -157,12 +157,14 @@ class PostsControllerTest < ActionDispatch::IntegrationTest
assert_select "div.list-of-comments p", /There are no comments/ assert_select "div.list-of-comments p", /There are no comments/
end end
should "show deleted comments to moderators" do should "not show deleted comments to moderators by default, but allow them to be unhidden" do
mod = create(:mod_user) mod = create(:mod_user)
get_auth post_path(@post), mod, params: { id: @post.id } get_auth post_path(@post), mod, params: { id: @post.id }
assert_response :success assert_response :success
assert_select "article.comment", 1 assert_select "article.comment", 0
assert_select "a#show-all-comments-link", 1
assert_select "div.list-of-comments p", /There are no comments/
end end
end end