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
master
Eugen Rochko 5 years ago committed by GitHub
parent 00862dcaff
commit 3c033c4352
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 36
      app/controllers/admin/account_actions_controller.rb
  2. 1
      app/controllers/admin/account_moderation_notes_controller.rb
  3. 21
      app/controllers/admin/accounts_controller.rb
  4. 69
      app/controllers/admin/reports_controller.rb
  5. 27
      app/controllers/admin/silences_controller.rb
  6. 60
      app/controllers/admin/suspensions_controller.rb
  7. 58
      app/controllers/admin/warning_presets_controller.rb
  8. 7
      app/helpers/admin/action_logs_helper.rb
  9. 4
      app/javascript/images/icon_flag.svg
  10. BIN
      app/javascript/images/mailer/icon_warning.png
  11. 4
      app/javascript/styles/mailer.scss
  12. 4
      app/javascript/styles/mastodon/admin.scss
  13. 12
      app/mailers/user_mailer.rb
  14. 8
      app/models/account.rb
  15. 23
      app/models/account_warning.rb
  16. 15
      app/models/account_warning_preset.rb
  17. 134
      app/models/admin/account_action.rb
  18. 2
      app/models/concerns/account_associations.rb
  19. 7
      app/models/form/admin_suspension_confirmation.rb
  20. 4
      app/policies/account_policy.rb
  21. 19
      app/policies/account_warning_preset_policy.rb
  22. 26
      app/views/admin/account_actions/new.html.haml
  23. 6
      app/views/admin/account_warnings/_account_warning.html.haml
  24. 14
      app/views/admin/accounts/show.html.haml
  25. 17
      app/views/admin/reports/show.html.haml
  26. 25
      app/views/admin/suspensions/new.html.haml
  27. 11
      app/views/admin/warning_presets/edit.html.haml
  28. 30
      app/views/admin/warning_presets/index.html.haml
  29. 63
      app/views/user_mailer/warning.html.haml
  30. 9
      app/views/user_mailer/warning.text.erb
  31. 2
      app/views/user_mailer/welcome.text.erb
  32. 5
      config/locales/ar.yml
  33. 2
      config/locales/ast.yml
  34. 6
      config/locales/ca.yml
  35. 6
      config/locales/co.yml
  36. 6
      config/locales/cs.yml
  37. 6
      config/locales/cy.yml
  38. 6
      config/locales/da.yml
  39. 6
      config/locales/de.yml
  40. 6
      config/locales/el.yml
  41. 32
      config/locales/en.yml
  42. 5
      config/locales/eo.yml
  43. 6
      config/locales/es.yml
  44. 6
      config/locales/eu.yml
  45. 6
      config/locales/fa.yml
  46. 6
      config/locales/fr.yml
  47. 6
      config/locales/gl.yml
  48. 6
      config/locales/it.yml
  49. 6
      config/locales/ja.yml
  50. 6
      config/locales/ko.yml
  51. 6
      config/locales/nl.yml
  52. 6
      config/locales/oc.yml
  53. 6
      config/locales/pl.yml
  54. 6
      config/locales/pt-BR.yml
  55. 6
      config/locales/ru.yml
  56. 19
      config/locales/simple_form.en.yml
  57. 6
      config/locales/sk.yml
  58. 6
      config/locales/sr.yml
  59. 16
      config/routes.rb
  60. 12
      db/migrate/20181213184704_create_account_warnings.rb
  61. 9
      db/migrate/20181213185533_create_account_warning_presets.rb
  62. 21
      db/schema.rb
  63. 52
      spec/controllers/admin/accounts_controller_spec.rb
  64. 48
      spec/controllers/admin/reports_controller_spec.rb
  65. 33
      spec/controllers/admin/silences_controller_spec.rb
  66. 39
      spec/controllers/admin/suspensions_controller_spec.rb
  67. 5
      spec/fabricators/account_warning_fabricator.rb
  68. 3
      spec/fabricators/account_warning_preset_fabricator.rb
  69. 5
      spec/mailers/previews/user_mailer_preview.rb
  70. 5
      spec/models/account_warning_preset_spec.rb
  71. 5
      spec/models/account_warning_spec.rb
  72. 4
      spec/models/admin/account_action_spec.rb

@ -0,0 +1,36 @@
# frozen_string_literal: true
module Admin
class AccountActionsController < BaseController
before_action :set_account
def new
@account_action = Admin::AccountAction.new(type: params[:type], report_id: params[:report_id], send_email_notification: true)
@warning_presets = AccountWarningPreset.all
end
def create
account_action = Admin::AccountAction.new(resource_params)
account_action.target_account = @account
account_action.current_account = current_account
account_action.save!
if account_action.with_report?
redirect_to admin_report_path(account_action.report)
else
redirect_to admin_account_path(@account.id)
end
end
private
def set_account
@account = Account.find(params[:account_id])
end
def resource_params
params.require(:admin_account_action).permit(:type, :report_id, :warning_preset_id, :text, :send_email_notification)
end
end
end

@ -14,6 +14,7 @@ module Admin
else
@account = @account_moderation_note.target_account
@moderation_notes = @account.targeted_moderation_notes.latest
@warnings = @account.targeted_account_warnings.latest.custom
render template: 'admin/accounts/show'
end

@ -2,9 +2,9 @@
module Admin
class AccountsController < BaseController
before_action :set_account, only: [:show, :subscribe, :unsubscribe, :redownload, :remove_avatar, :remove_header, :enable, :disable, :memorialize]
before_action :set_account, only: [:show, :subscribe, :unsubscribe, :redownload, :remove_avatar, :remove_header, :enable, :memorialize]
before_action :require_remote_account!, only: [:subscribe, :unsubscribe, :redownload]
before_action :require_local_account!, only: [:enable, :disable, :memorialize]
before_action :require_local_account!, only: [:enable, :memorialize]
def index
authorize :account, :index?
@ -13,8 +13,10 @@ module Admin
def show
authorize @account, :show?
@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
end
def subscribe
@ -43,10 +45,17 @@ module Admin
redirect_to admin_account_path(@account.id)
end
def disable
authorize @account.user, :disable?
@account.user.disable!
log_action :disable, @account.user
def unsilence
authorize @account, :unsilence?
@account.unsilence!
log_action :unsilence, @account
redirect_to admin_account_path(@account.id)
end
def unsuspend
authorize @account, :unsuspend?
@account.unsuspend!
log_action :unsuspend, @account
redirect_to admin_account_path(@account.id)
end

