Skip to content

Commit

Permalink
Change account suspensions to be reversible by default (mastodon#14726)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gargron authored and thenameisnigel-old committed Sep 18, 2020
1 parent bb645c2 commit 1a84b97
Show file tree
Hide file tree
Showing 39 changed files with 529 additions and 282 deletions.
31 changes: 20 additions & 11 deletions app/controllers/admin/accounts_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

module Admin
class AccountsController < BaseController
before_action :set_account, only: [:show, :redownload, :remove_avatar, :remove_header, :enable, :unsilence, :unsuspend, :memorialize, :approve, :reject]
before_action :set_account, except: [:index]
before_action :require_remote_account!, only: [:redownload]
before_action :require_local_account!, only: [:enable, :memorialize, :approve, :reject]

Expand All @@ -14,49 +14,58 @@ def index
def show
authorize @account, :show?

@deletion_request = @account.deletion_request
@account_moderation_note = current_account.account_moderation_notes.new(target_account: @account)
@moderation_notes = @account.targeted_moderation_notes.latest
@warnings = @account.targeted_account_warnings.latest.custom
@domain_block = DomainBlock.rule_for(@account.domain)
end

def memorialize
authorize @account, :memorialize?
@account.memorialize!
log_action :memorialize, @account
redirect_to admin_account_path(@account.id)
redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.memorialized_msg', username: @account.acct)
end

def enable
authorize @account.user, :enable?
@account.user.enable!
log_action :enable, @account.user
redirect_to admin_account_path(@account.id)
redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.enabled_msg', username: @account.acct)
end

def approve
authorize @account.user, :approve?
@account.user.approve!
redirect_to admin_pending_accounts_path
redirect_to admin_pending_accounts_path, notice: I18n.t('admin.accounts.approved_msg', username: @account.acct)
end

def reject
authorize @account.user, :reject?
SuspendAccountService.new.call(@account, reserve_email: false, reserve_username: false)
redirect_to admin_pending_accounts_path
DeleteAccountService.new.call(@account, reserve_email: false, reserve_username: false)
redirect_to admin_pending_accounts_path, notice: I18n.t('admin.accounts.rejected_msg', username: @account.acct)
end

def destroy
authorize @account, :destroy?
Admin::AccountDeletionWorker.perform_async(@account.id)
redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.destroyed_msg', username: @account.acct)
end

def unsilence
authorize @account, :unsilence?
@account.unsilence!
log_action :unsilence, @account
redirect_to admin_account_path(@account.id)
redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.unsilenced_msg', username: @account.acct)
end

def unsuspend
authorize @account, :unsuspend?
@account.unsuspend!
Admin::UnsuspensionWorker.perform_async(@account.id)
log_action :unsuspend, @account
redirect_to admin_account_path(@account.id)
redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.unsuspended_msg', username: @account.acct)
end

def redownload
Expand All @@ -65,7 +74,7 @@ def redownload
@account.update!(last_webfingered_at: nil)
ResolveAccountService.new.call(@account)

redirect_to admin_account_path(@account.id)
redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.redownloaded_msg', username: @account.acct)
end

def remove_avatar
Expand All @@ -76,7 +85,7 @@ def remove_avatar

log_action :remove_avatar, @account.user

redirect_to admin_account_path(@account.id)
redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.removed_avatar_msg', username: @account.acct)
end

def remove_header
Expand All @@ -87,7 +96,7 @@ def remove_header

log_action :remove_header, @account.user

redirect_to admin_account_path(@account.id)
redirect_to admin_account_path(@account.id), notice: I18n.t('admin.accounts.removed_header_msg', username: @account.acct)
end

private
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/api/base_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,12 @@ def require_authenticated_user!
def require_user!
if !current_user
render json: { error: 'This method requires an authenticated user' }, status: 422
elsif current_user.disabled?
render json: { error: 'Your login is currently disabled' }, status: 403
elsif !current_user.confirmed?
render json: { error: 'Your login is missing a confirmed e-mail address' }, status: 403
elsif !current_user.approved?
render json: { error: 'Your login is currently pending approval' }, status: 403
elsif !current_user.functional?
render json: { error: 'Your login is currently disabled' }, status: 403
else
set_user_activity
end
Expand Down
9 changes: 8 additions & 1 deletion app/controllers/api/v1/admin/accounts_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,13 @@ def approve

def reject
authorize @account.user, :reject?
SuspendAccountService.new.call(@account, reserve_email: false, reserve_username: false)
DeleteAccountService.new.call(@account, reserve_email: false, reserve_username: false)
render json: @account, serializer: REST::Admin::AccountSerializer
end

def destroy
authorize @account, :destroy?
Admin::AccountDeletionWorker.perform_async(@account.id)
render json: @account, serializer: REST::Admin::AccountSerializer
end

Expand All @@ -72,6 +78,7 @@ def unsilence
def unsuspend
authorize @account, :unsuspend?
@account.unsuspend!
Admin::UnsuspensionWorker.perform_async(@account.id)
log_action :unsuspend, @account
render json: @account, serializer: REST::Admin::AccountSerializer
end
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/settings/deletes_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def challenge_passed?

def destroy_account!
current_account.suspend!
Admin::SuspensionWorker.perform_async(current_user.account_id, true)
AccountDeletionWorker.perform_async(current_user.account_id)
sign_out
end
end
2 changes: 1 addition & 1 deletion app/lib/activitypub/activity/delete.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def perform

def delete_person
lock_or_return("delete_in_progress:#{@account.id}") do
SuspendAccountService.new.call(@account, reserve_username: false)
DeleteAccountService.new.call(@account, reserve_username: false)
end
end

Expand Down
16 changes: 9 additions & 7 deletions app/mailers/notification_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def mention(recipient, notification)
@me = recipient
@status = notification.target_status

return if @me.user.disabled? || @status.nil?
return unless @me.user.functional? && @status.present?

locale_for_account(@me) do
thread_by_conversation(@status.conversation)
Expand All @@ -22,7 +22,7 @@ def follow(recipient, notification)
@me = recipient
@account = notification.from_account

return if @me.user.disabled?
return unless @me.user.functional?

locale_for_account(@me) do
mail to: @me.user.email, subject: I18n.t('notification_mailer.follow.subject', name: @account.acct)
Expand All @@ -34,7 +34,7 @@ def favourite(recipient, notification)
@account = notification.from_account
@status = notification.target_status

return if @me.user.disabled? || @status.nil?
return unless @me.user.functional? && @status.present?

locale_for_account(@me) do
thread_by_conversation(@status.conversation)
Expand All @@ -47,7 +47,7 @@ def reblog(recipient, notification)
@account = notification.from_account
@status = notification.target_status

return if @me.user.disabled? || @status.nil?
return unless @me.user.functional? && @status.present?

locale_for_account(@me) do
thread_by_conversation(@status.conversation)
Expand All @@ -59,15 +59,15 @@ def follow_request(recipient, notification)
@me = recipient
@account = notification.from_account

return if @me.user.disabled?
return unless @me.user.functional?

locale_for_account(@me) do
mail to: @me.user.email, subject: I18n.t('notification_mailer.follow_request.subject', name: @account.acct)
end
end

def digest(recipient, **opts)
return if recipient.user.disabled?
return unless recipient.user.functional?

@me = recipient
@since = opts[:since] || [@me.user.last_emailed_at, (@me.user.current_sign_in_at + 1.day)].compact.max
Expand All @@ -88,8 +88,10 @@ def digest(recipient, **opts)

def thread_by_conversation(conversation)
return if conversation.nil?

msg_id = "<conversation-#{conversation.id}.#{conversation.created_at.strftime('%Y-%m-%d')}@#{Rails.configuration.x.local_domain}>"

headers['In-Reply-To'] = msg_id
headers['References'] = msg_id
headers['References'] = msg_id
end
end
28 changes: 14 additions & 14 deletions app/mailers/user_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def confirmation_instructions(user, token, **)
@token = token
@instance = Rails.configuration.x.local_domain

return if @resource.disabled?
return unless @resource.active_for_authentication?

I18n.with_locale(@resource.locale || I18n.default_locale) do
mail to: @resource.unconfirmed_email.presence || @resource.email,
Expand All @@ -29,7 +29,7 @@ def reset_password_instructions(user, token, **)
@token = token
@instance = Rails.configuration.x.local_domain

return if @resource.disabled?
return unless @resource.active_for_authentication?

I18n.with_locale(@resource.locale || I18n.default_locale) do
mail to: @resource.email, subject: I18n.t('devise.mailer.reset_password_instructions.subject')
Expand All @@ -40,7 +40,7 @@ def password_change(user, **)
@resource = user
@instance = Rails.configuration.x.local_domain

return if @resource.disabled?
return unless @resource.active_for_authentication?

I18n.with_locale(@resource.locale || I18n.default_locale) do
mail to: @resource.email, subject: I18n.t('devise.mailer.password_change.subject')
Expand All @@ -51,7 +51,7 @@ def email_changed(user, **)
@resource = user
@instance = Rails.configuration.x.local_domain

return if @resource.disabled?
return unless @resource.active_for_authentication?

I18n.with_locale(@resource.locale || I18n.default_locale) do
mail to: @resource.email, subject: I18n.t('devise.mailer.email_changed.subject')
Expand All @@ -62,7 +62,7 @@ def two_factor_enabled(user, **)
@resource = user
@instance = Rails.configuration.x.local_domain

return if @resource.disabled?
return unless @resource.active_for_authentication?

I18n.with_locale(@resource.locale || I18n.default_locale) do
mail to: @resource.email, subject: I18n.t('devise.mailer.two_factor_enabled.subject')
Expand All @@ -73,7 +73,7 @@ def two_factor_disabled(user, **)
@resource = user
@instance = Rails.configuration.x.local_domain

return if @resource.disabled?
return unless @resource.active_for_authentication?

I18n.with_locale(@resource.locale || I18n.default_locale) do
mail to: @resource.email, subject: I18n.t('devise.mailer.two_factor_disabled.subject')
Expand All @@ -84,7 +84,7 @@ def two_factor_recovery_codes_changed(user, **)
@resource = user
@instance = Rails.configuration.x.local_domain

return if @resource.disabled?
return unless @resource.active_for_authentication?

I18n.with_locale(@resource.locale || I18n.default_locale) do
mail to: @resource.email, subject: I18n.t('devise.mailer.two_factor_recovery_codes_changed.subject')
Expand All @@ -95,7 +95,7 @@ def webauthn_enabled(user, **)
@resource = user
@instance = Rails.configuration.x.local_domain

return if @resource.disabled?
return unless @resource.active_for_authentication?

I18n.with_locale(@resource.locale || I18n.default_locale) do
mail to: @resource.email, subject: I18n.t('devise.mailer.webauthn_enabled.subject')
Expand All @@ -106,7 +106,7 @@ def webauthn_disabled(user, **)
@resource = user
@instance = Rails.configuration.x.local_domain

return if @resource.disabled?
return unless @resource.active_for_authentication?

I18n.with_locale(@resource.locale || I18n.default_locale) do
mail to: @resource.email, subject: I18n.t('devise.mailer.webauthn_disabled.subject')
Expand All @@ -118,7 +118,7 @@ def webauthn_credential_added(user, webauthn_credential)
@instance = Rails.configuration.x.local_domain
@webauthn_credential = webauthn_credential

return if @resource.disabled?
return unless @resource.active_for_authentication?

I18n.with_locale(@resource.locale || I18n.default_locale) do
mail to: @resource.email, subject: I18n.t('devise.mailer.webauthn_credential.added.subject')
Expand All @@ -130,7 +130,7 @@ def webauthn_credential_deleted(user, webauthn_credential)
@instance = Rails.configuration.x.local_domain
@webauthn_credential = webauthn_credential

return if @resource.disabled?
return unless @resource.active_for_authentication?

I18n.with_locale(@resource.locale || I18n.default_locale) do
mail to: @resource.email, subject: I18n.t('devise.mailer.webauthn_credential.deleted.subject')
Expand All @@ -141,7 +141,7 @@ def welcome(user)
@resource = user
@instance = Rails.configuration.x.local_domain

return if @resource.disabled?
return unless @resource.active_for_authentication?

I18n.with_locale(@resource.locale || I18n.default_locale) do
mail to: @resource.email, subject: I18n.t('user_mailer.welcome.subject')
Expand All @@ -153,7 +153,7 @@ def backup_ready(user, backup)
@instance = Rails.configuration.x.local_domain
@backup = backup

return if @resource.disabled?
return unless @resource.active_for_authentication?

I18n.with_locale(@resource.locale || I18n.default_locale) do
mail to: @resource.email, subject: I18n.t('user_mailer.backup_ready.subject')
Expand Down Expand Up @@ -181,7 +181,7 @@ def sign_in_token(user, remote_ip, user_agent, timestamp)
@detection = Browser.new(user_agent)
@timestamp = timestamp.to_time.utc

return if @resource.disabled?
return unless @resource.active_for_authentication?

I18n.with_locale(@resource.locale || I18n.default_locale) do
mail to: @resource.email,
Expand Down
9 changes: 3 additions & 6 deletions app/models/account.rb
Original file line number Diff line number Diff line change
Expand Up @@ -222,23 +222,20 @@ def suspended?

def suspend!(date = Time.now.utc)
transaction do
user&.disable! if local?
create_deletion_request!
update!(suspended_at: date)
end
end

def unsuspend!
transaction do
user&.enable! if local?
deletion_request&.destroy!
update!(suspended_at: nil)
end
end

def memorialize!
transaction do
user&.disable! if local?
update!(memorial: true)
end
update!(memorial: true)
end

def sign?
Expand Down
20 changes: 20 additions & 0 deletions app/models/account_deletion_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

# == Schema Information
#
# Table name: account_deletion_requests
#
# id :bigint(8) not null, primary key
# account_id :bigint(8)
# created_at :datetime not null
# updated_at :datetime not null
#
class AccountDeletionRequest < ApplicationRecord
DELAY_TO_DELETION = 30.days.freeze

belongs_to :account

def due_at
created_at + DELAY_TO_DELETION
end
end
Loading

0 comments on commit 1a84b97

Please sign in to comment.