0
0
Fork 0

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:
Eugen Rochko 2018-12-22 20:02:09 +01:00 committed by GitHub
parent 00862dcaff
commit 3c033c4352
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
72 changed files with 685 additions and 539 deletions

View file

@ -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?

View 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

View 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

View 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

View file

@ -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

View file

@ -1,7 +0,0 @@
# frozen_string_literal: true
class Form::AdminSuspensionConfirmation
include ActiveModel::Model
attr_accessor :acct, :report_id
end