diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb
index 768bb2415..46734e2e6 100644
--- a/app/controllers/posts_controller.rb
+++ b/app/controllers/posts_controller.rb
@@ -26,7 +26,7 @@ class PostsController < ApplicationController
@comments = @post.comments
@comments = @comments.includes(:creator)
@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?
@parent_post_set = PostSets::PostRelationship.new(@post.parent_id, :include_deleted => include_deleted)
diff --git a/app/models/comment.rb b/app/models/comment.rb
index a03f949e4..ed77ca463 100644
--- a/app/models/comment.rb
+++ b/app/models/comment.rb
@@ -130,10 +130,19 @@ class Comment < ApplicationRecord
user.id.in?(votes.map(&:user_id))
end
- def visible_by?(user, show_thresholded: false, show_deleted: false)
- return false if is_deleted? && !show_deleted && !user.is_moderator?
- return false if score < user.comment_threshold && !is_sticky? && !show_thresholded
- true
+ def visibility(user)
+ return :invisible if is_deleted? && !user.is_moderator?
+ return :hidden if is_deleted? && user.is_moderator?
+ 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
def hidden_attributes
diff --git a/app/views/comments/_index_by_post.html.erb b/app/views/comments/_index_by_post.html.erb
index 08faa93af..17d9d1298 100644
--- a/app/views/comments/_index_by_post.html.erb
+++ b/app/views/comments/_index_by_post.html.erb
@@ -10,12 +10,12 @@
<% end %>
<% @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 %>
<%= link_to(image_tag(post.preview_file_url), post_path(post)) %>
- <%= 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 %>
<% end %>
<% end %>
diff --git a/app/views/comments/partials/index/_list.html.erb b/app/views/comments/partials/index/_list.html.erb
index a424094c8..21f3c4690 100644
--- a/app/views/comments/partials/index/_list.html.erb
+++ b/app/views/comments/partials/index/_list.html.erb
@@ -4,7 +4,7 @@
<% end %>
- <% 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) %>
diff --git a/test/functional/comments_controller_test.rb b/test/functional/comments_controller_test.rb
index 6f9de1a73..59badcecd 100644
--- a/test/functional/comments_controller_test.rb
+++ b/test/functional/comments_controller_test.rb
@@ -5,15 +5,12 @@ class CommentsControllerTest < ActionDispatch::IntegrationTest
setup do
@mod = FactoryBot.create(:moderator_user)
@user = FactoryBot.create(:member_user)
+ @post = create(:post)
+
CurrentUser.user = @user
CurrentUser.ip_addr = "127.0.0.1"
Danbooru.config.stubs(:member_comment_time_threshold).returns(1.week.from_now)
-
- @post = FactoryBot.create(:post)
- @comment = FactoryBot.create(:comment, :post => @post)
- CurrentUser.scoped(@mod) do
- @mod_comment = FactoryBot.create(:comment, :post => @post)
- end
+ Danbooru.config.stubs(:member_comment_limit).returns(100)
end
teardown do
@@ -22,14 +19,70 @@ class CommentsControllerTest < ActionDispatch::IntegrationTest
end
context "index action" do
- should "render for post" do
- get comments_path(post_id: @post.id, group_by: "post", format: "js"), xhr: true
- assert_response :success
- end
+ context "grouped by post" do
+ should "render all comments for .js" do
+ get comments_path(post_id: @post.id, group_by: "post", format: "js"), xhr: true
+ assert_response :success
+ end
- should "render by post" do
- get comments_path(group_by: "post")
- assert_response :success
+ should "show posts with visible comments" do
+ @comment = as(@user) { create(:comment, post: @post) }
+ 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
should "render by comment" do
@@ -45,6 +98,7 @@ class CommentsControllerTest < ActionDispatch::IntegrationTest
context "search action" do
should "render" do
+ @comment = create(:comment, post: @post)
get search_comments_path
assert_response :success
end
@@ -52,6 +106,7 @@ class CommentsControllerTest < ActionDispatch::IntegrationTest
context "show action" do
should "render" do
+ @comment = create(:comment, post: @post)
get comment_path(@comment.id)
assert_response :success
end
@@ -59,12 +114,17 @@ class CommentsControllerTest < ActionDispatch::IntegrationTest
context "edit action" do
should "render" do
+ @comment = create(:comment, post: @post)
get_auth edit_comment_path(@comment.id), @user
assert_response :success
end
end
context "update action" do
+ setup do
+ @comment = create(:comment, post: @post)
+ end
+
context "when updating another user's comment" do
should "succeed if updater is a moderator" do
put_auth comment_path(@comment.id), @user, params: {comment: {body: "abc"}}
@@ -73,6 +133,7 @@ class CommentsControllerTest < ActionDispatch::IntegrationTest
end
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"}}
assert_not_equal("abc", @mod_comment.reload.body)
assert_response 403
@@ -141,19 +202,19 @@ class CommentsControllerTest < ActionDispatch::IntegrationTest
context "destroy action" do
should "mark comment as deleted" do
+ @comment = create(:comment, post: @post)
delete_auth comment_path(@comment.id), @user
+
assert_equal(true, @comment.reload.is_deleted)
assert_redirected_to @comment
end
end
context "undelete action" do
- setup do
- @comment.delete!
- end
-
should "mark comment as undeleted" do
+ @comment = create(:comment, post: @post, is_deleted: true)
post_auth undelete_comment_path(@comment.id), @user
+
assert_equal(false, @comment.reload.is_deleted)
assert_redirected_to(@comment)
end
diff --git a/test/functional/posts_controller_test.rb b/test/functional/posts_controller_test.rb
index 39d0e1626..cbed45d93 100644
--- a/test/functional/posts_controller_test.rb
+++ b/test/functional/posts_controller_test.rb
@@ -157,12 +157,14 @@ class PostsControllerTest < ActionDispatch::IntegrationTest
assert_select "div.list-of-comments p", /There are no comments/
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)
get_auth post_path(@post), mod, params: { id: @post.id }
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