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
This commit is contained in:
parent
00862dcaff
commit
3c033c4352
36
app/controllers/admin/account_actions_controller.rb
Normal file
36
app/controllers/admin/account_actions_controller.rb
Normal 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
|
@ -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
|
||||||
|
@ -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
|
def unsilence
|
||||||
authorize @account.user, :disable?
|
authorize @account, :unsilence?
|
||||||
@account.user.disable!
|
@account.unsilence!
|
||||||
log_action :disable, @account.user
|
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
|
||||||
|
|
||||||
|
@ -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
|
@report.update!(assigned_account_id: current_account.id)
|
||||||
|
log_action :assigned_to_self, @report
|
||||||
if @report.action_taken?
|
|
||||||
redirect_to admin_reports_path, notice: I18n.t('admin.reports.resolved_msg')
|
|
||||||
else
|
|
||||||
redirect_to admin_report_path(@report)
|
redirect_to admin_report_path(@report)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def unassign
|
||||||
|
authorize @report, :update?
|
||||||
|
@report.update!(assigned_account_id: nil)
|
||||||
|
log_action :unassigned, @report
|
||||||
|
redirect_to admin_report_path(@report)
|
||||||
|
end
|
||||||
|
|
||||||
|
def reopen
|
||||||
|
authorize @report, :update?
|
||||||
|
@report.unresolve!
|
||||||
|
log_action :reopen, @report
|
||||||
|
redirect_to admin_report_path(@report)
|
||||||
|
end
|
||||||
|
|
||||||
|
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
|
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
|
|
||||||
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)
|
|
||||||
end
|
|
||||||
|
|
||||||
def unresolved_reports_for_target_account
|
|
||||||
Report.where(
|
|
||||||
target_account: @report.target_account
|
|
||||||
).unresolved
|
|
||||||
end
|
|
||||||
|
|
||||||
def filtered_reports
|
def filtered_reports
|
||||||
ReportFilter.new(filter_params).results.order(id: :desc).includes(
|
ReportFilter.new(filter_params).results.order(id: :desc).includes(:account, :target_account)
|
||||||
:account,
|
|
||||||
:target_account
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def filter_params
|
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
|
|
58
app/controllers/admin/warning_presets_controller.rb
Normal file
58
app/controllers/admin/warning_presets_controller.rb
Normal 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
|
@ -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
app/javascript/images/icon_flag.svg
Normal file
4
app/javascript/images/icon_flag.svg
Normal 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>
|
After Width: | Height: | Size: 197 B |
BIN
app/javascript/images/mailer/icon_warning.png
Normal file
BIN
app/javascript/images/mailer/icon_warning.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 371 B |
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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
app/models/account_warning.rb
Normal file
23
app/models/account_warning.rb
Normal 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
app/models/account_warning_preset.rb
Normal file
15
app/models/account_warning_preset.rb
Normal 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
app/models/admin/account_action.rb
Normal file
134
app/models/admin/account_action.rb
Normal 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
|
@ -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
|
||||||
|
@ -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?
|
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
app/policies/account_warning_preset_policy.rb
Normal file
19
app/policies/account_warning_preset_policy.rb
Normal 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
app/views/admin/account_actions/new.html.haml
Normal file
26
app/views/admin/account_actions/new.html.haml
Normal 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
|
@ -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)
|
= 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|
|
||||||
|
@ -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.warn'), new_admin_account_action_path(@report.target_account_id, type: 'none', report_id: @report.id), class: 'button'
|
||||||
= link_to t('admin.accounts.silence'), admin_report_path(@report, outcome: 'silence'), method: :put, class: 'button button--destructive'
|
= 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.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.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|
|
||||||
|
@ -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
app/views/admin/warning_presets/edit.html.haml
Normal file
11
app/views/admin/warning_presets/edit.html.haml
Normal 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
app/views/admin/warning_presets/index.html.haml
Normal file
30
app/views/admin/warning_presets/index.html.haml
Normal 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
app/views/user_mailer/warning.html.haml
Normal file
63
app/views/user_mailer/warning.html.haml
Normal 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
app/views/user_mailer/warning.text.erb
Normal file
9
app/views/user_mailer/warning.text.erb
Normal 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 %>
|
@ -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 %>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
@ -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: المخفية
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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é
|
||||||
|
@ -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:
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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: Κρυμμένες
|
||||||
|
@ -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.
|
||||||
|
@ -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:
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
@ -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é
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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: 非表示
|
||||||
|
@ -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: 숨겨짐
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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é
|
||||||
|
@ -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:
|
||||||
|
@ -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 :action, only: [:new, :create], controller: 'account_actions'
|
||||||
resource :suspension, only: [:new, :create, :destroy]
|
|
||||||
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
db/migrate/20181213184704_create_account_warnings.rb
Normal file
12
db/migrate/20181213184704_create_account_warnings.rb
Normal 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
|
@ -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
|
21
db/schema.rb
21
db/schema.rb
@ -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
|
||||||
|
@ -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 } }
|
||||||
|
|
||||||
|
@ -46,46 +46,11 @@ describe Admin::ReportsController do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'PUT #update' do
|
describe 'POST #reopen' 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
|
it 'reopens the report' do
|
||||||
report = Fabricate(:report)
|
report = Fabricate(:report)
|
||||||
|
|
||||||
put :update, params: { id: report, outcome: 'reopen' }
|
put :reopen, params: { id: report }
|
||||||
expect(response).to redirect_to(admin_report_path(report))
|
expect(response).to redirect_to(admin_report_path(report))
|
||||||
report.reload
|
report.reload
|
||||||
expect(report.action_taken_by_account).to eq nil
|
expect(report.action_taken_by_account).to eq nil
|
||||||
@ -93,26 +58,25 @@ describe Admin::ReportsController do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'with an outsome of `assign_to_self`' do
|
describe 'POST #assign_to_self' do
|
||||||
it 'reopens the report' do
|
it 'reopens the report' do
|
||||||
report = Fabricate(:report)
|
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))
|
expect(response).to redirect_to(admin_report_path(report))
|
||||||
report.reload
|
report.reload
|
||||||
expect(report.assigned_account).to eq user.account
|
expect(report.assigned_account).to eq user.account
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'with an outsome of `unassign`' do
|
describe 'POST #unassign' do
|
||||||
it 'reopens the report' do
|
it 'reopens the report' do
|
||||||
report = Fabricate(:report)
|
report = Fabricate(:report)
|
||||||
|
|
||||||
put :update, params: { id: report, outcome: 'unassign' }
|
put :unassign, params: { id: report }
|
||||||
expect(response).to redirect_to(admin_report_path(report))
|
expect(response).to redirect_to(admin_report_path(report))
|
||||||
report.reload
|
report.reload
|
||||||
expect(report.assigned_account).to eq nil
|
expect(report.assigned_account).to eq nil
|
||||||
end
|
end
|
||||||
end
|
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
|
|
5
spec/fabricators/account_warning_fabricator.rb
Normal file
5
spec/fabricators/account_warning_fabricator.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
Fabricator(:account_warning) do
|
||||||
|
account nil
|
||||||
|
target_account nil
|
||||||
|
text "MyText"
|
||||||
|
end
|
3
spec/fabricators/account_warning_preset_fabricator.rb
Normal file
3
spec/fabricators/account_warning_preset_fabricator.rb
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Fabricator(:account_warning_preset) do
|
||||||
|
text "MyText"
|
||||||
|
end
|
@ -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
spec/models/account_warning_preset_spec.rb
Normal file
5
spec/models/account_warning_preset_spec.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe AccountWarningPreset, type: :model do
|
||||||
|
pending "add some examples to (or delete) #{__FILE__}"
|
||||||
|
end
|
5
spec/models/account_warning_spec.rb
Normal file
5
spec/models/account_warning_spec.rb
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe AccountWarning, type: :model do
|
||||||
|
pending "add some examples to (or delete) #{__FILE__}"
|
||||||
|
end
|
4
spec/models/admin/account_action_spec.rb
Normal file
4
spec/models/admin/account_action_spec.rb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe Admin::AccountAction, type: :model do
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user