@ -13,75 +13,42 @@ module Admin
authorize @report, :show?
@report_note = @report.notes.new
@report_notes = (@report.notes.latest + @report.history).sort_by(&:created_at)
@report_notes = (@report.notes.latest + @report.history + @report.target_account.targeted_account_warnings.latest.custom).sort_by(&:created_at)
@form = Form::StatusBatch.new
end
def update
def assign_to_self
authorize @report, :update?
process_report
if @report.action_taken?
redirect_to admin_reports_path, notice: I18n.t('admin.reports.resolved_msg')
else
@report.update!(assigned_account_id: current_account.id)
log_action :assigned_to_self, @report
redirect_to admin_report_path(@report)
end
end
private
def process_report
case params[:outcome].to_s
when 'assign_to_self'
@report.update!(assigned_account_id: current_account.id)
log_action :assigned_to_self, @report
when 'unassign'
def unassign
authorize @report, :update?
@report.update!(assigned_account_id: nil)
log_action :unassigned, @report
when 'reopen'
redirect_to admin_report_path(@report)
end
def reopen
authorize @report, :update?
@report.unresolve!
log_action :reopen, @report
when 'resolve'
@report.resolve!(current_account)
log_action :resolve, @report
when 'disable'
@report.resolve!(current_account)
@report.target_account.user.disable!
log_action :resolve, @report
log_action :disable, @report.target_account.user
redirect_to admin_report_path(@report)
end
resolve_all_target_account_reports
when 'silence'
def resolve
authorize @report, :update?
@report.resolve!(current_account)
@report.target_account.update!(silenced: true)
log_action :resolve, @report
log_action :silence, @report.target_account
resolve_all_target_account_reports
else
raise ActiveRecord::RecordNotFound
end
@report.reload
end
def resolve_all_target_account_reports
unresolved_reports_for_target_account.update_all(action_taken: true, action_taken_by_account_id: current_account.id)
redirect_to admin_reports_path, notice: I18n.t('admin.reports.resolved_msg')
end
def unresolved_reports_for_target_account
Report.where(
target_account: @report.target_account
).unresolved
end
private
def filtered_reports
ReportFilter.new(filter_params).results.order(id: :desc).includes(
:account,
:target_account
)
ReportFilter.new(filter_params).results.order(id: :desc).includes(:account, :target_account)
end
def filter_params

@ -1,27 +0,0 @@
# frozen_string_literal: true
module Admin
class SilencesController < BaseController
before_action :set_account
def create
authorize @account, :silence?
@account.update!(silenced: true)
log_action :silence, @account
redirect_to admin_accounts_path
end
def destroy
authorize @account, :unsilence?
@account.update!(silenced: false)
log_action :unsilence, @account
redirect_to admin_accounts_path
end
private
def set_account
@account = Account.find(params[:account_id])
end
end
end

@ -1,60 +0,0 @@
# frozen_string_literal: true
module Admin
class SuspensionsController < BaseController
before_action :set_account
def new
@suspension = Form::AdminSuspensionConfirmation.new(report_id: params[:report_id])
end
def create
authorize @account, :suspend?
@suspension = Form::AdminSuspensionConfirmation.new(suspension_params)
if suspension_params[:acct] == @account.acct
resolve_report! if suspension_params[:report_id].present?
perform_suspend!
mark_reports_resolved!
redirect_to admin_accounts_path
else
flash.now[:alert] = I18n.t('admin.suspensions.bad_acct_msg')
render :new
end
end
def destroy
authorize @account, :unsuspend?
@account.unsuspend!
log_action :unsuspend, @account
redirect_to admin_accounts_path
end
private
def set_account
@account = Account.find(params[:account_id])
end
def suspension_params
params.require(:form_admin_suspension_confirmation).permit(:acct, :report_id)
end
def resolve_report!
report = Report.find(suspension_params[:report_id])
report.resolve!(current_account)
log_action :resolve, report
end
def perform_suspend!
@account.suspend!
Admin::SuspensionWorker.perform_async(@account.id)
log_action :suspend, @account
end
def mark_reports_resolved!
Report.where(target_account: @account).unresolved.update_all(action_taken: true, action_taken_by_account_id: current_account.id)
end
end
end

@ -0,0 +1,58 @@
# frozen_string_literal: true
module Admin
class WarningPresetsController < BaseController
before_action :set_warning_preset, except: [:index, :create]
def index
authorize :account_warning_preset, :index?
@warning_presets = AccountWarningPreset.all
@warning_preset = AccountWarningPreset.new
end
def create
authorize :account_warning_preset, :create?
@warning_preset = AccountWarningPreset.new(warning_preset_params)
if @warning_preset.save
redirect_to admin_warning_presets_path
else
@warning_presets = AccountWarningPreset.all
render :index
end
end
def edit
authorize @warning_preset, :update?
end
def update
authorize @warning_preset, :update?
if @warning_preset.update(warning_preset_params)
redirect_to admin_warning_presets_path
else
render :edit
end
end
def destroy
authorize @warning_preset, :destroy?
@warning_preset.destroy!
redirect_to admin_warning_presets_path
end
private
def set_warning_preset
@warning_preset = AccountWarningPreset.find(params[:id])
end
def warning_preset_params
params.require(:account_warning_preset).permit(:text)
end
end
end

@ -23,6 +23,8 @@ module Admin::ActionLogsHelper
link_to record.domain, "https://#{record.domain}"
when 'Status'
link_to record.account.acct, TagManager.instance.url_for(record)
when 'AccountWarning'
link_to record.target_account.acct, admin_account_path(record.target_account_id)
end
end
@ -34,6 +36,7 @@ module Admin::ActionLogsHelper
link_to attributes['domain'], "https://#{attributes['domain']}"
when 'Status'
tmp_status = Status.new(attributes.except('reblogs_count', 'favourites_count'))
if tmp_status.account
link_to tmp_status.account&.acct || "##{tmp_status.account_id}", admin_account_path(tmp_status.account_id)
else
@ -81,6 +84,8 @@ module Admin::ActionLogsHelper
'envelope'
when 'Status'
'pencil'
when 'AccountWarning'
'warning'
end
end
@ -104,6 +109,6 @@ module Admin::ActionLogsHelper
private
def opposite_verbs?(log)
%w(DomainBlock EmailDomainBlock).include?(log.target_type)
%w(DomainBlock EmailDomainBlock AccountWarning).include?(log.target_type)
end
end

@ -0,0 +1,4 @@
<svg fill="#FFFFFF" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M14.4 6L14 4H5v17h2v-7h5.6l.4 2h7V6z"/>
</svg>

After

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

