summaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2018-12-22 20:02:09 +0100
committerGitHub <noreply@github.com>2018-12-22 20:02:09 +0100
commit3c033c4352f8b156887cd7157b4a89c23a545838 (patch)
treefa6317223a0104abea84a10e6234a0beef316001 /app
parent00862dcaff7cb918d29947accda1c01873a7ddeb (diff)
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
Diffstat (limited to 'app')
-rw-r--r--app/controllers/admin/account_actions_controller.rb36
-rw-r--r--app/controllers/admin/account_moderation_notes_controller.rb1
-rw-r--r--app/controllers/admin/accounts_controller.rb23
-rw-r--r--app/controllers/admin/reports_controller.rb79
-rw-r--r--app/controllers/admin/silences_controller.rb27
-rw-r--r--app/controllers/admin/suspensions_controller.rb60
-rw-r--r--app/controllers/admin/warning_presets_controller.rb58
-rw-r--r--app/helpers/admin/action_logs_helper.rb7
-rw-r--r--app/javascript/images/icon_flag.svg4
-rw-r--r--app/javascript/images/mailer/icon_warning.pngbin0 -> 371 bytes
-rw-r--r--app/javascript/styles/mailer.scss4
-rw-r--r--app/javascript/styles/mastodon/admin.scss4
-rw-r--r--app/mailers/user_mailer.rb12
-rw-r--r--app/models/account.rb8
-rw-r--r--app/models/account_warning.rb23
-rw-r--r--app/models/account_warning_preset.rb15
-rw-r--r--app/models/admin/account_action.rb134
-rw-r--r--app/models/concerns/account_associations.rb2
-rw-r--r--app/models/form/admin_suspension_confirmation.rb7
-rw-r--r--app/policies/account_policy.rb4
-rw-r--r--app/policies/account_warning_preset_policy.rb19
-rw-r--r--app/views/admin/account_actions/new.html.haml26
-rw-r--r--app/views/admin/account_warnings/_account_warning.html.haml6
-rw-r--r--app/views/admin/accounts/show.html.haml14
-rw-r--r--app/views/admin/reports/show.html.haml17
-rw-r--r--app/views/admin/suspensions/new.html.haml25
-rw-r--r--app/views/admin/warning_presets/edit.html.haml11
-rw-r--r--app/views/admin/warning_presets/index.html.haml30
-rw-r--r--app/views/user_mailer/warning.html.haml63
-rw-r--r--app/views/user_mailer/warning.text.erb9
-rw-r--r--app/views/user_mailer/welcome.text.erb2
31 files changed, 533 insertions, 197 deletions
diff --git a/app/controllers/admin/account_actions_controller.rb b/app/controllers/admin/account_actions_controller.rb
new file mode 100644
index 00000000000..e847495f1b8
--- /dev/null
+++ b/app/controllers/admin/account_actions_controller.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
diff --git a/app/controllers/admin/account_moderation_notes_controller.rb b/app/controllers/admin/account_moderation_notes_controller.rb
index 7d5b9bf52c8..44f6e34f80b 100644
--- a/app/controllers/admin/account_moderation_notes_controller.rb
+++ b/app/controllers/admin/account_moderation_notes_controller.rb
@@ -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
diff --git a/app/controllers/admin/accounts_controller.rb b/app/controllers/admin/accounts_controller.rb
index 771302db807..10abd1e6aeb 100644
--- a/app/controllers/admin/accounts_controller.rb
+++ b/app/controllers/admin/accounts_controller.rb
@@ -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
+ @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
diff --git a/app/controllers/admin/reports_controller.rb b/app/controllers/admin/reports_controller.rb
index e97ddb9b647..f138376b2f7 100644
--- a/app/controllers/admin/reports_controller.rb
+++ b/app/controllers/admin/reports_controller.rb
@@ -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
- 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
- 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
- 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
- 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
+ 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
diff --git a/app/controllers/admin/silences_controller.rb b/app/controllers/admin/silences_controller.rb
deleted file mode 100644
index 4c06a9c0cc7..00000000000
--- a/app/controllers/admin/silences_controller.rb
+++ /dev/null
@@ -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
diff --git a/app/controllers/admin/suspensions_controller.rb b/app/controllers/admin/suspensions_controller.rb
deleted file mode 100644
index f9bbf36fb84..00000000000
--- a/app/controllers/admin/suspensions_controller.rb
+++ /dev/null
@@ -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
diff --git a/app/controllers/admin/warning_presets_controller.rb b/app/controllers/admin/warning_presets_controller.rb
new file mode 100644
index 00000000000..37be842c5b0
--- /dev/null
+++ b/app/controllers/admin/warning_presets_controller.rb
@@ -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
diff --git a/app/helpers/admin/action_logs_helper.rb b/app/helpers/admin/action_logs_helper.rb
index 68cf8c75dda..359d60b60e2 100644
--- a/app/helpers/admin/action_logs_helper.rb
+++ b/app/helpers/admin/action_logs_helper.rb
@@ -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
diff --git a/app/javascript/images/icon_flag.svg b/app/javascript/images/icon_flag.svg
new file mode 100644
index 00000000000..3939c9d2b37
--- /dev/null
+++ b/app/javascript/images/icon_flag.svg
@@ -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>
diff --git a/app/javascript/images/mailer/icon_warning.png b/app/javascript/images/mailer/icon_warning.png
new file mode 100644
index 00000000000..7baaac61cb8
--- /dev/null
+++ b/app/javascript/images/mailer/icon_warning.png
Binary files differ
diff --git a/app/javascript/styles/mailer.scss b/app/javascript/styles/mailer.scss
index d83bd4d9604..74d1df8ed3e 100644
--- a/app/javascript/styles/mailer.scss
+++ b/app/javascript/styles/mailer.scss
@@ -426,6 +426,10 @@ h5 {
background: $success-green;
}
+ &.alert-icon td {
+ background: $error-red;
+ }
+
img {
max-width: 32px;
width: 32px;
diff --git a/app/javascript/styles/mastodon/admin.scss b/app/javascript/styles/mastodon/admin.scss
index b6c771abf30..e8f33193235 100644
--- a/app/javascript/styles/mastodon/admin.scss
+++ b/app/javascript/styles/mastodon/admin.scss
@@ -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;
diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb
index aa76b4dfe40..8f3a4ab3aa2 100644
--- a/app/mailers/user_mailer.rb
+++ b/app/mailers/user_mailer.rb
@@ -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
diff --git a/app/models/account.rb b/app/models/account.rb
index 5a7a9c580a0..16ef6c187a7 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -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?
diff --git a/app/models/account_warning.rb b/app/models/account_warning.rb
new file mode 100644
index 00000000000..157e6c04d1e
--- /dev/null
+++ b/app/models/account_warning.rb
@@ -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
diff --git a/app/models/account_warning_preset.rb b/app/models/account_warning_preset.rb
new file mode 100644
index 00000000000..ba8ceabb353
--- /dev/null
+++ b/app/models/account_warning_preset.rb
@@ -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
diff --git a/app/models/admin/account_action.rb b/app/models/admin/account_action.rb
new file mode 100644
index 00000000000..84c3f880d25
--- /dev/null
+++ b/app/models/admin/account_action.rb
@@ -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
<