Browse Source

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

+ 36
- 0
app/controllers/admin/account_actions_controller.rb View File

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

+ 1
- 0
app/controllers/admin/account_moderation_notes_controller.rb View File

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

+ 16
- 7
app/controllers/admin/accounts_controller.rb View File

@ -2,9 +2,9 @@
module Admin module Admin
class AccountsController < BaseController 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_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 def index
authorize :account, :index? authorize :account, :index?
@ -13,8 +13,10 @@ module Admin
def show def show
authorize @account, :show? authorize @account, :show?
@account_moderation_note = current_account.account_moderation_notes.new(target_account: @account) @account_moderation_note = current_account.account_moderation_notes.new(target_account: @account)
@moderation_notes = @account.targeted_moderation_notes.latest
@moderation_notes = @account.targeted_moderation_notes.latest
@warnings = @account.targeted_account_warnings.latest.custom
end end
def subscribe def subscribe
@ -43,10 +45,17 @@ module Admin
redirect_to admin_account_path(@account.id) redirect_to admin_account_path(@account.id)
end 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) redirect_to admin_account_path(@account.id)
end end

+ 23
- 56
app/controllers/admin/reports_controller.rb View File

@ -13,75 +13,42 @@ module Admin
authorize @report, :show? authorize @report, :show?
@report_note = @report.notes.new @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 @form = Form::StatusBatch.new
end end
def update
def assign_to_self
authorize @report, :update? authorize @report, :update?
process_report
if @report.action_taken?
redirect_to admin_reports_path, notice: I18n.t('admin.reports.resolved_msg')
else
redirect_to admin_report_path(@report)
end
@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'
@report.update!(assigned_account_id: nil)
log_action :unassigned, @report
when 'reopen'
@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
resolve_all_target_account_reports
when 'silence'
@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
def unassign
authorize @report, :update?
@report.update!(assigned_account_id: nil)
log_action :unassigned, @report
redirect_to admin_report_path(@report)
end 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)
def reopen
authorize @report, :update?
@report.unresolve!
log_action :reopen, @report
redirect_to admin_report_path(@report)
end end
def unresolved_reports_for_target_account
Report.where(
target_account: @report.target_account
).unresolved
def resolve
authorize @report, :update?
@report.resolve!(current_account)
log_action :resolve, @report
redirect_to admin_reports_path, notice: I18n.t('admin.reports.resolved_msg')
end end
private
def filtered_reports 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 end
def filter_params def filter_params

+ 0
- 27
app/controllers/admin/silences_controller.rb View File

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

+ 0
- 60
app/controllers/admin/suspensions_controller.rb View File

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

+ 58
- 0
app/controllers/admin/warning_presets_controller.rb View File

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

+ 6
- 1
app/helpers/admin/action_logs_helper.rb View File

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

+ 4
- 0
app/javascript/images/icon_flag.svg View File

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

BIN
View File


+ 4
- 0
app/javascript/styles/mailer.scss View File

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

+ 4
- 0
app/javascript/styles/mastodon/admin.scss View File

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

+ 12
- 0
app/mailers/user_mailer.rb View File

@ -78,4 +78,16 @@ class UserMailer < Devise::Mailer
mail to: @resource.email, subject: I18n.t('user_mailer.backup_ready.subject') mail to: @resource.email, subject: I18n.t('user_mailer.backup_ready.subject')
end end
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 end

+ 8
- 0
app/models/account.rb View File

@ -155,6 +155,14 @@ class Account < ApplicationRecord
ResolveAccountService.new.call(acct) ResolveAccountService.new.call(acct)
end end
def silence!
update!(silenced: true)
end
def unsilence!
update!(silenced: false)
end
def suspend! def suspend!
transaction do transaction do
user&.disable! if local? user&.disable! if local?

+ 23
- 0
app/models/account_warning.rb 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

+ 15
- 0
app/models/account_warning_preset.rb 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

+ 134
- 0
app/models/admin/account_action.rb 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

+ 2
- 0
app/models/concerns/account_associations.rb View File

@ -39,6 +39,8 @@ module AccountAssociations
# Moderation notes # Moderation notes
has_many :account_moderation_notes, dependent: :destroy, inverse_of: :account 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 :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) # Lists (that the account is on, not owned by the account)
has_many :list_accounts, inverse_of: :account, dependent: :destroy has_many :list_accounts, inverse_of: :account, dependent: :destroy

+ 0
- 7
app/models/form/admin_suspension_confirmation.rb View File

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

+ 4
- 0
app/policies/account_policy.rb View File

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

+ 19
- 0
app/policies/account_warning_preset_policy.rb View File

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

+ 26
- 0
app/views/admin/account_actions/new.html.haml View File

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

+ 6
- 0
app/views/admin/account_warnings/_account_warning.html.haml View File

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

+ 9
- 5
app/views/admin/accounts/show.html.haml View File

@ -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) = table_link_to 'unlock', t('admin.accounts.enable'), enable_admin_account_path(@account.id), method: :post if can?(:enable, @account.user)
- else - else
= t('admin.accounts.enabled') = 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 %tr
%th= t('admin.accounts.most_recent_ip') %th= t('admin.accounts.most_recent_ip')
%td= @account.user_current_sign_in_ip %td= @account.user_current_sign_in_ip
@ -119,18 +119,18 @@
%div{ style: 'float: left' } %div{ style: 'float: left' }
- if @account.silenced? - 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 - 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? - if @account.local?
- unless @account.user_confirmed? - 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) = link_to t('admin.accounts.confirm'), admin_account_confirmation_path(@account.id), method: :post, class: 'button' if can?(:confirm, @account.user)
- if @account.suspended? - 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 - 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? - if !@account.local? && @account.hub_url.present?
%hr.spacer/ %hr.spacer/
@ -184,6 +184,10 @@
%hr.spacer/ %hr.spacer/
= render @warnings
%hr.spacer/
= render @moderation_notes = render @moderation_notes
= simple_form_for @account_moderation_note, url: admin_account_moderation_notes_path do |f| = simple_form_for @account_moderation_note, url: admin_account_moderation_notes_path do |f|

+ 9
- 8
app/views/admin/reports/show.html.haml View File

@ -8,13 +8,14 @@
- if @report.unresolved? - if @report.unresolved?
%div{ style: 'float: right' } %div{ style: 'float: right' }
- if @report.target_account.local? - 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' } %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 - 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 %hr.spacer
@ -67,10 +68,10 @@
= admin_account_link_to @report.assigned_account = admin_account_link_to @report.assigned_account
%td %td
- if @report.assigned_account != current_user.account - 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 %td
- if !@report.assigned_account.nil? - 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 %hr.spacer
@ -104,7 +105,7 @@
- @report_notes.each do |item| - @report_notes.each do |item|
- if item.is_a?(Admin::ActionLog) - if item.is_a?(Admin::ActionLog)
= render partial: 'action_log', locals: { action_log: item } = render partial: 'action_log', locals: { action_log: item }
- elsif item.is_a?(ReportNote)
- else
= render item = render item
= simple_form_for @report_note, url: admin_report_notes_path do |f| = simple_form_for @report_note, url: admin_report_notes_path do |f|

+ 0
- 25
app/views/admin/suspensions/new.html.haml View File

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

+ 11
- 0
app/views/admin/warning_presets/edit.html.haml View File

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

+ 30
- 0
app/views/admin/warning_presets/index.html.haml View File

@ -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') }

+ 63
- 0
app/views/user_mailer/warning.html.haml View File

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

+ 9
- 0
app/views/user_mailer/warning.text.erb View File

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

+ 1
- 1
app/views/user_mailer/welcome.text.erb View File

@ -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 %> <%= t 'user_mailer.welcome.full_handle_hint', instance: @instance %>
--- ---

+ 0
- 5
config/locales/ar.yml View File

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

+ 0
- 2
config/locales/ast.yml View File

@ -121,8 +121,6 @@ ast:
failed_to_execute: Fallu al executar failed_to_execute: Fallu al executar
subscriptions: subscriptions:
title: WebSub 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 title: Alministración
admin_mailer: admin_mailer:
new_report: new_report:

+ 0
- 6
config/locales/ca.yml View File

@ -439,12 +439,6 @@ ca:
last_delivery: Últim lliurament last_delivery: Últim lliurament
title: WebSub title: WebSub
topic: Tema 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: tags:
accounts: Comptes accounts: Comptes
hidden: Amagat hidden: Amagat

+ 0
- 6
config/locales/co.yml View File

@ -439,12 +439,6 @@ co:
last_delivery: Ultima arricata last_delivery: Ultima arricata
title: WebSub title: WebSub
topic: Sughjettu 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: tags:
accounts: Conti accounts: Conti
hidden: Piattatu hidden: Piattatu

+ 0
- 6
config/locales/cs.yml View File

@ -444,12 +444,6 @@ cs:
last_delivery: Poslední doručení last_delivery: Poslední doručení
title: WebSub title: WebSub
topic: Téma 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: tags:
accounts: Účty accounts: Účty
hidden: Skryté hidden: Skryté

+ 0
- 6
config/locales/cy.yml View File

@ -423,12 +423,6 @@ cy:
last_delivery: Danfoniad diwethaf last_delivery: Danfoniad diwethaf
title: WebSub title: WebSub
topic: Pwnc 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 title: Gweinyddiaeth
admin_mailer: admin_mailer:
new_report: new_report:

+ 0
- 6
config/locales/da.yml View File

@ -427,12 +427,6 @@ da:
last_delivery: Sidste levering last_delivery: Sidste levering
title: Websub title: Websub
topic: Emne 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 title: Administration
admin_mailer: admin_mailer:
new_report: new_report:

+ 0
- 6
config/locales/de.yml View File

@ -439,12 +439,6 @@ de:
last_delivery: Letzte Zustellung last_delivery: Letzte Zustellung
title: WebSub title: WebSub
topic: Thema 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: tags:
accounts: Konten accounts: Konten
hidden: Versteckt hidden: Versteckt

+ 0
- 6
config/locales/el.yml View File

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

+ 26
- 6
config/locales/en.yml View File

@ -70,6 +70,9 @@ en:
moderator: Mod moderator: Mod
unfollow: Unfollow unfollow: Unfollow
admin: admin:
account_actions:
action: Perform action
title: Perform moderation action on %{acct}
account_moderation_notes: account_moderation_notes:
create: Leave note create: Leave note
created_msg: Moderation note successfully created! created_msg: Moderation note successfully created!
@ -173,6 +176,7 @@ en:
assigned_to_self_report: "%{name} assigned report %{target} to themselves" assigned_to_self_report: "%{name} assigned report %{target} to themselves"
change_email_user: "%{name} changed the e-mail address of user %{target}" change_email_user: "%{name} changed the e-mail address of user %{target}"
confirm_user: "%{name} confirmed 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_custom_emoji: "%{name} uploaded new emoji %{target}"
create_domain_block: "%{name} blocked domain %{target}" create_domain_block: "%{name} blocked domain %{target}"
create_email_domain_block: "%{name} blacklisted e-mail domain %{target}" create_email_domain_block: "%{name} blacklisted e-mail domain %{target}"
@ -441,12 +445,6 @@ en:
last_delivery: Last delivery last_delivery: Last delivery
title: WebSub title: WebSub
topic: Topic 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: tags:
accounts: Accounts accounts: Accounts
hidden: Hidden hidden: Hidden
@ -456,6 +454,12 @@ en:
unhide: Show in directory unhide: Show in directory
visible: Visible visible: Visible
title: Administration title: Administration
warning_presets:
add_new: Add new
delete: Delete
edit: Edit
edit_preset: Edit warning preset
title: Manage warning presets
admin_mailer: admin_mailer:
new_report: new_report:
body: "%{reporter} has reported %{target}" 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! explanation: You requested a full backup of your Mastodon account. It's now ready for download!
subject: Your archive is ready for download subject: Your archive is ready for download
title: Archive takeout 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: welcome:
edit_profile_action: Setup profile 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. 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.

+ 0
- 5
config/locales/eo.yml View File

@ -427,11 +427,6 @@ eo:
last_delivery: Lasta livero last_delivery: Lasta livero
title: WebSub title: WebSub
topic: Temo 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 title: Administrado
admin_mailer: admin_mailer:
new_report: new_report:

+ 0
- 6
config/locales/es.yml View File

@ -433,12 +433,6 @@ es:
last_delivery: Última entrega last_delivery: Última entrega
title: WebSub title: WebSub
topic: Tópico 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 title: Administración
admin_mailer: admin_mailer:
new_report: new_report:

+ 0
- 6
config/locales/eu.yml View File

@ -435,12 +435,6 @@ eu:
last_delivery: Azken bidalketa last_delivery: Azken bidalketa
title: WebSub title: WebSub
topic: Mintzagaia 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: tags:
accounts: Kontuak accounts: Kontuak
hidden: Ezkutatuta hidden: Ezkutatuta

+ 0
- 6
config/locales/fa.yml View File

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

+ 0
- 6
config/locales/fr.yml View File

@ -439,12 +439,6 @@ fr:
last_delivery: Dernière livraison last_delivery: Dernière livraison
title: WebSub title: WebSub
topic: Sujet 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: tags:
accounts: Comptes accounts: Comptes
hidden: Masqué hidden: Masqué

+ 0
- 6
config/locales/gl.yml View File

@ -439,12 +439,6 @@ gl:
last_delivery: Última entrega last_delivery: Última entrega
title: WebSub title: WebSub
topic: Asunto 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: tags:
accounts: Contas accounts: Contas
hidden: Ocultas hidden: Ocultas

+ 0
- 6
config/locales/it.yml View File

@ -429,12 +429,6 @@ it:
confirmed: Confermato confirmed: Confermato
expires_in: Scade in expires_in: Scade in
topic: Argomento 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 title: Amministrazione
application_mailer: application_mailer:
notification_preferences: Cambia preferenze email notification_preferences: Cambia preferenze email

+ 0
- 6
config/locales/ja.yml View File

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

+ 0
- 6
config/locales/ko.yml View File

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

+ 0
- 6
config/locales/nl.yml View File

@ -439,12 +439,6 @@ nl:
last_delivery: Laatste bezorging last_delivery: Laatste bezorging
title: WebSub title: WebSub
topic: Account 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: tags:
accounts: Accounts accounts: Accounts
hidden: Verborgen hidden: Verborgen

+ 0
- 6
config/locales/oc.yml View File

@ -439,12 +439,6 @@ oc:
last_delivery: Darrièra distribucion last_delivery: Darrièra distribucion
title: WebSub title: WebSub
topic: Subjècte 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: tags:
accounts: Comptes accounts: Comptes
hidden: Amagat hidden: Amagat

+ 0
- 6
config/locales/pl.yml View File

@ -445,12 +445,6 @@ pl:
last_delivery: Ostatnio doręczono last_delivery: Ostatnio doręczono
title: WebSub title: WebSub
topic: Temat 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: tags:
accounts: Konta accounts: Konta
hidden: Ukryte hidden: Ukryte

+ 0
- 6
config/locales/pt-BR.yml View File

@ -439,12 +439,6 @@ pt-BR:
last_delivery: Última entrega last_delivery: Última entrega
title: WebSub title: WebSub
topic: Tópico 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: tags:
accounts: Contas accounts: Contas
hidden: Escondido hidden: Escondido

+ 0
- 6
config/locales/ru.yml View File

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

+ 19
- 0
config/locales/simple_form.en.yml View File

@ -2,6 +2,13 @@
en: en:
simple_form: simple_form:
hints: 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: defaults:
autofollow: People who sign up through the invite will automatically follow you 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 avatar: PNG, GIF or JPG. At most %{size}. Will be downscaled to %{dimensions}px
@ -40,6 +47,18 @@ en:
fields: fields:
name: Label name: Label
value: Content 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: defaults:
autofollow: Invite to follow your account autofollow: Invite to follow your account
avatar: Avatar avatar: Avatar

+ 0
- 6
config/locales/sk.yml View File

@ -444,12 +444,6 @@ sk:
last_delivery: Posledné doručenie last_delivery: Posledné doručenie
title: WebSub title: WebSub
topic: Téma 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: tags:
accounts: Účty accounts: Účty
hidden: Skryté hidden: Skryté

+ 0
- 6
config/locales/sr.yml View File

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

+ 12
- 4
config/routes.rb View File