@ -426,6 +426,10 @@ h5 {
background: $success-green;
}
&.alert-icon td {
background: $error-red;
}
img {
max-width: 32px;
width: 32px;

@ -542,6 +542,10 @@ a.name-tag,
border-left-color: lighten($error-red, 12%);
}
&.warning {
border-left-color: $gold-star;
}
&__bubble {
padding: 16px;
padding-left: 14px;

@ -78,4 +78,16 @@ class UserMailer < Devise::Mailer
mail to: @resource.email, subject: I18n.t('user_mailer.backup_ready.subject')
end
end
def warning(user, warning)
@resource = user
@warning = warning
@instance = Rails.configuration.x.local_domain
I18n.with_locale(@resource.locale || I18n.default_locale) do
mail to: @resource.email,
subject: I18n.t("user_mailer.warning.subject.#{@warning.action}", acct: "@#{user.account.local_username_and_domain}"),
reply_to: Setting.site_contact_email
end
end
end

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

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

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

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

@ -9,6 +9,10 @@ class AccountPolicy < ApplicationPolicy
staff?
end
def warn?
staff? && !record.user&.staff?
end
def suspend?
staff? && !record.user&.staff?
end

@ -0,0 +1,19 @@
# frozen_string_literal: true
class AccountWarningPresetPolicy < ApplicationPolicy
def index?
staff?
end
def create?
staff?
end
def update?
staff?
end
def destroy?
staff?
end
end

@ -0,0 +1,26 @@
- content_for :page_title do
= t('admin.account_actions.title', acct: @account.acct)
= simple_form_for @account_action, url: admin_account_action_path(@account.id) do |f|
= f.input :report_id, as: :hidden
.fields-group
= f.input :type, collection: Admin::AccountAction.types_for_account(@account), include_blank: false, wrapper: :with_block_label, label_method: ->(type) { I18n.t("simple_form.labels.admin_account_action.types.#{type}")}, hint: t('simple_form.hints.admin_account_action.type_html', acct: @account.acct)
- if @account.local?
%hr.spacer/
.fields-group
= f.input :send_email_notification, as: :boolean, wrapper: :with_label
%hr.spacer/
- unless @warning_presets.empty?
.fields-group
= f.input :warning_preset_id, collection: @warning_presets, label_method: :text, wrapper: :with_block_label
.fields-group
= f.input :text, as: :text, wrapper: :with_block_label, hint: t('simple_form.hints.admin_account_action.text_html', path: admin_warning_presets_path)
.actions
= f.button :button, t('admin.account_actions.action'), type: :submit

@ -0,0 +1,6 @@
.speech-bubble.warning
.speech-bubble__bubble
= Formatter.instance.linkify(account_warning.text)
.speech-bubble__owner
= admin_account_link_to account_warning.account
%time.formatted{ datetime: account_warning.created_at.iso8601 }= l account_warning.created_at

@ -64,7 +64,7 @@
= table_link_to 'unlock', t('admin.accounts.enable'), enable_admin_account_path(@account.id), method: :post if can?(:enable, @account.user)
- else
= t('admin.accounts.enabled')
= table_link_to 'lock', t('admin.accounts.disable'), disable_admin_account_path(@account.id), method: :post if can?(:disable, @account.user)
= table_link_to 'lock', t('admin.accounts.disable'), new_admin_account_action_path(@account.id, type: 'disable') if can?(:disable, @account.user)
%tr
%th= t('admin.accounts.most_recent_ip')
%td= @account.user_current_sign_in_ip
@ -119,18 +119,18 @@
%div{ style: 'float: left' }
- if @account.silenced?
= link_to t('admin.accounts.undo_silenced'), admin_account_silence_path(@account.id), method: :delete, class: 'button' if can?(:unsilence, @account)
= link_to t('admin.accounts.undo_silenced'), unsilence_admin_account_path(@account.id), method: :post, class: 'button' if can?(:unsilence, @account)
- else
= link_to t('admin.accounts.silence'), admin_account_silence_path(@account.id), method: :post, class: 'button button--destructive' if can?(:silence, @account)
= link_to t('admin.accounts.silence'), new_admin_account_action_path(@account.id, type: 'silence'), class: 'button button--destructive' if can?(:silence, @account)
- if @account.local?
- unless @account.user_confirmed?
= link_to t('admin.accounts.confirm'), admin_account_confirmation_path(@account.id), method: :post, class: 'button' if can?(:confirm, @account.user)
- if @account.suspended?
= link_to t('admin.accounts.undo_suspension'), admin_account_suspension_path(@account.id), method: :delete, class: 'button' if can?(:unsuspend, @account)
= link_to t('admin.accounts.undo_suspension'), unsuspend_admin_account_path(@account.id), method: :post, class: 'button' if can?(:unsuspend, @account)
- else
= link_to t('admin.accounts.perform_full_suspension'), new_admin_account_suspension_path(@account.id), class: 'button button--destructive' if can?(:suspend, @account)
= link_to t('admin.accounts.perform_full_suspension'), new_admin_account_action_path(@account.id, type: 'suspend'), class: 'button button--destructive' if can?(:suspend, @account)
- if !@account.local? && @account.hub_url.present?
%hr.spacer/
@ -184,6 +184,10 @@
%hr.spacer/
= render @warnings
%hr.spacer/
= render @moderation_notes
= simple_form_for @account_moderation_note, url: admin_account_moderation_notes_path do |f|

@ -8,13 +8,14 @@
- if @report.unresolved?
%div{ style: 'float: right' }
- if @report.target_account.local?
= link_to t('admin.accounts.disable'), admin_report_path(@report, outcome: 'disable'), method: :put, class: 'button button--destructive'
= link_to t('admin.accounts.silence'), admin_report_path(@report, outcome: 'silence'), method: :put, class: 'button button--destructive'
= link_to t('admin.accounts.perform_full_suspension'), new_admin_account_suspension_path(@report.target_account_id, report_id: @report.id), class: 'button button--destructive'
= link_to t('admin.accounts.warn'), new_admin_account_action_path(@report.target_account_id, type: 'none', report_id: @report.id), class: 'button'
= link_to t('admin.accounts.disable'), new_admin_account_action_path(@report.target_account_id, type: 'disable', report_id: @report.id), class: 'button button--destructive'
= link_to t('admin.accounts.silence'), new_admin_account_action_path(@report.target_account_id, type: 'silence', report_id: @report.id), class: 'button button--destructive'
= link_to t('admin.accounts.perform_full_suspension'), new_admin_account_action_path(@report.target_account_id, type: 'suspend', report_id: @report.id), class: 'button button--destructive'
%div{ style: 'float: left' }
= link_to t('admin.reports.mark_as_resolved'), admin_report_path(@report, outcome: 'resolve'), method: :put, class: 'button'
= link_to t('admin.reports.mark_as_resolved'), resolve_admin_report_path(@report), method: :post, class: 'button'
- else
= link_to t('admin.reports.mark_as_unresolved'), admin_report_path(@report, outcome: 'reopen'), method: :put, class: 'button'
= link_to t('admin.reports.mark_as_unresolved'), reopen_admin_report_path(@report), method: :post, class: 'button'
%hr.spacer
@ -67,10 +68,10 @@
= admin_account_link_to @report.assigned_account
%td
- if @report.assigned_account != current_user.account
= table_link_to 'user', t('admin.reports.assign_to_self'), admin_report_path(@report, outcome: 'assign_to_self'), method: :put
= table_link_to 'user', t('admin.reports.assign_to_self'), assign_to_self_admin_report_path(@report), method: :post
%td
- if !@report.assigned_account.nil?
= table_link_to 'trash', t('admin.reports.unassign'), admin_report_path(@report, outcome: 'unassign'), method: :put
= table_link_to 'trash', t('admin.reports.unassign'), unassign_admin_report_path(@report), method: :post
%hr.spacer
@ -104,7 +105,7 @@
- @report_notes.each do |item|
- if item.is_a?(Admin::ActionLog)
= render partial: 'action_log', locals: { action_log: item }
- elsif item.is_a?(ReportNote)
- else
= render item
= simple_form_for @report_note, url: admin_report_notes_path do |f|

@ -1,25 +0,0 @@
- content_for :page_title do
= t('admin.suspensions.title', acct: @account.acct)
= simple_form_for @suspension, url: admin_account_suspension_path(@account.id), method: :post do |f|
%p.hint= t('admin.suspensions.warning_html')
.fields-group
%ul
%li.negative-hint
= number_to_human @account.statuses_count, strip_insignificant_zeros: true
= t('accounts.posts', count: @account.statuses_count)
%li.negative-hint
= number_to_human @account.following_count, strip_insignificant_zeros: true
= t('accounts.following', count: @account.following_count)
%li.negative-hint
= number_to_human @account.followers_count, strip_insignificant_zeros: true
= t('accounts.followers', count: @account.followers_count)
%p.hint= t('admin.suspensions.hint_html', value: content_tag(:code, @account.acct))
= f.input :acct
= f.input_field :report_id, as: :hidden
.actions
= f.button :button, t('admin.suspensions.proceed'), type: :submit, class: 'negative'

@ -0,0 +1,11 @@
- content_for :page_title do
= t('admin.warning_presets.edit_preset')
= simple_form_for @warning_preset, url: admin_warning_preset_path(@warning_preset) do |f|
= render 'shared/error_messages', object: @warning_preset
.fields-group
= f.input :text, wrapper: :with_block_label
.actions
= f.button :button, t('generic.save_changes'), type: :submit

@ -0,0 +1,30 @@
- content_for :page_title do
= t('admin.warning_presets.title')
- if can? :create, :account_warning_preset
= simple_form_for @warning_preset, url: admin_warning_presets_path do |f|
= render 'shared/error_messages', object: @warning_preset
.fields-group
= f.input :text, wrapper: :with_block_label
.actions
= f.button :button, t('admin.warning_presets.add_new'), type: :submit
%hr.spacer/
- unless @warning_presets.empty?
.table-wrapper
%table.table
%thead
%tr
%th= t('simple_form.labels.account_warning_preset.text')
%th
%tbody
- @warning_presets.each do |preset|
%tr
%td
= Formatter.instance.linkify(preset.text)
%td
= table_link_to 'pencil', t('admin.warning_presets.edit'), edit_admin_warning_preset_path(preset)
= table_link_to 'trash', t('admin.warning_presets.delete'), admin_warning_preset_path(preset), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') }

@ -0,0 +1,63 @@
%table.email-table{ cellspacing: 0, cellpadding: 0 }
%tbody
%tr
%td.email-body
.email-container
%table.content-section{ cellspacing: 0, cellpadding: 0 }
%tbody
%tr
%td.content-cell.hero
.email-row
.col-6
%table.column{ cellspacing: 0, cellpadding: 0 }
%tbody
%tr
%td.column-cell.text-center.padded
%table.hero-icon.alert-icon{ align: 'center', cellspacing: 0, cellpadding: 0 }
%tbody
%tr
%td
= image_tag full_pack_url('icon_warning.png'), alt: ''
%h1= t "user_mailer.warning.title.#{@warning.action}"
%table.email-table{ cellspacing: 0, cellpadding: 0 }
%tbody
%tr
%td.email-body
.email-container
%table.content-section{ cellspacing: 0, cellpadding: 0 }
%tbody
%tr
%td.content-cell.content-start
.email-row
.col-6
%table.column{ cellspacing: 0, cellpadding: 0 }
%tbody
%tr
%td.column-cell.text-center
- unless @warning.none_action?
%p= t "user_mailer.warning.explanation.#{@warning.action}"
- unless @warning.text.blank?
= Formatter.instance.linkify(@warning.text)
%table.email-table{ cellspacing: 0, cellpadding: 0 }
%tbody
%tr
%td.email-body
.email-container
%table.content-section{ cellspacing: 0, cellpadding: 0 }
%tbody
%tr
%td.content-cell
%table.column{ cellspacing: 0, cellpadding: 0 }
%tbody
%tr
%td.column-cell.button-cell
%table.button{ align: 'center', cellspacing: 0, cellpadding: 0 }
%tbody
%tr
%td.button-primary
= link_to about_more_url do
%span= t 'user_mailer.warning.review_server_policies'

@ -0,0 +1,9 @@
<%= t "user_mailer.warning.title.#{@warning.action}" %>
===
<% unless @warning.none_action? %>
<%= t "user_mailer.warning.explanation.#{@warning.action}" %>
<% end %>
<%= @warning.text %>

@ -2,7 +2,7 @@
===
<%= t 'user_mailer.welcome.full_handle' %> (<%= "@#{@resource.account.username}@#{@instance}" %>)
<%= t 'user_mailer.welcome.full_handle' %> (<%= "@#{@resource.account.local_username_and_domain}" %>)
<%= t 'user_mailer.welcome.full_handle_hint', instance: @instance %>
---

@ -455,11 +455,6 @@ ar:
last_delivery: آخر إيداع
title: WebSub
topic: الموضوع
suspensions:
bad_acct_msg: قيمة التأكيد غير متطابقة. متأكد مِن أنك بصدد تعليق الحساب الصحيح؟
hint_html: 'لتأكيد إجراء تعليق الحساب، يُرجى إدخال %{value} في الحقل التالي:'
proceed: مواصلة
title: تعليق الحساب %{acct}
tags:
accounts: الحسابات
hidden: المخفية

@ -121,8 +121,6 @@ ast:
failed_to_execute: Fallu al executar
subscriptions:
title: WebSub
suspensions:
warning_html: 'El suspender esta cuenta va desaniciar <strong>de mou irreversible</strong> los sos datos qu''inclúin:'
title: Alministración
admin_mailer:
new_report:

@ -439,12 +439,6 @@ ca:
last_delivery: Últim lliurament
title: WebSub
topic: Tema
suspensions:
bad_acct_msg: El valor de confirmació no s'ha trobat. Estàs suspenen el compte correcte?
hint_html: 'Per confirmar la suspensió del compte, introdueix %{value} al camp següent:'
proceed: Procedeix
title: Suspèn %{acct}
warning_html: 'Suspenen aquest compte esborrarà <strong>irreversiblement</strong> les dades del compte, incloent:'
tags:
accounts: Comptes
hidden: Amagat

@ -439,12 +439,6 @@ co:
last_delivery: Ultima arricata
title: WebSub
topic: Sughjettu
suspensions:
bad_acct_msg: U valore di cunfirmazione ùn era micca curretta. Site sicuru·a di suspende u bonu contu?
hint_html: 'Per cunfirmà a suspensione di u contu, entrate %{value} quì sottu:'
proceed: Cuntinuà
title: Suspende %{acct}
warning_html: 'A suspensione di u contu sguasserà di manera <strong>irreversibile</strong> i so dati, cum''è:'
tags:
accounts: Conti
hidden: Piattatu

@ -444,12 +444,6 @@ cs:
last_delivery: Poslední doručení
title: WebSub
topic: Téma
suspensions:
bad_acct_msg: Hodnota pro potvrzení neodpovídá. Suspendujete správný účet?
hint_html: 'Pro potvrzení suspenzace účtu prosím zadejte do pole níže %{value}:'
proceed: Pokračovat
title: Suspendovat účet %{acct}
warning_html: 'Suspenzace tohoto účtu <strong>nenávratně</strong> smaže z tohoto účtu data, včetně:'
tags:
accounts: Účty
hidden: Skryté

@ -423,12 +423,6 @@ cy:
last_delivery: Danfoniad diwethaf
title: WebSub
topic: Pwnc
suspensions:
bad_acct_msg: Nid yw'r gwerthoedd cadarnhau yn cyfateb. Ydych chi'n atal y cyfrif cywir?
hint_html: 'I gadarnhau atal y cyfrif, mewnbynwch %{value} yn y maes isod:'
proceed: Parhau
title: Atal %{acct}
warning_html: 'Mi fydd atal y cyfrif hwn yn dileu data <strong>am byth</strong> o''r cyfrif hwn, gan gynnwys:'
title: Gweinyddiaeth
admin_mailer:
new_report:

@ -427,12 +427,6 @@ da:
last_delivery: Sidste levering
title: Websub
topic: Emne
suspensions:
bad_acct_msg: Bekræftelsværdien stemte ikke overens. Er du ved at udelukke den rigtige konto?
hint_html: 'For at bekræfte udelukkelsen af kontoen, indtast venligst %{value} i nedenstående felt:'
proceed: Fortsæt
title: Udeluk %{acct}
warning_html: 'Udelukkelse af denne konto vil <strong>uigenkaldeligt</strong> slette al data fra denne konto, hvilket indebærer:'
title: Administration
admin_mailer:
new_report:

@ -439,12 +439,6 @@ de:
last_delivery: Letzte Zustellung
title: WebSub
topic: Thema
suspensions:
bad_acct_msg: Der Bestätigungswert stimmt nicht überein. Sperrst du das richtige Benutzerkonto?
hint_html: 'Um die Sperrung des Benutzerkontos zu genehmigen tippe %{value} in das Feld unten ein:'
proceed: Fortfahren
title: "%{acct} sperren"
warning_html: 'Die Sperrung des Benutzerkontos wird <strong>unwiederrufliche</strong> Schäden hervorrufen und alle Daten löschen, die folgendes beinhalten:'
tags:
accounts: Konten
hidden: Versteckt

@ -439,12 +439,6 @@ el:
last_delivery: Τελευταία παράδοση
title: WebSub
topic: Θέμα
suspensions:
bad_acct_msg: Η τιμή επιβεβαίωσης δεν ταιριάζει. Σίγουρα αναστέλλεις το σωστό λογαριασμό;
hint_html: 'Για να επιβεβαιώσεις την αναστολή του λογαριασμού, γράψε %{value} στο ακόλουθο πεδίο:'
proceed: Συνέχεια
title: Αναστολή %{acct}
warning_html: 'Αναστέλλοντας αυτό το λογαριασμό θα διαγραφούν <strong>αμετάκλητα</strong> δεδομένα του, μεταξύ των οποίων:'
tags:
accounts: Λογαριασμοί
hidden: Κρυμμένες

@ -70,6 +70,9 @@ en:
moderator: Mod
unfollow: Unfollow
admin:
account_actions:
action: Perform action
title: Perform moderation action on %{acct}
account_moderation_notes:
create: Leave note
created_msg: Moderation note successfully created!
@ -173,6 +176,7 @@ en:
assigned_to_self_report: "%{name} assigned report %{target} to themselves"
change_email_user: "%{name} changed the e-mail address of user %{target}"
confirm_user: "%{name} confirmed e-mail address of user %{target}"
create_account_warning: "%{name} sent a warning to %{target}"
create_custom_emoji: "%{name} uploaded new emoji %{target}"
create_domain_block: "%{name} blocked domain %{target}"
create_email_domain_block: "%{name} blacklisted e-mail domain %{target}"
@ -441,12 +445,6 @@ en:
last_delivery: Last delivery
title: WebSub
topic: Topic
suspensions:
bad_acct_msg: The confirmation value didn't match up. Are you suspending the right account?
hint_html: 'To confirm the suspension of the account, please enter %{value} into the field below:'
proceed: Proceed
title: Suspend %{acct}
warning_html: 'Suspending this account will <strong>irreversibly</strong> delete data from this account, which includes:'
tags:
accounts: Accounts
hidden: Hidden
@ -456,6 +454,12 @@ en:
unhide: Show in directory
visible: Visible
title: Administration
warning_presets:
add_new: Add new
delete: Delete
edit: Edit
edit_preset: Edit warning preset
title: Manage warning presets
admin_mailer:
new_report:
body: "%{reporter} has reported %{target}"
@ -922,6 +926,22 @@ en:
explanation: You requested a full backup of your Mastodon account. It's now ready for download!
subject: Your archive is ready for download
title: Archive takeout
warning:
explanation:
disable: While your account is frozen, your account data remains intact, but you cannot perform any actions until it is unlocked.
silence: While your account is limited, only people who are already following you will see your toots on this server, and you may be excluded from various public listings. However, others may still manually follow you.
suspend: Your account has been suspended, and all of your toots and your uploaded media files have been irreversibly removed from this server, and servers where you had followers.
review_server_policies: Review server policies
subject:
disable: Your account %{acct} has been frozen
none: Warning for %{acct}
silence: Your account %{acct} has been limited
suspend: Your account %{acct} has been suspended
title:
disable: Account frozen
none: Warning
silence: Account limited
suspend: Account suspended
welcome:
edit_profile_action: Setup profile
edit_profile_step: You can customize your profile by uploading an avatar, header, changing your display name and more. If you’d like to review new followers before they’re allowed to follow you, you can lock your account.

@ -427,11 +427,6 @@ eo:
last_delivery: Lasta livero
title: WebSub
topic: Temo
suspensions:
hint_html: 'Por konformi la haltigo de la konto, bonvolu enigi %{value} en la kampo sube:'
proceed: Daŭrigita
title: Haltigi %{acct}
warning_html: 'Haltigi ĉi tiu konton forigos <strong>senrevene</strong> datumojn de ĉi tiu konto, inklusive de:'
title: Administrado
admin_mailer:
new_report:

@ -433,12 +433,6 @@ es:
last_delivery: Última entrega
title: WebSub
topic: Tópico
suspensions:
bad_acct_msg: El valor de confirmación no cuadra. ¿Estás suspendiendo la cuenta correcta?
hint_html: 'Para confirmar las suspensión de la cuenta, por favor introduce %{value} en el campo de abajo:'
proceed: Proceder
title: Suspender %{acct}
warning_html: 'Suspender esta cuenta borrará <strong>irreversiblemente</strong> los datos de stra cuenta que incluyen:'
title: Administración
admin_mailer:
new_report:

@ -435,12 +435,6 @@ eu:
last_delivery: Azken bidalketa
title: WebSub
topic: Mintzagaia
suspensions:
bad_acct_msg: Berrespen balioa ez dator bat. Dagokion kontua kanporatzen ari zara?
hint_html: 'Kontuaren kanporatzea berresteko, sartu %{value} beheko eremuan:'
proceed: Jarraitu
title: Kanporatu %{acct}
warning_html: 'Kontu hau kanporatzeak <strong>behin betiko</strong> ezabatuko ditu kontu honetako datuak, hauek barne:'
tags:
accounts: Kontuak
hidden: Ezkutatuta

@ -433,12 +433,6 @@ fa:
last_delivery: آخرین ارسال
title: WebSub
topic: موضوع
suspensions:
bad_acct_msg: محتوایی که برای تأیید وارد کردید منطبق نبود. آیا دارید حساب درستی را معلق میکنید؟
hint_html: 'برای تأیید معلقکردن حساب، لطفاً در کادر زیر %{value} را وارد کنید:'
proceed: ادامه
title: معلقکردن %{acct}
warning_html: 'معلقکردن این حساب <strong>برای همیشه</strong> دادههایش را پاک میکند. دادههایی شامل:'
title: مدیریت سرور
admin_mailer:
new_report:

@ -439,12 +439,6 @@ fr:
last_delivery: Dernière livraison
title: WebSub
topic: Sujet
suspensions:
bad_acct_msg: La valeur de confirmation n'a pas correspondu. Êtes-vous certain de suspendre le bon compte ?
hint_html: 'Pour confirmer la suspension du compte, veuillez entrer %{value} dans le champ ci-dessous :'
proceed: Confirmer
title: Suspension de %{acct}
warning_html: 'Suspendre ce compte effacera <strong>irréversiblement</strong> les données de ce compte, ce qui inclut :'
tags:
accounts: Comptes
hidden: Masqué

@ -439,12 +439,6 @@ gl:
last_delivery: Última entrega
title: WebSub
topic: Asunto
suspensions:
bad_acct_msg: O valor de confirmación non é coincidente. Está a suspender a conta correcta?
hint_html: 'Para confirmar a suspensión da conta introduza %{value} no campo inferior:'
proceed: Proceder
title: Suspender %{acct}
warning_html: 'Ao suspender esta conta eliminará <strong>de xeito irreversible</strong> os datos de esta conta, que inclúe:'
tags:
accounts: Contas
hidden: Ocultas

@ -429,12 +429,6 @@ it:
confirmed: Confermato
expires_in: Scade in
topic: Argomento
suspensions:
bad_acct_msg: Il valore di conferma non corrisponde. Stai sospendendo l'account giusto?
hint_html: 'Per confermare la sospensione dell''account, inserisci %{value} nel campo qui sotto:'
proceed: Continua
title: Sospendi %{acct}
warning_html: 'La sospensione dell''account comporta la cancellazione <strong>irreversibile</strong> dei suoi dati, che comprendono:'
title: Amministrazione
application_mailer:
notification_preferences: Cambia preferenze email

@ -441,12 +441,6 @@ ja:
last_delivery: 最終配送
title: WebSub
topic: トピック
suspensions:
bad_acct_msg: 値が一致しませんでした。停止しようとしているアカウントに間違いはありませんか?
hint_html: 'アカウントの停止を確認するには、以下のフィールドに %{value} と入力してください:'
proceed: 完全に活動停止させる
title: "%{acct} を停止"
warning_html: 'このアカウントを停止すると、このアカウントから次のようなデータが<strong>不可逆的に</strong>削除されます:'
tags:
accounts: アカウント
hidden: 非表示

@ -441,12 +441,6 @@ ko:
last_delivery: 최종 발송
title: WebSub
topic: 토픽
suspensions:
bad_acct_msg: 확인값이 일치하지 않습니다. 정지하려는 계정이 맞습니까?
hint_html: '이 계정을 정지하려면 %{value}를 아래 입력칸에 입력하세요:'
proceed: 완전히 정지시키기
title: "%{acct} 정지하기"
warning_html: '이 계정을 정지하면 계정의 데이터를 모두 삭제하며 <strong>되돌릴 수 없습니다</strong>. 이것은 다음을 포함합니다:'
tags:
accounts: 계정들
hidden: 숨겨짐

@ -439,12 +439,6 @@ nl:
last_delivery: Laatste bezorging
title: WebSub
topic: Account
suspensions:
bad_acct_msg: De bevestigingswaarde kwam niet overeen. Schort je wel het juiste account op?
hint_html: Vul in het veld hieronder %{value} in, om het opschorten van dit account te bevestigen.
proceed: Ga verder
title: "%{acct} opschorten"
warning_html: 'Door het opschorten van dit account worden gegevens van dit account <strong>permanent</strong> verwijderd, waaronder:'
tags:
accounts: Accounts
hidden: Verborgen

@ -439,12 +439,6 @@ oc:
last_delivery: Darrièra distribucion
title: WebSub
topic: Subjècte
suspensions:
bad_acct_msg: La valor de confirmacion a pas coïncidit. Sètz a suspendre lo bon compte?
hint_html: 'Per confirmar la suspension del compte, picatz %{value} al camp çai-jos :'
proceed: Tractat
title: Suspension de %{acct}
warning_html: 'Suspendre aqueste compte suprimirà <strong>irreversiblament</strong> las donadas del compte, aquò compren:'
tags:
accounts: Comptes
hidden: Amagat

@ -445,12 +445,6 @@ pl:
last_delivery: Ostatnio doręczono
title: WebSub
topic: Temat
suspensions:
bad_acct_msg: Zawartość potwierdzenia nie zgadza się. Czy próbujesz zawiesić właściwe konto?
hint_html: 'Aby potwierdzić zawieszenie konta, wprowadź %{value} w poniższe pole:'
proceed: Przejdź
title: Zawieś %{acct}
warning_html: 'Zawieszenie konta będzie skutkowało <strong>nieodwracalnym</strong> usunięciem danych z tego konta, wliczając:'
tags:
accounts: Konta
hidden: Ukryte

@ -439,12 +439,6 @@ pt-BR:
last_delivery: Última entrega
title: WebSub
topic: Tópico
suspensions:
bad_acct_msg: Os valores de confirmação não correspondem. Você está suspendendo a conta certa?
hint_html: 'Para confirmar a suspensão da conta, por favor digite %{value} no campo abaixo:'
proceed: Prosseguir
title: Suspender %{acct}
warning_html: 'Suspender essa conta vai remover <strong>irreversivelmente</strong> dados dessa conta, o que inclui:'
tags:
accounts: Contas
hidden: Escondido

@ -427,12 +427,6 @@ ru:
last_delivery: Последняя доставка
title: WebSub
topic: Тема
suspensions:
bad_acct_msg: Не удалось найти такое число подтверждения. Вы уверены, что замораживаете нужный аккаунт?
hint_html: 'Чтобы подтвердить заморозку аккаунта, пожалуйста, введите %{value} в поле ниже:'
proceed: Продолжить
title: Заморозить %{acct}
warning_html: 'Заморозка этого аккаунта приведёт к <strong>необратимому</strong> удалению данных с этого аккаунта, включая:'
title: Администрирование
admin_mailer:
new_report:

@ -2,6 +2,13 @@
en:
simple_form:
hints:
account_warning_preset:
text: You can use toot syntax, such as URLs, hashtags and mentions
admin_account_action:
send_email_notification: The user will receive an explanation of what happened with their account
text_html: Optional. You can use toot syntax. You can <a href="%{path}">add warning presets</a> to save time
type_html: Choose what to do with <strong>%{acct}</strong>
warning_preset_id: Optional. You can still add custom text to end of the preset
defaults:
autofollow: People who sign up through the invite will automatically follow you
avatar: PNG, GIF or JPG. At most %{size}. Will be downscaled to %{dimensions}px
@ -40,6 +47,18 @@ en:
fields:
name: Label
value: Content
account_warning_preset:
text: Preset text
admin_account_action:
send_email_notification: Notify the user per e-mail
text: Custom warning
type: Action
types:
disable: Disable
none: Do nothing
silence: Silence
suspend: Suspend and irreversibly delete account data
warning_preset_id: Use a warning preset
defaults:
autofollow: Invite to follow your account
avatar: Avatar

@ -444,12 +444,6 @@ sk:
last_delivery: Posledné doručenie
title: WebSub
topic: Téma
suspensions:
bad_acct_msg: Hodnota pre potvrdenie sa nezhoduje. Si si istý/á že zamrazuješ ten správny účet?
hint_html: 'Pre potvrdenie zamrazenia účtu, prosím napíš %{value} do následujúceho políčka:'
proceed: Pokračuj
title: Zamraziť %{acct}
warning_html: 'Zamrazením tohto účtu budú dáta na tomto účte <strong>nenávratne</strong> zmazané, zahŕňajúc:'
tags:
accounts: Účty
hidden: Skryté

@ -443,12 +443,6 @@ sr:
last_delivery: Последња достава
title: WebSub
topic: Topic
suspensions:
bad_acct_msg: Вредност потврде се не поклапа. Да ли суспендујете прави рачун?
hint_html: 'Да бисте потврдили суспензију налога, унесите %{value} у поље испод:'
proceed: Настави
title: Суспендуј %{acct}
warning_html: 'Суспендовање овог налога ће <strong>неповратно</strong>избрисати све податке са овог налога, који укључују:'
title: Администрација
admin_mailer:
new_report:

@ -139,6 +139,7 @@ Rails.application.routes.draw do
resources :domain_blocks, only: [:index, :new, :create, :show, :destroy]
resources :email_domain_blocks, only: [:index, :new, :create, :destroy]
resources :action_logs, only: [:index]
resources :warning_presets, except: [:new]
resource :settings, only: [:edit, :update]
resources :invites, only: [:index, :create, :destroy] do
@ -160,7 +161,14 @@ Rails.application.routes.draw do
end
end
resources :reports, only: [:index, :show, :update] do
resources :reports, only: [:index, :show] do
member do
post :assign_to_self
post :unassign
post :reopen
post :resolve
end
resources :reported_statuses, only: [:create]
end
@ -171,7 +179,8 @@ Rails.application.routes.draw do
post :subscribe
post :unsubscribe
post :enable
post :disable
post :unsilence
post :unsuspend
post :redownload
post :remove_avatar
post :remove_header
@ -180,8 +189,7 @@ Rails.application.routes.draw do
resource :change_email, only: [:show, :update]
resource :reset, only: [:create]
resource :silence, only: [:create, :destroy]
resource :suspension, only: [:new, :create, :destroy]
resource :action, only: [:new, :create], controller: 'account_actions'
resources :statuses, only: [:index, :create, :update, :destroy]
resource :confirmation, only: [:create] do

@ -0,0 +1,12 @@
class CreateAccountWarnings < ActiveRecord::Migration[5.2]
def change
create_table :account_warnings do |t|
t.belongs_to :account, foreign_key: { on_delete: :nullify }
t.belongs_to :target_account, foreign_key: { to_table: 'accounts', on_delete: :cascade }
t.integer :action, null: false, default: 0
t.text :text, null: false, default: ''
t.timestamps
end
end
end

@ -0,0 +1,9 @@
class CreateAccountWarningPresets < ActiveRecord::Migration[5.2]
def change
create_table :account_warning_presets do |t|
t.text :text, null: false, default: ''
t.timestamps
end
end
end

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2018_12_07_011115) do
ActiveRecord::Schema.define(version: 2018_12_13_185533) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -76,6 +76,23 @@ ActiveRecord::Schema.define(version: 2018_12_07_011115) do
t.index ["tag_id"], name: "index_account_tag_stats_on_tag_id", unique: true
end
create_table "account_warning_presets", force: :cascade do |t|
t.text "text", default: "", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "account_warnings", force: :cascade do |t|
t.bigint "account_id"
t.bigint "target_account_id"
t.integer "action", default: 0, null: false
t.text "text", default: "", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["account_id"], name: "index_account_warnings_on_account_id"
t.index ["target_account_id"], name: "index_account_warnings_on_target_account_id"
end
create_table "accounts", force: :cascade do |t|
t.string "username", default: "", null: false
t.string "domain"
@ -656,6 +673,8 @@ ActiveRecord::Schema.define(version: 2018_12_07_011115) do
add_foreign_key "account_pins", "accounts", on_delete: :cascade
add_foreign_key "account_stats", "accounts", on_delete: :cascade
add_foreign_key "account_tag_stats", "tags", on_delete: :cascade
add_foreign_key "account_warnings", "accounts", column: "target_account_id", on_delete: :cascade
add_foreign_key "account_warnings", "accounts", on_delete: :nullify
add_foreign_key "accounts", "accounts", column: "moved_to_account_id", on_delete: :nullify
add_foreign_key "admin_action_logs", "accounts", on_delete: :cascade
add_foreign_key "backups", "users", on_delete: :nullify

@ -191,58 +191,6 @@ RSpec.describe Admin::AccountsController, type: :controller do
end
end
describe 'POST #disable' do
subject { post :disable, params: { id: account.id } }
let(:current_user) { Fabricate(:user, admin: current_user_admin) }
let(:account) { Fabricate(:account, user: user) }
let(:user) { Fabricate(:user, disabled: false, admin: target_user_admin) }
context 'when user is admin' do
let(:current_user_admin) { true }
context 'when target user is admin' do
let(:target_user_admin) { true }
it 'fails to disable account' do
is_expected.to have_http_status :forbidden
expect(user.reload).not_to be_disabled
end
end
context 'when target user is not admin' do
let(:target_user_admin) { false }
it 'succeeds in disabling account' do
is_expected.to redirect_to admin_account_path(account.id)
expect(user.reload).to be_disabled
end
end
end
context 'when user is not admin' do
let(:current_user_admin) { false }
context 'when target user is admin' do
let(:target_user_admin) { true }
it 'fails to disable account' do
is_expected.to have_http_status :forbidden
expect(user.reload).not_to be_disabled
end
end
context 'when target user is not admin' do
let(:target_user_admin) { false }
it 'fails to disable account' do
is_expected.to have_http_status :forbidden
expect(user.reload).not_to be_disabled
end
end
end
end
describe 'POST #redownload' do
subject { post :redownload, params: { id: account.id } }

@ -46,46 +46,11 @@ describe Admin::ReportsController do
end
end
describe 'PUT #update' do
describe 'with an unknown outcome' do
it 'rejects the change' do
report = Fabricate(:report)
put :update, params: { id: report, outcome: 'unknown' }
expect(response).to have_http_status(404)
end
end
describe 'with an outcome of `resolve`' do
it 'resolves the report' do
report = Fabricate(:report)
put :update, params: { id: report, outcome: 'resolve' }
expect(response).to redirect_to(admin_reports_path)
report.reload
expect(report.action_taken_by_account).to eq user.account
expect(report.action_taken).to eq true
end
end
describe 'with an outsome of `silence`' do
it 'silences the reported account' do
report = Fabricate(:report)
put :update, params: { id: report, outcome: 'silence' }
expect(response).to redirect_to(admin_reports_path)
report.reload
expect(report.action_taken_by_account).to eq user.account
expect(report.action_taken).to eq true
expect(report.target_account).to be_silenced
end
end
describe 'with an outsome of `reopen`' do
describe 'POST #reopen' do
it 'reopens the report' do
report = Fabricate(:report)
put :update, params: { id: report, outcome: 'reopen' }
put :reopen, params: { id: report }
expect(response).to redirect_to(admin_report_path(report))
report.reload
expect(report.action_taken_by_account).to eq nil
@ -93,26 +58,25 @@ describe Admin::ReportsController do
end
end
describe 'with an outsome of `assign_to_self`' do
describe 'POST #assign_to_self' do
it 'reopens the report' do
report = Fabricate(:report)
put :update, params: { id: report, outcome: 'assign_to_self' }
put :assign_to_self, params: { id: report }
expect(response).to redirect_to(admin_report_path(report))
report.reload
expect(report.assigned_account).to eq user.account
end
end
describe 'with an outsome of `unassign`' do
describe 'POST #unassign' do
it 'reopens the report' do
report = Fabricate(:report)
put :update, params: { id: report, outcome: 'unassign' }
put :unassign, params: { id: report }
expect(response).to redirect_to(admin_report_path(report))
report.reload
expect(report.assigned_account).to eq nil
end
end
end
end

