Add moderation warnings (#9519)
* Add moderation warnings Replace individual routes for disabling, silencing, and suspending a user, as well as the report update route, with a unified account action controller that allows you to select an action (none, disable, silence, suspend) as well as whether it should generate an e-mail notification with optional custom text. That notification, with the optional custom text, is saved as a warning. Additionally, there are warning presets you can configure to save time when performing the above. * Use Account#local_username_and_domain
This commit is contained in:
parent
00862dcaff
commit
3c033c4352
72 changed files with 685 additions and 539 deletions
|
@ -155,6 +155,14 @@ class Account < ApplicationRecord
|
|||
ResolveAccountService.new.call(acct)
|
||||
end
|
||||
|
||||
def silence!
|
||||
update!(silenced: true)
|
||||
end
|
||||
|
||||
def unsilence!
|
||||
update!(silenced: false)
|
||||
end
|
||||
|
||||
def suspend!
|
||||
transaction do
|
||||
user&.disable! if local?
|
||||
|
|
23
app/models/account_warning.rb
Normal file
23
app/models/account_warning.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
# frozen_string_literal: true
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: account_warnings
|
||||
#
|
||||
# id :bigint(8) not null, primary key
|
||||
# account_id :bigint(8)
|
||||
# target_account_id :bigint(8)
|
||||
# action :integer default("none"), not null
|
||||
# text :text default(""), not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
|
||||
class AccountWarning < ApplicationRecord
|
||||
enum action: %i(none disable silence suspend), _suffix: :action
|
||||
|
||||
belongs_to :account, inverse_of: :account_warnings
|
||||
belongs_to :target_account, class_name: 'Account', inverse_of: :targeted_account_warnings
|
||||
|
||||
scope :latest, -> { order(created_at: :desc) }
|
||||
scope :custom, -> { where.not(text: '') }
|
||||
end
|
15
app/models/account_warning_preset.rb
Normal file
15
app/models/account_warning_preset.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# == Schema Information
|
||||
#
|
||||
# Table name: account_warning_presets
|
||||
#
|
||||
# id :bigint(8) not null, primary key
|
||||
# text :text default(""), not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
|
||||
class AccountWarningPreset < ApplicationRecord
|
||||
validates :text, presence: true
|
||||
end
|
134
app/models/admin/account_action.rb
Normal file
134
app/models/admin/account_action.rb
Normal file
|
@ -0,0 +1,134 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Admin::AccountAction
|
||||
include ActiveModel::Model
|
||||
include AccountableConcern
|
||||
include Authorization
|
||||
|
||||
TYPES = %w(
|
||||
none
|
||||
disable
|
||||
silence
|
||||
suspend
|
||||
).freeze
|
||||
|
||||
attr_accessor :target_account,
|
||||
:current_account,
|
||||
:type,
|
||||
:text,
|
||||
:report_id,
|
||||
:warning_preset_id,
|
||||
:send_email_notification
|
||||
|
||||
attr_reader :warning
|
||||
|
||||
def save!
|
||||
ApplicationRecord.transaction do
|
||||
process_action!
|
||||
process_warning!
|
||||
end
|
||||
|
||||
queue_email!
|
||||
process_reports!
|
||||
end
|
||||
|
||||
def report
|
||||
@report ||= Report.find(report_id) if report_id.present?
|
||||
end
|
||||
|
||||
def with_report?
|
||||
!report.nil?
|
||||
end
|
||||
|
||||
class << self
|
||||
def types_for_account(account)
|
||||
if account.local?
|
||||
TYPES
|
||||
else
|
||||
TYPES - %w(none disable)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def process_action!
|
||||
case type
|
||||
when 'disable'
|
||||
handle_disable!
|
||||
when 'silence'
|
||||
handle_silence!
|
||||
when 'suspend'
|
||||
handle_suspend!
|
||||
end
|
||||
end
|
||||
|
||||
def process_warning!
|
||||
return unless warnable?
|
||||
|
||||
authorize(target_account, :warn?)
|
||||
|
||||
@warning = AccountWarning.create!(target_account: target_account,
|
||||
account: current_account,
|
||||
action: type,
|
||||
text: text_for_warning)
|
||||
|
||||
# A log entry is only interesting if the warning contains
|
||||
# custom text from someone. Otherwise it's just noise.
|
||||
log_action(:create, warning) if warning.text.present?
|
||||
end
|
||||
|
||||
def process_reports!
|
||||
return if report_id.blank?
|
||||
|
||||
authorize(report, :update?)
|
||||
|
||||
if type == 'none'
|
||||
log_action(:resolve, report)
|
||||
report.resolve!(current_account)
|
||||
else
|
||||
Report.where(target_account: target_account).unresolved.update_all(action_taken: true, action_taken_by_account_id: current_account.id)
|
||||
end
|
||||
end
|
||||
|
||||
def handle_disable!
|
||||
authorize(target_account.user, :disable?)
|
||||
log_action(:disable, target_account.user)
|
||||
target_account.user&.disable!
|
||||
end
|
||||
|
||||
def handle_silence!
|
||||
authorize(target_account, :silence?)
|
||||
log_action(:silence, target_account)
|
||||
target_account.silence!
|
||||
end
|
||||
|
||||
def handle_suspend!
|
||||
authorize(target_account, :suspend?)
|
||||
log_action(:suspend, target_account)
|
||||
target_account.suspend!
|
||||
queue_suspension_worker!
|
||||
end
|
||||
|
||||
def text_for_warning
|
||||
[warning_preset&.text, text].compact.join("\n\n")
|
||||
end
|
||||
|
||||
def queue_suspension_worker!
|
||||
Admin::SuspensionWorker.perform_async(target_account.id)
|
||||
end
|
||||
|
||||
def queue_email!
|
||||
return unless warnable?
|
||||
|
||||
UserMailer.warning(target_account.user, warning).deliver_later!
|
||||
end
|
||||
|
||||
def warnable?
|
||||
send_email_notification && target_account.local?
|
||||
end
|
||||
|
||||
def warning_preset
|
||||
@warning_preset ||= AccountWarningPreset.find(warning_preset_id) if warning_preset_id.present?
|
||||
end
|
||||
end
|
|
@ -39,6 +39,8 @@ module AccountAssociations
|
|||
# Moderation notes
|
||||
has_many :account_moderation_notes, dependent: :destroy, inverse_of: :account
|
||||
has_many :targeted_moderation_notes, class_name: 'AccountModerationNote', foreign_key: :target_account_id, dependent: :destroy, inverse_of: :target_account
|
||||
has_many :account_warnings, dependent: :destroy, inverse_of: :account
|
||||
has_many :targeted_account_warnings, class_name: 'AccountWarning', foreign_key: :target_account_id, dependent: :destroy, inverse_of: :target_account
|
||||
|
||||
# Lists (that the account is on, not owned by the account)
|
||||
has_many :list_accounts, inverse_of: :account, dependent: :destroy
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Form::AdminSuspensionConfirmation
|
||||
include ActiveModel::Model
|
||||
|
||||
attr_accessor :acct, :report_id
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue