mirror of
https://github.com/discourse/discourse.git
synced 2025-01-16 05:12:40 +08:00
DEV: Add reviewables:mass-handle rake task (#30658)
This commit introduces a new rake task that can be used in situations where a community receives a large number of flags/reports and needs a quick way to handle all of those pending reports. Usage instructions are included in the rake task source code. Internal topic: t/145475.
This commit is contained in:
parent
b96a9b9896
commit
85f7778563
114
lib/tasks/reviewables.rake
Normal file
114
lib/tasks/reviewables.rake
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
desc "Perform an action on all pending reviewables of a given type"
|
||||||
|
task "reviewables:mass-handle", %i[reviewable_type username action_id] => :environment do |_, args|
|
||||||
|
args_hash = args.to_hash
|
||||||
|
|
||||||
|
if args_hash.size == 0
|
||||||
|
pending_types = Reviewable.where(status: Reviewable.statuses[:pending]).distinct.pluck(:type)
|
||||||
|
puts <<~HELP
|
||||||
|
rake reviewables:mass-handle[reviewable_type,username,action]
|
||||||
|
reviewable_type:
|
||||||
|
a type of `Reviewable` such as `ReviewableFlaggedPost`, `ReviewableQueuedPost` etc.
|
||||||
|
Your site currently has #{pending_types.size} types with pending records, and they are:
|
||||||
|
#{pending_types}
|
||||||
|
username:
|
||||||
|
username of the acting user who will perform the action on the reviewables
|
||||||
|
action:
|
||||||
|
the name of the action that you want to mass-perform on pending
|
||||||
|
reviewables. There isn't one set of actions that works on all types of
|
||||||
|
reviewables because each type defines its own set of actions.
|
||||||
|
To list all available actions for a given type, run this rake task
|
||||||
|
without the action argument and it will print the list of actions that
|
||||||
|
you can perform.
|
||||||
|
HELP
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
reviewable_class =
|
||||||
|
begin
|
||||||
|
args[:reviewable_type]&.constantize
|
||||||
|
rescue NameError
|
||||||
|
raise "#{args[:reviewable_type].inspect} is not a valid Reviewable type."
|
||||||
|
end
|
||||||
|
|
||||||
|
if !reviewable_class || !(reviewable_class < Reviewable)
|
||||||
|
raise "#{args[:reviewable_type].inspect} is not a Reviewable subclass."
|
||||||
|
end
|
||||||
|
|
||||||
|
acting_user = User.find_by(username_lower: args[:username]&.downcase)
|
||||||
|
raise "Cannot find user with id=#{args[:username].inspect}." if !acting_user
|
||||||
|
|
||||||
|
relation = reviewable_class.where(status: Reviewable.statuses[:pending])
|
||||||
|
count = relation.count
|
||||||
|
|
||||||
|
if count == 0
|
||||||
|
puts "There are 0 pending #{reviewable_class}. Nothing to do."
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
if !args_hash.key?(:action_id)
|
||||||
|
collection = relation.first.actions_for(acting_user.guardian)
|
||||||
|
actions = collection.bundles.map(&:actions).flatten.map(&:server_action)
|
||||||
|
|
||||||
|
puts <<~MSG
|
||||||
|
You need to specify an action to perform on the #{count} pending #{reviewable_class}.
|
||||||
|
Here's a list of the all avaiable actions on the #{reviewable_class} type:
|
||||||
|
#{actions.join("\n")}
|
||||||
|
MSG
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
action_id = args[:action_id]
|
||||||
|
if !reviewable_class.method_defined?(:"perform_#{action_id}")
|
||||||
|
raise "#{reviewable_class} doesn't support an action with the name #{action_id.inspect}."
|
||||||
|
end
|
||||||
|
|
||||||
|
print <<~MSG.strip + " "
|
||||||
|
There are #{count} pending #{reviewable_class} records.
|
||||||
|
@#{acting_user.username} will perform #{action_id.inspect} on them.
|
||||||
|
Are you sure you want to proceed? Type "#{count}" to confirm or "n" to cancel:
|
||||||
|
MSG
|
||||||
|
|
||||||
|
while true
|
||||||
|
input = STDIN.readline.strip
|
||||||
|
|
||||||
|
if input == "n"
|
||||||
|
puts "Task cancelled."
|
||||||
|
break
|
||||||
|
elsif input == count.to_s
|
||||||
|
puts "Performing #{action_id.inspect} on #{count} #{reviewable_class} records..."
|
||||||
|
failed = []
|
||||||
|
relation.find_each do |reviewable|
|
||||||
|
result = reviewable.perform(acting_user, action_id)
|
||||||
|
|
||||||
|
if result.success?
|
||||||
|
putc "."
|
||||||
|
else
|
||||||
|
putc "F"
|
||||||
|
failed << { reviewable:, errors: result.errors }
|
||||||
|
end
|
||||||
|
rescue => error
|
||||||
|
putc "F"
|
||||||
|
failed << { reviewable:, errors: [error] }
|
||||||
|
end
|
||||||
|
|
||||||
|
puts ""
|
||||||
|
puts "#{count - failed.size} records have been processed successfully and #{failed.size} failed."
|
||||||
|
|
||||||
|
if failed.size > 0
|
||||||
|
puts "Here's a detailed report of each record that failed:"
|
||||||
|
failed.each do |obj|
|
||||||
|
puts <<~TEXT
|
||||||
|
reviewable id: #{obj[:reviewable].id}
|
||||||
|
errors: #{obj[:errors].inspect}
|
||||||
|
TEXT
|
||||||
|
puts "=" * 50
|
||||||
|
end
|
||||||
|
end
|
||||||
|
break
|
||||||
|
else
|
||||||
|
print "Can't understand your input. Please try again: "
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user