comments: allow admins to remove comment votes (fix #4640)
Allow admins to remove comment votes by other users. This is done by clicking the comment score to get to the comment vote list, then clicking the Remove button on every vote.
This commit is contained in:
@@ -28,12 +28,16 @@ class CommentComponent < ApplicationComponent
|
||||
|
||||
def upvoted?
|
||||
return false if current_user.is_anonymous?
|
||||
comment.votes.active.select(&:is_positive?).map(&:user_id).include?(current_user.id)
|
||||
current_vote&.is_positive?
|
||||
end
|
||||
|
||||
def downvoted?
|
||||
return false if current_user.is_anonymous?
|
||||
comment.votes.active.select(&:is_negative?).map(&:user_id).include?(current_user.id)
|
||||
current_vote&.is_negative?
|
||||
end
|
||||
|
||||
def current_vote
|
||||
@current_vote ||= comment.votes.active.find { |v| v.user_id == current_user.id }
|
||||
end
|
||||
|
||||
def reported?
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<% if current_user.is_anonymous? %>
|
||||
<%= link_to upvote_icon, login_path(url: request.fullpath), class: "comment-upvote-link inactive-link" %>
|
||||
<% elsif upvoted? %>
|
||||
<%= link_to upvote_icon, comment_comment_votes_path(comment_id: comment.id), class: "comment-upvote-link comment-unvote-link active-link", method: :delete, remote: true %>
|
||||
<%= link_to upvote_icon, comment_vote_path(current_vote), class: "comment-upvote-link comment-unvote-link active-link", method: :delete, remote: true %>
|
||||
<% else %>
|
||||
<%= link_to upvote_icon, comment_comment_votes_path(comment_id: comment.id, score: "1"), class: "comment-upvote-link inactive-link", method: :post, remote: true %>
|
||||
<% end %>
|
||||
@@ -64,7 +64,7 @@
|
||||
<% if current_user.is_anonymous? %>
|
||||
<%= link_to downvote_icon, login_path(url: request.fullpath), class: "comment-downvote-link inactive-link" %>
|
||||
<% elsif downvoted? %>
|
||||
<%= link_to downvote_icon, comment_comment_votes_path(comment_id: comment.id), class: "comment-downvote-link comment-unvote-link active-link", method: :delete, remote: true %>
|
||||
<%= link_to downvote_icon, comment_vote_path(current_vote), class: "comment-downvote-link comment-unvote-link active-link", method: :delete, remote: true %>
|
||||
<% else %>
|
||||
<%= link_to downvote_icon, comment_comment_votes_path(comment_id: comment.id, score: "-1"), class: "comment-downvote-link inactive-link", method: :post, remote: true %>
|
||||
<% end %>
|
||||
|
||||
@@ -26,8 +26,7 @@ class CommentVotesController < ApplicationController
|
||||
end
|
||||
|
||||
def destroy
|
||||
# XXX should find by comment vote id.
|
||||
@comment_vote = authorize CommentVote.active.find_by!(comment_id: params[:comment_id], user: CurrentUser.user)
|
||||
@comment_vote = authorize CommentVote.find(params[:id])
|
||||
@comment_vote.soft_delete(updater: CurrentUser.user)
|
||||
|
||||
respond_with(@comment_vote)
|
||||
|
||||
@@ -4,7 +4,7 @@ class CommentVotePolicy < ApplicationPolicy
|
||||
end
|
||||
|
||||
def destroy?
|
||||
record.user_id == user.id
|
||||
!record.is_deleted? && (record.user_id == user.id || user.is_admin?)
|
||||
end
|
||||
|
||||
def can_see_votes?
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<%= fc.input :post_id, label: "Post", input_html: { value: params.dig(:search, :comment, :post_id) } %>
|
||||
<% end %>
|
||||
<%= f.input :comment_id, label: "Comment", input_html: { value: params[:search][:comment_id] } %>
|
||||
<%= f.input :is_deleted, label: "Deleted?", as: :select, include_blank: true, selected: params[:search][:is_deleted] %>
|
||||
<%= f.input :score, collection: [["+1", "1"], ["-1", "-1"]], include_blank: true, selected: params[:search][:score] %>
|
||||
<%= f.submit "Search" %>
|
||||
<% end %>
|
||||
|
||||
2
app/views/comment_votes/destroy.js+listing.erb
Normal file
2
app/views/comment_votes/destroy.js+listing.erb
Normal file
@@ -0,0 +1,2 @@
|
||||
Danbooru.Utility.notice("Vote removed");
|
||||
location.reload();
|
||||
@@ -14,9 +14,23 @@
|
||||
<%= link_to "»", comment_votes_path(search: { user_name: vote.user.name }) %>
|
||||
<% end %>
|
||||
|
||||
<% t.column "Status" do |vote| %>
|
||||
<%= "Deleted" if vote.is_deleted? %>
|
||||
<% end %>
|
||||
|
||||
<% t.column "Created" do |vote| %>
|
||||
<%= time_ago_in_words_tagged(vote.created_at) %>
|
||||
<% end %>
|
||||
|
||||
<% t.column column: "control" do |vote| %>
|
||||
<% if policy(vote).destroy? %>
|
||||
<%= render PopupMenuComponent.new do |menu| %>
|
||||
<%= menu.item do %>
|
||||
<%= link_to "Remove", comment_vote_path(vote, variant: "listing"), remote: true, method: :delete %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<%= numbered_paginator(@comment_votes) %>
|
||||
|
||||
@@ -8,27 +8,40 @@
|
||||
<% t.column "Post" do |vote| %>
|
||||
<%= post_preview(vote.comment.post, show_deleted: true) %>
|
||||
<% end %>
|
||||
|
||||
<% t.column "Comment", td: {class: "col-expand"} do |vote| %>
|
||||
<div class="prose">
|
||||
<%= format_text(vote.comment.body) %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% t.column "Status" do |vote| %>
|
||||
<%= "Deleted" if vote.is_deleted? %>
|
||||
<% end %>
|
||||
|
||||
<% t.column "Score" do |vote| %>
|
||||
<%= link_to sprintf("%+d", vote.score), comment_votes_path(search: { score: vote.score }) %>
|
||||
<% end %>
|
||||
|
||||
<% t.column "Commenter" do |vote| %>
|
||||
<%= link_to_user vote.comment.creator %>
|
||||
<%= link_to "»", comment_votes_path(search: { comment: { creator_name: vote.comment.creator.name }}) %>
|
||||
<div><%= time_ago_in_words_tagged(vote.comment.created_at) %></div>
|
||||
<% end %>
|
||||
|
||||
<% t.column "Voter" do |vote| %>
|
||||
<%= link_to_user vote.user %>
|
||||
<%= link_to "»", comment_votes_path(search: { user_name: vote.user.name }) %>
|
||||
<div><%= time_ago_in_words_tagged(vote.created_at) %></div>
|
||||
<% end %>
|
||||
|
||||
<% t.column column: "control" do |vote| %>
|
||||
<% if vote.user == CurrentUser.user %>
|
||||
<%= link_to "unvote", comment_comment_votes_path(vote.comment), remote: true, method: :delete %>
|
||||
<% if policy(vote).destroy? %>
|
||||
<%= render PopupMenuComponent.new do |menu| %>
|
||||
<%= menu.item do %>
|
||||
<%= link_to "Remove", comment_vote_path(vote, variant: "listing"), remote: true, method: :delete %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
@@ -81,7 +81,7 @@ Rails.application.routes.draw do
|
||||
post :approve
|
||||
end
|
||||
end
|
||||
resources :comment_votes, only: [:index]
|
||||
resources :comment_votes, only: [:index, :destroy]
|
||||
resources :comments do
|
||||
resource :votes, controller: "comment_votes", only: [:create, :destroy], as: "comment_votes"
|
||||
collection do
|
||||
|
||||
@@ -141,21 +141,51 @@ class CommentVotesControllerTest < ActionDispatch::IntegrationTest
|
||||
context "#destroy" do
|
||||
should "allow users to remove their own comment votes" do
|
||||
@vote = create(:comment_vote, user: @user)
|
||||
assert_equal(1, @vote.comment.score)
|
||||
|
||||
assert_difference("CommentVote.count", 0) do
|
||||
delete_auth comment_comment_votes_path(@vote.comment), @user, xhr: true
|
||||
delete_auth comment_vote_path(@vote), @user, xhr: true
|
||||
|
||||
assert_response :success
|
||||
assert_equal(true, @vote.reload.is_deleted?)
|
||||
assert_equal(0, @vote.comment.score)
|
||||
|
||||
assert_equal(false, ModAction.comment_vote_delete.exists?)
|
||||
end
|
||||
end
|
||||
|
||||
should "not allow users to remove comment votes by other users" do
|
||||
should "not allow normal users to remove comment votes by other users" do
|
||||
@vote = create(:comment_vote)
|
||||
assert_equal(1, @vote.comment.score)
|
||||
|
||||
assert_difference("CommentVote.count", 0) do
|
||||
delete_auth comment_comment_votes_path(@vote.comment), @user, xhr: true
|
||||
assert_response 404
|
||||
delete_auth comment_vote_path(@vote), @user, xhr: true, params: { variant: "listing" }
|
||||
|
||||
assert_response 403
|
||||
assert_equal(false, @vote.reload.is_deleted?)
|
||||
assert_equal(1, @vote.comment.score)
|
||||
end
|
||||
end
|
||||
|
||||
should "not allow deleting already deleted votes" do
|
||||
@vote = create(:comment_vote, is_deleted: true)
|
||||
delete_auth comment_vote_path(@vote), @user, xhr: true
|
||||
assert_response 403
|
||||
end
|
||||
|
||||
should "allow admins to remove comment votes by other users" do
|
||||
@vote = create(:comment_vote)
|
||||
assert_equal(1, @vote.comment.score)
|
||||
|
||||
assert_difference("CommentVote.count", 0) do
|
||||
delete_auth comment_vote_path(@vote), create(:admin_user), xhr: true, params: { variant: "listing" }
|
||||
|
||||
assert_response :success
|
||||
assert_equal(true, @vote.reload.is_deleted?)
|
||||
assert_equal(0, @vote.comment.score)
|
||||
|
||||
assert_equal("comment_vote_delete", ModAction.last.category)
|
||||
assert_match(/deleted comment vote/, ModAction.last.description)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -167,7 +197,7 @@ class CommentVotesControllerTest < ActionDispatch::IntegrationTest
|
||||
|
||||
should "delete the current active vote" do
|
||||
@vote = create(:comment_vote, comment: @comment, user: @user)
|
||||
delete_auth comment_comment_votes_path(@vote.comment), @user, xhr: true
|
||||
delete_auth comment_vote_path(@vote), @user, xhr: true
|
||||
|
||||
assert_response :success
|
||||
assert_equal(true, @vote.reload.is_deleted?)
|
||||
|
||||
Reference in New Issue
Block a user