DEV: Use Service::Base for suspend and silence actions (#28459)

This commit moves the business logic in the `Admin::UsersController#suspend` and `Admin::UsersController#silence` actions to dedicated service classes. There's no functional changes in this commit.

Internal topic: t/130014.
This commit is contained in:
Osama Sayegh
2024-08-22 14:38:56 +03:00
committed by GitHub
parent 58c4528a1c
commit 67cde14a61
8 changed files with 338 additions and 165 deletions

View File

@ -1,8 +1,6 @@
# frozen_string_literal: true
class Admin::UsersController < Admin::StaffController
MAX_SIMILAR_USERS = 10
before_action :fetch_user,
only: %i[
suspend
@ -62,7 +60,7 @@ class Admin::UsersController < Admin::StaffController
{
users:
ActiveModel::ArraySerializer.new(
@user.similar_users.limit(MAX_SIMILAR_USERS),
@user.similar_users.limit(User::MAX_SIMILAR_USERS),
each_serializer: SimilarAdminUserSerializer,
scope: guardian,
root: false,
@ -121,70 +119,41 @@ class Admin::UsersController < Admin::StaffController
end
def suspend
guardian.ensure_can_suspend!(@user)
reason = params[:reason]
if reason && (!reason.is_a?(String) || reason.size > 300)
raise Discourse::InvalidParameters.new(:reason)
end
if @user.suspended?
suspend_record = @user.suspend_record
message =
I18n.t(
"user.already_suspended",
staff: suspend_record.acting_user.username,
time_ago:
AgeWords.time_ago_in_words(
suspend_record.created_at,
true,
scope: :"datetime.distance_in_words_verbose",
),
with_service(SuspendUser, user: @user) do
on_success do
render_json_dump(
suspension: {
suspend_reason: result.reason,
full_suspend_reason: result.user_history&.details,
suspended_till: @user.suspended_till,
suspended_at: @user.suspended_at,
suspended_by: BasicUserSerializer.new(current_user, root: false).as_json,
},
)
return render json: failed_json.merge(message: message), status: 409
end
params.require(%i[suspend_until reason])
all_users = [@user]
if Array === params[:other_user_ids]
if params[:other_user_ids].size > MAX_SIMILAR_USERS
raise Discourse::InvalidParameters.new(:other_user_ids)
end
all_users.concat(User.where(id: params[:other_user_ids]).to_a)
all_users.uniq!
on_failed_policy(:can_suspend) { raise Discourse::InvalidAccess.new }
on_failed_policy(:not_suspended_already) do
suspend_record = @user.suspend_record
message =
I18n.t(
"user.already_suspended",
staff: suspend_record.acting_user.username,
time_ago:
AgeWords.time_ago_in_words(
suspend_record.created_at,
true,
scope: :"datetime.distance_in_words_verbose",
),
)
render json: failed_json.merge(message: message), status: 409
end
on_failed_contract do |contract|
render json: failed_json.merge(errors: contract.errors.full_messages), status: 400
end
end
user_history = nil
all_users.each { |user| raise Discourse::InvalidAccess.new if !guardian.can_suspend?(user) }
all_users.each do |user|
suspender =
UserSuspender.new(
user,
suspended_till: params[:suspend_until],
reason: params[:reason],
by_user: current_user,
message: params[:message],
post_id: params[:post_id],
)
suspender.suspend
user_history = suspender.user_history
end
perform_post_action
render_json_dump(
suspension: {
suspend_reason: params[:reason],
full_suspend_reason: user_history&.details,
suspended_till: @user.suspended_till,
suspended_at: @user.suspended_at,
suspended_by: BasicUserSerializer.new(current_user, root: false).as_json,
},
)
end
def unsuspend
@ -359,78 +328,41 @@ class Admin::UsersController < Admin::StaffController
end
def silence
reason = params[:reason]
if reason && (!reason.is_a?(String) || reason.size > 300)
raise Discourse::InvalidParameters.new(:reason)
end
if @user.silenced?
silenced_record = @user.silenced_record
message =
I18n.t(
"user.already_silenced",
staff: silenced_record.acting_user.username,
time_ago:
AgeWords.time_ago_in_words(
silenced_record.created_at,
true,
scope: :"datetime.distance_in_words_verbose",
),
)
return render json: failed_json.merge(message: message), status: 409
end
all_users = [@user]
if Array === params[:other_user_ids]
if params[:other_user_ids].size > MAX_SIMILAR_USERS
raise Discourse::InvalidParameters.new(:other_user_ids)
end
all_users.concat(User.where(id: params[:other_user_ids]).to_a)
all_users.uniq!
end
user_history = nil
all_users.each do |user|
raise Discourse::InvalidAccess.new if !guardian.can_silence_user?(user)
end
all_users.each do |user|
silencer =
UserSilencer.new(
user,
current_user,
silenced_till: params[:silenced_till],
reason: params[:reason],
message_body: params[:message],
keep_posts: true,
post_id: params[:post_id],
)
if silencer.silence
user_history = silencer.user_history
Jobs.enqueue(
:critical_user_email,
type: "account_silenced",
user_id: user.id,
user_history_id: user_history.id,
with_service(SilenceUser, user: @user) do
on_success do
render_json_dump(
silence: {
silenced: true,
silence_reason: result.user_history&.details,
silenced_till: @user.silenced_till,
silenced_at: @user.silenced_at,
silenced_by: BasicUserSerializer.new(current_user, root: false).as_json,
},
)
end
on_failed_policy(:can_silence) { raise Discourse::InvalidAccess.new }
on_failed_policy(:not_silenced_already) do
silenced_record = @user.silenced_record
message =
I18n.t(
"user.already_silenced",
staff: silenced_record.acting_user.username,
time_ago:
AgeWords.time_ago_in_words(
silenced_record.created_at,
true,
scope: :"datetime.distance_in_words_verbose",
),
)
render json: failed_json.merge(message: message), status: 409
end
on_failed_contract do |contract|
render json: failed_json.merge(errors: contract.errors.full_messages), status: 400
end
end
perform_post_action
render_json_dump(
silence: {
silenced: true,
silence_reason: user_history.try(:details),
silenced_till: @user.silenced_till,
silenced_at: @user.silenced_at,
silenced_by: BasicUserSerializer.new(current_user, root: false).as_json,
},
)
end
def unsilence
@ -612,31 +544,6 @@ class Admin::UsersController < Admin::StaffController
private
def perform_post_action
return if params[:post_id].blank? || params[:post_action].blank?
if post = Post.where(id: params[:post_id]).first
case params[:post_action]
when "delete"
PostDestroyer.new(current_user, post).destroy if guardian.can_delete_post_or_topic?(post)
when "delete_replies"
if guardian.can_delete_post_or_topic?(post)
PostDestroyer.delete_with_replies(current_user, post)
end
when "edit"
revisor = PostRevisor.new(post)
# Take what the moderator edited in as gospel
revisor.revise!(
current_user,
{ raw: params[:post_edit] },
skip_validations: true,
skip_revision: true,
)
end
end
end
def fetch_user
@user = User.find_by(id: params[:user_id])
raise Discourse::NotFound unless @user