@ -139,6 +139,7 @@ Rails.application.routes.draw do
resources :domain_blocks, only: [:index, :new, :create, :show, :destroy] resources :domain_blocks, only: [:index, :new, :create, :show, :destroy]
resources :email_domain_blocks, only: [:index, :new, :create, :destroy] resources :email_domain_blocks, only: [:index, :new, :create, :destroy]
resources :action_logs, only: [:index] resources :action_logs, only: [:index]
resources :warning_presets, except: [:new]
resource :settings, only: [:edit, :update] resource :settings, only: [:edit, :update]
resources :invites, only: [:index, :create, :destroy] do resources :invites, only: [:index, :create, :destroy] do
@ -160,7 +161,14 @@ Rails.application.routes.draw do
end end
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] resources :reported_statuses, only: [:create]
end end
@ -171,7 +179,8 @@ Rails.application.routes.draw do
post :subscribe post :subscribe
post :unsubscribe post :unsubscribe
post :enable post :enable
post :disable
post :unsilence
post :unsuspend
post :redownload post :redownload
post :remove_avatar post :remove_avatar
post :remove_header post :remove_header
@ -180,8 +189,7 @@ Rails.application.routes.draw do
resource :change_email, only: [:show, :update] resource :change_email, only: [:show, :update]
resource :reset, only: [:create] 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] resources :statuses, only: [:index, :create, :update, :destroy]
resource :confirmation, only: [:create] do resource :confirmation, only: [:create] do

+ 12
- 0
db/migrate/20181213184704_create_account_warnings.rb View File

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

+ 9
- 0
db/migrate/20181213185533_create_account_warning_presets.rb View File

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

+ 20
- 1
db/schema.rb View File

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # 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 # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" 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 t.index ["tag_id"], name: "index_account_tag_stats_on_tag_id", unique: true
end 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| create_table "accounts", force: :cascade do |t|
t.string "username", default: "", null: false t.string "username", default: "", null: false
t.string "domain" 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_pins", "accounts", on_delete: :cascade
add_foreign_key "account_stats", "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_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 "accounts", "accounts", column: "moved_to_account_id", on_delete: :nullify
add_foreign_key "admin_action_logs", "accounts", on_delete: :cascade add_foreign_key "admin_action_logs", "accounts", on_delete: :cascade
add_foreign_key "backups", "users", on_delete: :nullify add_foreign_key "backups", "users", on_delete: :nullify

+ 0
- 52
spec/controllers/admin/accounts_controller_spec.rb View File

@ -191,58 +191,6 @@ RSpec.describe Admin::AccountsController, type: :controller do
end end
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 describe 'POST #redownload' do
subject { post :redownload, params: { id: account.id } } subject { post :redownload, params: { id: account.id } }

+ 24
- 60
spec/controllers/admin/reports_controller_spec.rb View File

@ -46,73 +46,37 @@ describe Admin::ReportsController do
end end
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
it 'reopens the report' do
report = Fabricate(:report)
describe 'POST #reopen' do
it 'reopens the report' do
report = Fabricate(:report)
put :update, params: { id: report, outcome: 'reopen' }
expect(response).to redirect_to(admin_report_path(report))
report.reload
expect(report.action_taken_by_account).to eq nil
expect(report.action_taken).to eq false
end
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
expect(report.action_taken).to eq false
end end
end
describe 'with an outsome of `assign_to_self`' do
it 'reopens the report' do
report = Fabricate(:report)
describe 'POST #assign_to_self' do
it 'reopens the report' do
report = Fabricate(:report)
put :update, params: { id: report, outcome: 'assign_to_self' }
expect(response).to redirect_to(admin_report_path(report))
report.reload
expect(report.assigned_account).to eq user.account
end
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
end
describe 'with an outsome of `unassign`' do
it 'reopens the report' do
report = Fabricate(:report)
describe 'POST #unassign' do
it 'reopens the report' do
report = Fabricate(:report)
put :update, params: { id: report, outcome: 'unassign' }
expect(response).to redirect_to(admin_report_path(report))
report.reload
expect(report.assigned_account).to eq nil
end
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
end end

+ 0
- 33
spec/controllers/admin/silences_controller_spec.rb View File

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

+ 0
- 39
spec/controllers/admin/suspensions_controller_spec.rb View File

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

+ 5
- 0
spec/fabricators/account_warning_fabricator.rb View File

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

+ 3
- 0
spec/fabricators/account_warning_preset_fabricator.rb View File

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

+ 5
- 0
spec/mailers/previews/user_mailer_preview.rb View File

@ -39,4 +39,9 @@ class UserMailerPreview < ActionMailer::Preview
def backup_ready def backup_ready
UserMailer.backup_ready(User.first, Backup.first) UserMailer.backup_ready(User.first, Backup.first)
end 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 end

+ 5
- 0
spec/models/account_warning_preset_spec.rb View File

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

+ 5
- 0
spec/models/account_warning_spec.rb View File

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

+ 4
- 0
spec/models/admin/account_action_spec.rb View File

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

Loading…
Cancel
Save