@ -1,33 +0,0 @@
require 'rails_helper'
describe Admin::SilencesController do
render_views
before do
sign_in Fabricate(:user, admin: true), scope: :user
end
describe 'POST #create' do
it 'redirects to admin accounts page' do
account = Fabricate(:account, silenced: false)
post :create, params: { account_id: account.id }
account.reload
expect(account.silenced?).to eq true
expect(response).to redirect_to(admin_accounts_path)
end
end
describe 'DELETE #destroy' do
it 'redirects to admin accounts page' do
account = Fabricate(:account, silenced: true)
delete :destroy, params: { account_id: account.id }
account.reload
expect(account.silenced?).to eq false
expect(response).to redirect_to(admin_accounts_path)
end
end
end

@ -1,39 +0,0 @@
require 'rails_helper'
describe Admin::SuspensionsController do
render_views
before do
sign_in Fabricate(:user, admin: true), scope: :user
end
describe 'GET #new' do
it 'returns 200' do
get :new, params: { account_id: Fabricate(:account).id, report_id: Fabricate(:report).id }
expect(response).to have_http_status(200)
end
end
describe 'POST #create' do
it 'redirects to admin accounts page' do
account = Fabricate(:account, suspended: false)
expect(Admin::SuspensionWorker).to receive(:perform_async).with(account.id)
post :create, params: { account_id: account.id, form_admin_suspension_confirmation: { acct: account.acct } }
expect(response).to redirect_to(admin_accounts_path)
end
end
describe 'DELETE #destroy' do
it 'redirects to admin accounts page' do
account = Fabricate(:account, suspended: true)
delete :destroy, params: { account_id: account.id }
account.reload
expect(account.suspended?).to eq false
expect(response).to redirect_to(admin_accounts_path)
end
end
end

@ -0,0 +1,5 @@
Fabricator(:account_warning) do
account nil
target_account nil
text "MyText"
end

@ -0,0 +1,3 @@
Fabricator(:account_warning_preset) do
text "MyText"
end

@ -39,4 +39,9 @@ class UserMailerPreview < ActionMailer::Preview
def backup_ready
UserMailer.backup_ready(User.first, Backup.first)
end
# Preview this email at http://localhost:3000/rails/mailers/user_mailer/warning
def warning
UserMailer.warning(User.first, AccountWarning.new(text: '', action: :silence))
end
end

@ -0,0 +1,5 @@
require 'rails_helper'
RSpec.describe AccountWarningPreset, type: :model do
pending "add some examples to (or delete) #{__FILE__}"
end

@ -0,0 +1,5 @@
require 'rails_helper'
RSpec.describe AccountWarning, type: :model do
pending "add some examples to (or delete) #{__FILE__}"
end

@ -0,0 +1,4 @@
require 'rails_helper'
RSpec.describe Admin::AccountAction, type: :model do
end
Loading…
Cancel
Save