Files
mastodon/app/controllers/admin/moderation_suggestions_controller.rb

160 lines
6.9 KiB
Ruby

# frozen_string_literal: true
class Admin::ModerationSuggestionsController < Admin::BaseController
before_action :set_moderation_suggestion_targets, only: :index
before_action :set_moderation_suggestions_by_target, only: :index
before_action :set_moderation_advisories_by_target, only: :index
before_action :set_current_state_by_target, only: :index
before_action :set_moderation_suggestion, only: [:destroy, :apply]
def index
authorize :moderation_suggestion, :index?
end
def destroy
authorize @moderation_suggestion, :dismiss?
# TODO: log?
# Actually dismiss all of the suggestions for the same target
ModerationSuggestion.where(target_type: @moderation_suggestion.target_type, target_key: @moderation_suggestion.target_key).update_all(state: :dismissed)
redirect_to admin_moderation_suggestions_path, notice: I18n.t('admin.moderation_suggestions.destroyed_msg', target_key: @moderation_suggestion.target_key)
end
def apply
authorize @moderation_suggestion, :apply?
case [@moderation_suggestion.target_type, @moderation_suggestion.action]
when ['domain', 'accept']
domain_allow = @moderation_suggestion.to_domain_allow
ApplicationRecord.transaction do
# TODO: log
domain_allow.save!
@moderation_suggestion.mark_as_applied!
end
redirect_to admin_moderation_suggestions_path, notice: I18n.t('admin.moderation_suggestions.applied_msg', target_key: @moderation_suggestion.target_key)
when ['domain', 'reject'], ['domain', 'limit']
domain_block = @moderation_suggestion.to_domain_block
# TODO: factor with `DomainBlocksController#create`?
existing_domain_block = DomainBlock.rule_for(domain_block.domain)
# We can't create a laxer block for a subdomain than we have for a domain
if existing_domain_block.present? && existing_domain_block.domain != TagManager.instance.normalize_domain(domain_block.domain) && !domain_block.stricter_than?(existing_domain_block)
return redirect_to admin_moderation_suggestions_path,
alert: I18n.t('admin.moderation_suggestions.unable_to_apply_msg',
target_key: @moderation_suggestion.target_key)
end
update = false
# Allow transparently upgrading a domain block
if existing_domain_block.present? && existing_domain_block.domain == TagManager.instance.normalize_domain(domain_block.domain)
# Downgrading requires confirmation
return render :confirm_downgrade unless domain_block.stricter_than?(existing_domain_block) || params[:confirm_downgrade]
# Transparent upgrading is allowed
existing_domain_block.assign_attributes(domain_block.attributes.without('id', 'created_at', 'updated_at'))
domain_block = existing_domain_block
update = domain_block.severity_changed?
end
# Require explicit confirmation on block
return render :confirm_reject if requires_confirmation?(domain_block)
domain_block.save!
# TODO: is this the way we want to log it?
log_action (update ? :update : :create), domain_block, moderation_subscription_id: domain_block.moderation_subscription_id
DomainBlockWorker.perform_async(domain_block.id, update)
@moderation_suggestion.mark_as_applied!
redirect_to admin_moderation_suggestions_path, notice: I18n.t('admin.moderation_suggestions.applied_msg', target_key: @moderation_suggestion.target_key)
when ['domain', 'retract']
ApplicationRecord.transaction do
if Rails.configuration.x.mastodon.limited_federation_mode
domain_allow = DomainAllow.find_by(domain: @moderation_suggestion.target_key)
UnallowDomainService.new.call(domain_allow)
# TODO: is this the way we want to log it?
log_action :destroy, domain_allow, moderation_subscription_id: domain_block.moderation_subscription_id
else
domain_block = DomainBlock.find_by(domain: @moderation_suggestion.target_key)
UnblockDomainService.new.call(domain_block)
# TODO: is this the way we want to log it?
log_action :destroy, domain_block, moderation_subscription_id: domain_block.moderation_subscription_id
end
@moderation_suggestion.mark_as_applied!
end
redirect_to admin_moderation_suggestions_path, notice: I18n.t('admin.moderation_suggestions.retracted_msg', target_key: @moderation_suggestion.target_key)
end
end
private
def requires_confirmation?(domain_block)
domain_block.valid? && (domain_block.new_record? || domain_block.severity_changed?) && domain_block.suspend? && !params[:confirm]
end
def set_moderation_suggestion_targets
@moderation_suggestion_targets = ModerationSuggestion.where(state: ['new', 'mailed']).reorder([target_type: :asc, target_key: :asc]).distinct.pluck(:target_type, :target_key)
end
def set_moderation_suggestions_by_target
@moderation_suggestions_by_target = begin
@moderation_suggestion_targets.group_by(&:first).reduce(ModerationSuggestion.none) do |scope, (target_type, target_pairs)|
scope.or(ModerationSuggestion.where(target_type: target_type, target_key: target_pairs.map(&:second)))
end
end.group_by { |suggestion| [suggestion.target_type, suggestion.target_key] }
end
def set_moderation_advisories_by_target
@moderation_advisories_by_target = begin
@moderation_suggestion_targets.group_by(&:first).reduce(SubscribedAdvisory.none) do |scope, (target_type, target_pairs)|
scope.or(SubscribedAdvisory.joins(:moderation_subscription).where(target_type: target_type, target_key: target_pairs.map(&:second)))
end
end.group_by { |advisory| [advisory.target_type, advisory.target_key] }
@moderation_advisories_by_target.each_value do |advisories|
advisories.sort_by! { |advisory| advisory.moderation_subscription.priority }
end
@moderation_advisories_by_target
end
def set_current_state_by_target
# TODO: handle other target types
if Rails.configuration.x.mastodon.limited_federation_mode
@current_state_by_target = DomainAllow.where(domain: @moderation_suggestion_targets.filter_map { |type, key| key if type == 'domain' }).pluck(:domain).to_h { |domain| [['domain', domain], 'accept'] }
@current_state_by_target.default = 'reject'
else
@current_state_by_target = DomainBlock.where(domain: @moderation_suggestion_targets.filter_map { |type, key| key if type == 'domain' }).to_h do |domain_block|
action = begin
case domain_block.severity
when 'suspend'
'reject'
when 'silence'
'limit'
else
'accept'
end
end
[['domain', domain_block.domain], action]
end
@current_state_by_target.default = 'accept'
end
@current_state_by_target
end
def set_moderation_suggestion
@moderation_suggestion = ModerationSuggestion.find(params[:id])
end
end