FEATURE: Blocking is optional when deleting a user from the review queue. (#13375)
Subclasses must call #delete_user_actions inside build_actions to support user deletion. The method adds a delete user bundle, which has a delete and a delete + block option. Every subclass is responsible for implementing these actions.
This commit is contained in:
parent
503017474c
commit
4dc8c3c409
|
@ -20,7 +20,7 @@ module Jobs
|
|||
elsif reviewable.is_a?(ReviewableQueuedPost)
|
||||
reviewable.perform(Discourse.system_user, :reject_post)
|
||||
elsif reviewable.is_a?(ReviewableUser)
|
||||
reviewable.perform(Discourse.system_user, :reject_user_delete)
|
||||
reviewable.perform(Discourse.system_user, :delete_user)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -643,6 +643,28 @@ class Reviewable < ActiveRecord::Base
|
|||
self.score
|
||||
end
|
||||
|
||||
def delete_user_actions(actions, require_reject_reason: false)
|
||||
reject = actions.add_bundle(
|
||||
'reject_user',
|
||||
icon: 'user-times',
|
||||
label: 'reviewables.actions.reject_user.title'
|
||||
)
|
||||
|
||||
actions.add(:delete_user, bundle: reject) do |a|
|
||||
a.icon = 'user-times'
|
||||
a.label = "reviewables.actions.reject_user.delete.title"
|
||||
a.require_reject_reason = require_reject_reason
|
||||
a.description = "reviewables.actions.reject_user.delete.description"
|
||||
end
|
||||
|
||||
actions.add(:delete_user_block, bundle: reject) do |a|
|
||||
a.icon = 'ban'
|
||||
a.label = "reviewables.actions.reject_user.block.title"
|
||||
a.require_reject_reason = require_reject_reason
|
||||
a.description = "reviewables.actions.reject_user.block.description"
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def increment_version!(version = nil)
|
||||
|
|
|
@ -57,16 +57,6 @@ class ReviewableFlaggedPost < Reviewable
|
|||
build_action(actions, :agree_and_silence, icon: 'microphone-slash', bundle: agree, client_action: 'silence')
|
||||
end
|
||||
|
||||
if can_delete_spammer = potential_spam? && guardian.can_delete_all_posts?(target_created_by)
|
||||
build_action(
|
||||
actions,
|
||||
:delete_spammer,
|
||||
icon: 'exclamation-triangle',
|
||||
bundle: agree,
|
||||
confirm: true
|
||||
)
|
||||
end
|
||||
|
||||
if post.user_deleted?
|
||||
build_action(actions, :agree_and_restore, icon: 'far-eye', bundle: agree)
|
||||
end
|
||||
|
@ -79,6 +69,10 @@ class ReviewableFlaggedPost < Reviewable
|
|||
|
||||
build_action(actions, :ignore, icon: 'external-link-alt')
|
||||
|
||||
if potential_spam? && guardian.can_delete_all_posts?(target_created_by)
|
||||
delete_user_actions(actions)
|
||||
end
|
||||
|
||||
if guardian.can_delete_post_or_topic?(post)
|
||||
delete = actions.add_bundle("#{id}-delete", icon: "far-trash-alt", label: "reviewables.actions.delete.title")
|
||||
build_action(actions, :delete_and_ignore, icon: 'external-link-alt', bundle: delete)
|
||||
|
@ -134,17 +128,22 @@ class ReviewableFlaggedPost < Reviewable
|
|||
agree(performed_by, args)
|
||||
end
|
||||
|
||||
def perform_delete_spammer(performed_by, args)
|
||||
UserDestroyer.new(performed_by).destroy(
|
||||
post.user,
|
||||
delete_posts: true,
|
||||
prepare_for_destroy: true,
|
||||
block_email: true,
|
||||
block_urls: true,
|
||||
block_ip: true,
|
||||
delete_as_spammer: true,
|
||||
context: "review"
|
||||
)
|
||||
def perform_delete_user(performed_by, args)
|
||||
delete_options = delete_opts
|
||||
|
||||
UserDestroyer.new(performed_by).destroy(post.user, delete_options)
|
||||
|
||||
agree(performed_by, args)
|
||||
end
|
||||
|
||||
def perform_delete_user_block(performed_by, args)
|
||||
delete_options = delete_opts
|
||||
|
||||
if Rails.env.production?
|
||||
delete_options.merge!(block_email: true, block_ip: true)
|
||||
end
|
||||
|
||||
UserDestroyer.new(performed_by).destroy(post.user, delete_options)
|
||||
|
||||
agree(performed_by, args)
|
||||
end
|
||||
|
@ -302,6 +301,16 @@ protected
|
|||
|
||||
private
|
||||
|
||||
def delete_opts
|
||||
{
|
||||
delete_posts: true,
|
||||
prepare_for_destroy: true,
|
||||
block_urls: true,
|
||||
delete_as_spammer: true,
|
||||
context: "review"
|
||||
}
|
||||
end
|
||||
|
||||
def destroyer(performed_by, post)
|
||||
PostDestroyer.new(performed_by, post, reviewable: self)
|
||||
end
|
||||
|
|
|
@ -33,12 +33,7 @@ class ReviewableQueuedPost < Reviewable
|
|||
end
|
||||
|
||||
if pending? && guardian.can_delete_user?(created_by)
|
||||
actions.add(:delete_user) do |action|
|
||||
action.icon = 'trash-alt'
|
||||
action.button_class = 'btn-danger'
|
||||
action.label = 'reviewables.actions.delete_user.title'
|
||||
action.confirm_message = 'reviewables.actions.delete_user.confirm'
|
||||
end
|
||||
delete_user_actions(actions)
|
||||
end
|
||||
|
||||
actions.add(:delete) if guardian.can_delete?(self)
|
||||
|
@ -133,24 +128,35 @@ class ReviewableQueuedPost < Reviewable
|
|||
end
|
||||
|
||||
def perform_delete_user(performed_by, args)
|
||||
delete_options = {
|
||||
context: I18n.t('reviewables.actions.delete_user.reason'),
|
||||
delete_posts: true,
|
||||
block_urls: true,
|
||||
block_email: true,
|
||||
block_ip: true,
|
||||
delete_as_spammer: true
|
||||
}
|
||||
delete_user(performed_by, delete_opts)
|
||||
end
|
||||
|
||||
def perform_delete_user_block(performed_by, args)
|
||||
delete_options = delete_opts
|
||||
|
||||
if Rails.env.production?
|
||||
delete_options.merge!(block_email: true, block_ip: true)
|
||||
end
|
||||
|
||||
delete_user(performed_by, delete_options)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def delete_user(performed_by, delete_options)
|
||||
reviewable_ids = Reviewable.where(created_by: created_by).pluck(:id)
|
||||
UserDestroyer.new(performed_by).destroy(created_by, delete_options)
|
||||
create_result(:success) { |r| r.remove_reviewable_ids = reviewable_ids }
|
||||
end
|
||||
|
||||
def delete_opts
|
||||
{
|
||||
context: I18n.t('reviewables.actions.delete_user.reason'),
|
||||
delete_posts: true,
|
||||
block_urls: true,
|
||||
delete_as_spammer: true
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
# == Schema Information
|
||||
|
|
|
@ -19,23 +19,7 @@ class ReviewableUser < Reviewable
|
|||
end
|
||||
end
|
||||
|
||||
reject = actions.add_bundle(
|
||||
'reject_user',
|
||||
icon: 'user-times',
|
||||
label: 'reviewables.actions.reject_user.title'
|
||||
)
|
||||
actions.add(:reject_user_delete, bundle: reject) do |a|
|
||||
a.icon = 'user-times'
|
||||
a.label = "reviewables.actions.reject_user.delete.title"
|
||||
a.require_reject_reason = !is_a_suspect_user?
|
||||
a.description = "reviewables.actions.reject_user.delete.description"
|
||||
end
|
||||
actions.add(:reject_user_block, bundle: reject) do |a|
|
||||
a.icon = 'ban'
|
||||
a.label = "reviewables.actions.reject_user.block.title"
|
||||
a.require_reject_reason = !is_a_suspect_user?
|
||||
a.description = "reviewables.actions.reject_user.block.description"
|
||||
end
|
||||
delete_user_actions(actions, require_reject_reason: !is_a_suspect_user?)
|
||||
end
|
||||
|
||||
def perform_approve_user(performed_by, args)
|
||||
|
@ -56,7 +40,7 @@ class ReviewableUser < Reviewable
|
|||
create_result(:success, :approved)
|
||||
end
|
||||
|
||||
def perform_reject_user_delete(performed_by, args)
|
||||
def perform_delete_user(performed_by, args)
|
||||
# We'll delete the user if we can
|
||||
if target.present?
|
||||
destroyer = UserDestroyer.new(performed_by)
|
||||
|
@ -96,10 +80,10 @@ class ReviewableUser < Reviewable
|
|||
create_result(:success, :rejected)
|
||||
end
|
||||
|
||||
def perform_reject_user_block(performed_by, args)
|
||||
def perform_delete_user_block(performed_by, args)
|
||||
args[:block_email] = true
|
||||
args[:block_ip] = true
|
||||
perform_reject_user_delete(performed_by, args)
|
||||
perform_delete_user(performed_by, args)
|
||||
end
|
||||
|
||||
# Update's the user's fields for approval but does not save. This
|
||||
|
|
|
@ -1019,7 +1019,7 @@ class User < ActiveRecord::Base
|
|||
self.update!(active: false)
|
||||
|
||||
if reviewable = ReviewableUser.pending.find_by(target: self)
|
||||
reviewable.perform(performed_by, :reject_user_delete)
|
||||
reviewable.perform(performed_by, :delete_user)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -108,7 +108,7 @@ class UserDestroyer
|
|||
|
||||
# After the user is deleted, remove the reviewable
|
||||
if reviewable = ReviewableUser.pending.find_by(target: user)
|
||||
reviewable.perform(@actor, :reject_user_delete)
|
||||
reviewable.perform(@actor, :delete_user)
|
||||
end
|
||||
|
||||
result
|
||||
|
|
|
@ -4987,10 +4987,6 @@ en:
|
|||
agree_and_hide:
|
||||
title: "Hide Post"
|
||||
description: "Hide this post and automatically send the user a message urging them to edit it."
|
||||
delete_spammer:
|
||||
title: "Delete Spammer"
|
||||
description: "Remove the user and all their posts and topics."
|
||||
confirm: "Are you sure you want to delete all that user's posts, topics, and block their IP and email addresses?"
|
||||
delete_single:
|
||||
title: "Delete"
|
||||
delete:
|
||||
|
@ -5047,8 +5043,6 @@ en:
|
|||
approve_and_restore:
|
||||
title: "Approve and Restore post"
|
||||
delete_user:
|
||||
title: "Delete User"
|
||||
confirm: "Are you sure you want to delete that user? This will remove all of their posts and block their email and IP address."
|
||||
reason: "Deleted via review queue"
|
||||
|
||||
email_style:
|
||||
|
|
|
@ -34,7 +34,8 @@ RSpec.describe ReviewableFlaggedPost, type: :model do
|
|||
expect(actions.has?(:agree_and_keep_hidden)).to eq(false)
|
||||
expect(actions.has?(:agree_and_silence)).to eq(true)
|
||||
expect(actions.has?(:agree_and_suspend)).to eq(true)
|
||||
expect(actions.has?(:delete_spammer)).to eq(true)
|
||||
expect(actions.has?(:delete_user)).to eq(true)
|
||||
expect(actions.has?(:delete_user_block)).to eq(true)
|
||||
expect(actions.has?(:disagree)).to eq(true)
|
||||
expect(actions.has?(:ignore)).to eq(true)
|
||||
expect(actions.has?(:delete_and_ignore)).to eq(true)
|
||||
|
@ -137,7 +138,7 @@ RSpec.describe ReviewableFlaggedPost, type: :model do
|
|||
end
|
||||
|
||||
it "supports deleting a spammer" do
|
||||
reviewable.perform(moderator, :delete_spammer)
|
||||
reviewable.perform(moderator, :delete_user_block)
|
||||
expect(reviewable).to be_approved
|
||||
expect(score.reload).to be_agreed
|
||||
expect(post.reload.deleted_at).to be_present
|
||||
|
|
|
@ -118,12 +118,6 @@ RSpec.describe ReviewableQueuedPost, type: :model do
|
|||
end
|
||||
|
||||
context "delete_user" do
|
||||
it "has the correct button class" do
|
||||
expect(reviewable.actions_for(Guardian.new(moderator)).to_a.
|
||||
find { |a| a.id == :delete_user }.button_class).
|
||||
to eq("btn-danger")
|
||||
end
|
||||
|
||||
it "deletes the user and rejects the post" do
|
||||
other_reviewable = Fabricate(:reviewable_queued_post, created_by: reviewable.created_by)
|
||||
|
||||
|
|
|
@ -539,4 +539,23 @@ RSpec.describe Reviewable, type: :model do
|
|||
expect(Reviewable.by_status(Reviewable.all, :reviewed)).to contain_exactly(reviewable)
|
||||
end
|
||||
end
|
||||
|
||||
context 'default actions' do
|
||||
let(:reviewable) { Reviewable.new }
|
||||
let(:actions) { Reviewable::Actions.new(reviewable, Guardian.new) }
|
||||
|
||||
describe '#delete_user_actions' do
|
||||
it 'adds a bundle with the delete_user action' do
|
||||
reviewable.delete_user_actions(actions)
|
||||
|
||||
expect(actions.has?(:delete_user)).to be true
|
||||
end
|
||||
|
||||
it 'adds a bundle with the delete_user_block action' do
|
||||
reviewable.delete_user_actions(actions)
|
||||
|
||||
expect(actions.has?(:delete_user_block)).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,35 +17,35 @@ RSpec.describe ReviewableUser, type: :model do
|
|||
it "returns correct actions in the pending state" do
|
||||
actions = reviewable.actions_for(Guardian.new(moderator))
|
||||
expect(actions.has?(:approve_user)).to eq(true)
|
||||
expect(actions.has?(:reject_user_delete)).to eq(true)
|
||||
expect(actions.has?(:reject_user_block)).to eq(true)
|
||||
expect(actions.has?(:delete_user)).to eq(true)
|
||||
expect(actions.has?(:delete_user_block)).to eq(true)
|
||||
end
|
||||
|
||||
it "doesn't return anything in the approved state" do
|
||||
reviewable.status = Reviewable.statuses[:approved]
|
||||
actions = reviewable.actions_for(Guardian.new(moderator))
|
||||
expect(actions.has?(:approve_user)).to eq(false)
|
||||
expect(actions.has?(:reject_user_delete)).to eq(false)
|
||||
expect(actions.has?(:delete_user_block)).to eq(false)
|
||||
end
|
||||
|
||||
it 'can delete a user without a giving a rejection reason if the user was a spammer' do
|
||||
reviewable.reviewable_scores.build(user: admin, reason: 'suspect_user')
|
||||
|
||||
assert_require_reject_reason(:reject_user_delete, false)
|
||||
assert_require_reject_reason(:delete_user, false)
|
||||
end
|
||||
|
||||
it 'requires a rejection reason to delete a user' do
|
||||
assert_require_reject_reason(:reject_user_delete, true)
|
||||
assert_require_reject_reason(:delete_user, true)
|
||||
end
|
||||
|
||||
it 'can delete and block a user without giving a rejection reason if the user was a spammer' do
|
||||
reviewable.reviewable_scores.build(user: admin, reason: 'suspect_user')
|
||||
|
||||
assert_require_reject_reason(:reject_user_block, false)
|
||||
assert_require_reject_reason(:delete_user, false)
|
||||
end
|
||||
|
||||
it 'requires a rejection reason to delete and block a user' do
|
||||
assert_require_reject_reason(:reject_user_block, true)
|
||||
assert_require_reject_reason(:delete_user_block, true)
|
||||
end
|
||||
|
||||
def assert_require_reject_reason(id, expected)
|
||||
|
@ -95,7 +95,7 @@ RSpec.describe ReviewableUser, type: :model do
|
|||
end
|
||||
|
||||
it "allows us to reject a user" do
|
||||
result = reviewable.perform(moderator, :reject_user_delete, reject_reason: "reject reason")
|
||||
result = reviewable.perform(moderator, :delete_user, reject_reason: "reject reason")
|
||||
expect(result.success?).to eq(true)
|
||||
|
||||
expect(reviewable.pending?).to eq(false)
|
||||
|
@ -114,7 +114,7 @@ RSpec.describe ReviewableUser, type: :model do
|
|||
email = reviewable.target.email
|
||||
ip = reviewable.target.ip_address
|
||||
|
||||
result = reviewable.perform(moderator, :reject_user_block, reject_reason: "reject reason")
|
||||
result = reviewable.perform(moderator, :delete_user_block, reject_reason: "reject reason")
|
||||
expect(result.success?).to eq(true)
|
||||
|
||||
expect(reviewable.pending?).to eq(false)
|
||||
|
@ -132,18 +132,18 @@ RSpec.describe ReviewableUser, type: :model do
|
|||
it "is not sending email to the user about rejection" do
|
||||
SiteSetting.must_approve_users = true
|
||||
Jobs::CriticalUserEmail.any_instance.expects(:execute).never
|
||||
reviewable.perform(moderator, :reject_user_block, reject_reason: "reject reason")
|
||||
reviewable.perform(moderator, :delete_user_block, reject_reason: "reject reason")
|
||||
end
|
||||
|
||||
it "optionally sends email with reject reason" do
|
||||
SiteSetting.must_approve_users = true
|
||||
Jobs::CriticalUserEmail.any_instance.expects(:execute).with(type: :signup_after_reject, user_id: reviewable.target_id, reject_reason: "reject reason").once
|
||||
reviewable.perform(moderator, :reject_user_block, reject_reason: "reject reason", send_email: true)
|
||||
reviewable.perform(moderator, :delete_user_block, reject_reason: "reject reason", send_email: true)
|
||||
end
|
||||
|
||||
it "allows us to reject a user who has posts" do
|
||||
Fabricate(:post, user: reviewable.target)
|
||||
result = reviewable.perform(moderator, :reject_user_delete)
|
||||
result = reviewable.perform(moderator, :delete_user)
|
||||
expect(result.success?).to eq(true)
|
||||
|
||||
expect(reviewable.pending?).to eq(false)
|
||||
|
@ -158,7 +158,7 @@ RSpec.describe ReviewableUser, type: :model do
|
|||
it "allows us to reject a user who has been deleted" do
|
||||
reviewable.target.destroy!
|
||||
reviewable.reload
|
||||
result = reviewable.perform(moderator, :reject_user_delete)
|
||||
result = reviewable.perform(moderator, :delete_user)
|
||||
expect(result.success?).to eq(true)
|
||||
expect(reviewable.rejected?).to eq(true)
|
||||
expect(reviewable.target).to be_blank
|
||||
|
|
|
@ -506,7 +506,7 @@ describe WebHook do
|
|||
payload = JSON.parse(job_args["payload"])
|
||||
expect(payload["id"]).to eq(reviewable.id)
|
||||
|
||||
reviewable.perform(Discourse.system_user, :reject_user_delete)
|
||||
reviewable.perform(Discourse.system_user, :delete_user)
|
||||
job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
|
||||
|
||||
expect(job_args["event_name"]).to eq("reviewable_transitioned_to")
|
||||
|
|
|
@ -182,10 +182,10 @@ describe ReviewablesController do
|
|||
user.activate
|
||||
reviewable = ReviewableUser.find_by(target: user)
|
||||
|
||||
put "/review/#{reviewable.id}/perform/reject_user_delete.json?version=0"
|
||||
put "/review/#{reviewable.id}/perform/delete_user.json?version=0"
|
||||
expect(response.code).to eq("200")
|
||||
|
||||
put "/review/#{reviewable.id}/perform/reject_user_delete.json?version=0&index=2"
|
||||
put "/review/#{reviewable.id}/perform/delete_user.json?version=0&index=2"
|
||||
expect(response.code).to eq("404")
|
||||
json = response.parsed_body
|
||||
|
||||
|
|
Loading…
Reference in New Issue