Moderation: add `force sensitive` and `force unlisted` actions. Accounts: add federatable `adult content` tag. Handle from remote accounts as well.
parent
5c59d1837f
commit
3b06175e8f
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
module Admin
|
module Admin
|
||||||
class AccountsController < BaseController
|
class AccountsController < BaseController
|
||||||
before_action :set_account, only: [:show, :redownload, :remove_avatar, :remove_header, :enable, :unsilence, :unsuspend, :memorialize, :approve, :reject]
|
before_action :set_account, only: [:show, :redownload, :remove_avatar, :remove_header, :enable, :allow_public, :allow_nonsensitive, :unsilence, :unsuspend, :memorialize, :approve, :reject]
|
||||||
before_action :require_remote_account!, only: [:redownload]
|
before_action :require_remote_account!, only: [:redownload]
|
||||||
before_action :require_local_account!, only: [:enable, :memorialize, :approve, :reject]
|
before_action :require_local_account!, only: [:enable, :memorialize, :approve, :reject]
|
||||||
|
|
||||||
|
@ -45,6 +45,34 @@ module Admin
|
||||||
redirect_to admin_accounts_path(pending: '1')
|
redirect_to admin_accounts_path(pending: '1')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def force_sensitive
|
||||||
|
authorize @account, :force_sensitive?
|
||||||
|
@account.force_sensitive!
|
||||||
|
log_action :force_sensitive, @account
|
||||||
|
redirect_to admin_account_path(@account.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def allow_nonsensitive
|
||||||
|
authorize @account, :allow_nonsensitive?
|
||||||
|
@account.allow_nonsensitive!
|
||||||
|
log_action :allow_nonsensitive, @account
|
||||||
|
redirect_to admin_account_path(@account.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def force_unlisted
|
||||||
|
authorize @account, :force_unlisted?
|
||||||
|
@account.force_unlisted!
|
||||||
|
log_action :force_unlisted, @account
|
||||||
|
redirect_to admin_account_path(@account.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def allow_public
|
||||||
|
authorize @account, :allow_public?
|
||||||
|
@account.allow_public!
|
||||||
|
log_action :allow_public, @account
|
||||||
|
redirect_to admin_account_path(@account.id)
|
||||||
|
end
|
||||||
|
|
||||||
def unsilence
|
def unsilence
|
||||||
authorize @account, :unsilence?
|
authorize @account, :unsilence?
|
||||||
@account.unsilence!
|
@account.unsilence!
|
||||||
|
|
|
@ -53,7 +53,7 @@ module Admin
|
||||||
end
|
end
|
||||||
|
|
||||||
def resource_params
|
def resource_params
|
||||||
params.require(:domain_block).permit(:domain, :severity, :reject_media, :reject_reports)
|
params.require(:domain_block).permit(:domain, :severity, :force_sensitive, :reject_media, :reject_reports)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -25,7 +25,7 @@ class Settings::ProfilesController < Settings::BaseController
|
||||||
private
|
private
|
||||||
|
|
||||||
def account_params
|
def account_params
|
||||||
params.require(:account).permit(:display_name, :note, :avatar, :header, :replies, :locked, :hidden, :unlisted, :bot, :discoverable, fields_attributes: [:name, :value])
|
params.require(:account).permit(:display_name, :note, :avatar, :header, :replies, :locked, :hidden, :unlisted, :adults_only, :bot, :discoverable, fields_attributes: [:name, :value])
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_account
|
def set_account
|
||||||
|
|
|
@ -19,7 +19,7 @@ module Admin::ActionLogsHelper
|
||||||
elsif log.target_type == 'User' && [:change_email].include?(log.action)
|
elsif log.target_type == 'User' && [:change_email].include?(log.action)
|
||||||
log.recorded_changes.slice('email', 'unconfirmed_email')
|
log.recorded_changes.slice('email', 'unconfirmed_email')
|
||||||
elsif log.target_type == 'DomainBlock'
|
elsif log.target_type == 'DomainBlock'
|
||||||
log.recorded_changes.slice('severity', 'reject_media')
|
log.recorded_changes.slice('severity', 'reject_media', 'force_sensitive')
|
||||||
elsif log.target_type == 'Status' && log.action == :update
|
elsif log.target_type == 'Status' && log.action == :update
|
||||||
log.recorded_changes.slice('sensitive')
|
log.recorded_changes.slice('sensitive')
|
||||||
end
|
end
|
||||||
|
@ -55,13 +55,13 @@ module Admin::ActionLogsHelper
|
||||||
|
|
||||||
def class_for_log_icon(log)
|
def class_for_log_icon(log)
|
||||||
case log.action
|
case log.action
|
||||||
when :enable, :unsuspend, :unsilence, :confirm, :promote, :resolve
|
when :enable, :allow_public, :allow_nonsensitive, :unsuspend, :unsilence, :confirm, :promote, :resolve
|
||||||
'positive'
|
'positive'
|
||||||
when :create
|
when :create
|
||||||
opposite_verbs?(log) ? 'negative' : 'positive'
|
opposite_verbs?(log) ? 'negative' : 'positive'
|
||||||
when :update, :reset_password, :disable_2fa, :memorialize, :change_email
|
when :update, :reset_password, :disable_2fa, :memorialize, :change_email
|
||||||
'neutral'
|
'neutral'
|
||||||
when :demote, :silence, :disable, :suspend, :remove_avatar, :remove_header, :reopen
|
when :demote, :force_sensitive, :force_unlisted, :silence, :disable, :suspend, :remove_avatar, :remove_header, :reopen
|
||||||
'negative'
|
'negative'
|
||||||
when :destroy
|
when :destroy
|
||||||
opposite_verbs?(log) ? 'positive' : 'negative'
|
opposite_verbs?(log) ? 'positive' : 'negative'
|
||||||
|
|
|
@ -38,6 +38,7 @@ module StreamEntriesHelper
|
||||||
content_tag(:div, class: 'roles') do
|
content_tag(:div, class: 'roles') do
|
||||||
roles = []
|
roles = []
|
||||||
roles << content_tag(:div, t('accounts.roles.bot'), class: 'account-role bot') if account.bot?
|
roles << content_tag(:div, t('accounts.roles.bot'), class: 'account-role bot') if account.bot?
|
||||||
|
roles << content_tag(:div, t('accounts.roles.adults_only'), class: 'account-role adults-only') if account.adults_only?
|
||||||
roles << content_tag(:div, t('accounts.roles.gentlies_kobolds'), class: 'account-role gentlies') if account&.user&.setting_gently_kobolds
|
roles << content_tag(:div, t('accounts.roles.gentlies_kobolds'), class: 'account-role gentlies') if account&.user&.setting_gently_kobolds
|
||||||
roles << content_tag(:div, t('accounts.roles.kobold'), class: 'account-role kobold') if account&.user&.setting_user_is_kobold
|
roles << content_tag(:div, t('accounts.roles.kobold'), class: 'account-role kobold') if account&.user&.setting_user_is_kobold
|
||||||
|
|
||||||
|
|
|
@ -189,7 +189,8 @@ class Header extends ImmutablePureComponent {
|
||||||
const content = { __html: account.get('note_emojified') };
|
const content = { __html: account.get('note_emojified') };
|
||||||
const displayNameHtml = { __html: account.get('display_name_html') };
|
const displayNameHtml = { __html: account.get('display_name_html') };
|
||||||
const fields = account.get('fields');
|
const fields = account.get('fields');
|
||||||
const badge = account.get('bot') ? (<div className='account-role bot'><FormattedMessage id='account.badges.bot' defaultMessage='Bot' /></div>) : null;
|
const badge_bot = account.get('bot') ? (<div className='account-role bot'><FormattedMessage id='account.badges.bot' defaultMessage='Bot' /></div>) : null;
|
||||||
|
const badge_ao = account.get('adults_only') ? (<div className='account-role adults-only'><FormattedMessage id='account.badges.adults_only' defaultMessage="🔞 Adult content" /></div>) : null;
|
||||||
const acct = account.get('acct').indexOf('@') === -1 && domain ? `${account.get('acct')}@${domain}` : account.get('acct');
|
const acct = account.get('acct').indexOf('@') === -1 && domain ? `${account.get('acct')}@${domain}` : account.get('acct');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -219,7 +220,7 @@ class Header extends ImmutablePureComponent {
|
||||||
|
|
||||||
<div className='account__header__tabs__name'>
|
<div className='account__header__tabs__name'>
|
||||||
<h1>
|
<h1>
|
||||||
<span dangerouslySetInnerHTML={displayNameHtml} /> {badge}
|
<span dangerouslySetInnerHTML={displayNameHtml} /> {badge_ao}{badge_bot}
|
||||||
<small>@{acct} {lockedIcon}</small>
|
<small>@{acct} {lockedIcon}</small>
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"account.add_or_remove_from_list": "Add or Remove from lists",
|
"account.add_or_remove_from_list": "Add or Remove from lists",
|
||||||
"account.badges.bot": "Bot",
|
"account.badges.bot": "Bot",
|
||||||
|
"account.badges.adults_only": "🔞 Adult content",
|
||||||
"account.block": "Block @{name}",
|
"account.block": "Block @{name}",
|
||||||
"account.block_domain": "Hide {domain}",
|
"account.block_domain": "Hide {domain}",
|
||||||
"account.blocked": "Blocked",
|
"account.blocked": "Blocked",
|
||||||
|
|
|
@ -34,6 +34,9 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
|
||||||
process_tags
|
process_tags
|
||||||
process_audience
|
process_audience
|
||||||
|
|
||||||
|
@params[:visibility] = :unlisted if @params[:visibility] == :public && @account.force_unlisted?
|
||||||
|
@params[:sensitive] = true if @account.force_sensitive?
|
||||||
|
|
||||||
ApplicationRecord.transaction do
|
ApplicationRecord.transaction do
|
||||||
@status = Status.create!(@params)
|
@status = Status.create!(@params)
|
||||||
attach_tags(@status)
|
attach_tags(@status)
|
||||||
|
|
|
@ -19,6 +19,7 @@ class ActivityPub::Adapter < ActiveModelSerializers::Adapter::Base
|
||||||
focal_point: { 'toot' => 'http://joinmastodon.org/ns#', 'focalPoint' => { '@container' => '@list', '@id' => 'toot:focalPoint' } },
|
focal_point: { 'toot' => 'http://joinmastodon.org/ns#', 'focalPoint' => { '@container' => '@list', '@id' => 'toot:focalPoint' } },
|
||||||
identity_proof: { 'toot' => 'http://joinmastodon.org/ns#', 'IdentityProof' => 'toot:IdentityProof' },
|
identity_proof: { 'toot' => 'http://joinmastodon.org/ns#', 'IdentityProof' => 'toot:IdentityProof' },
|
||||||
blurhash: { 'toot' => 'http://joinmastodon.org/ns#', 'blurhash' => 'toot:blurhash' },
|
blurhash: { 'toot' => 'http://joinmastodon.org/ns#', 'blurhash' => 'toot:blurhash' },
|
||||||
|
adults_only: { 'schema' => 'http://schema.org#', 'suggestedMinAge' => 'schema:suggestedMinAge' }
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
def self.default_key_transform
|
def self.default_key_transform
|
||||||
|
|
|
@ -48,6 +48,9 @@
|
||||||
# vars :jsonb not null
|
# vars :jsonb not null
|
||||||
# replies :boolean default(TRUE), not null
|
# replies :boolean default(TRUE), not null
|
||||||
# unlisted :boolean default(FALSE), not null
|
# unlisted :boolean default(FALSE), not null
|
||||||
|
# force_unlisted :boolean default(FALSE), not null
|
||||||
|
# force_sensitive :boolean default(FALSE), not null
|
||||||
|
# adults_only :boolean default(FALSE), not null
|
||||||
#
|
#
|
||||||
|
|
||||||
class Account < ApplicationRecord
|
class Account < ApplicationRecord
|
||||||
|
@ -120,6 +123,7 @@ class Account < ApplicationRecord
|
||||||
:moderator?,
|
:moderator?,
|
||||||
:staff?,
|
:staff?,
|
||||||
:locale,
|
:locale,
|
||||||
|
:default_sensitive?,
|
||||||
:hides_network?,
|
:hides_network?,
|
||||||
:shows_application?,
|
:shows_application?,
|
||||||
:always_local?,
|
:always_local?,
|
||||||
|
@ -185,6 +189,28 @@ class Account < ApplicationRecord
|
||||||
ResolveAccountService.new.call(acct)
|
ResolveAccountService.new.call(acct)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def force_unlisted!
|
||||||
|
transaction do
|
||||||
|
update!(force_unlisted: true)
|
||||||
|
Status.where(account_id: id, visibility: :public).in_batches.update_all(visibility: :unlisted)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def force_sensitive!
|
||||||
|
transaction do
|
||||||
|
update!(force_sensitive: true)
|
||||||
|
Status.where(account_id: id, sensitive: false).in_batches.update_all(sensitive: true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def allow_public!
|
||||||
|
update!(force_unlisted: false)
|
||||||
|
end
|
||||||
|
|
||||||
|
def allow_nonsensitive!
|
||||||
|
update!(force_sensitive: false)
|
||||||
|
end
|
||||||
|
|
||||||
def silenced?
|
def silenced?
|
||||||
silenced_at.present?
|
silenced_at.present?
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
class AccountWarning < ApplicationRecord
|
class AccountWarning < ApplicationRecord
|
||||||
enum action: %i(none disable silence suspend), _suffix: :action
|
enum action: %i(none disable force_sensitive force_unlisted silence suspend), _suffix: :action
|
||||||
|
|
||||||
belongs_to :account, inverse_of: :account_warnings
|
belongs_to :account, inverse_of: :account_warnings
|
||||||
belongs_to :target_account, class_name: 'Account', inverse_of: :targeted_account_warnings
|
belongs_to :target_account, class_name: 'Account', inverse_of: :targeted_account_warnings
|
||||||
|
|
|
@ -8,6 +8,8 @@ class Admin::AccountAction
|
||||||
TYPES = %w(
|
TYPES = %w(
|
||||||
none
|
none
|
||||||
disable
|
disable
|
||||||
|
force_sensitive
|
||||||
|
force_unlisted
|
||||||
silence
|
silence
|
||||||
suspend
|
suspend
|
||||||
).freeze
|
).freeze
|
||||||
|
@ -56,6 +58,10 @@ class Admin::AccountAction
|
||||||
case type
|
case type
|
||||||
when 'disable'
|
when 'disable'
|
||||||
handle_disable!
|
handle_disable!
|
||||||
|
when 'force_sensitive'
|
||||||
|
handle_force_sensitive!
|
||||||
|
when 'force_unlisted'
|
||||||
|
handle_force_unlisted!
|
||||||
when 'silence'
|
when 'silence'
|
||||||
handle_silence!
|
handle_silence!
|
||||||
when 'suspend'
|
when 'suspend'
|
||||||
|
@ -97,6 +103,18 @@ class Admin::AccountAction
|
||||||
target_account.user&.disable!
|
target_account.user&.disable!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def handle_force_sensitive!
|
||||||
|
authorize(target_account, :force_sensitive?)
|
||||||
|
log_action(:force_sensitive, target_account.user)
|
||||||
|
target_account.force_sensitive!
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_force_unlisted!
|
||||||
|
authorize(target_account, :force_unlisted?)
|
||||||
|
log_action(:force_unlisted, target_account.user)
|
||||||
|
target_account.force_unlisted!
|
||||||
|
end
|
||||||
|
|
||||||
def handle_silence!
|
def handle_silence!
|
||||||
authorize(target_account, :silence?)
|
authorize(target_account, :silence?)
|
||||||
log_action(:silence, target_account)
|
log_action(:silence, target_account)
|
||||||
|
|
|
@ -3,19 +3,20 @@
|
||||||
#
|
#
|
||||||
# Table name: domain_blocks
|
# Table name: domain_blocks
|
||||||
#
|
#
|
||||||
# id :bigint(8) not null, primary key
|
# id :bigint(8) not null, primary key
|
||||||
# domain :string default(""), not null
|
# domain :string default(""), not null
|
||||||
# created_at :datetime not null
|
# created_at :datetime not null
|
||||||
# updated_at :datetime not null
|
# updated_at :datetime not null
|
||||||
# severity :integer default("silence")
|
# severity :integer default("noop")
|
||||||
# reject_media :boolean default(FALSE), not null
|
# reject_media :boolean default(FALSE), not null
|
||||||
# reject_reports :boolean default(FALSE), not null
|
# reject_reports :boolean default(FALSE), not null
|
||||||
|
# force_sensitive :boolean default(FALSE), not null
|
||||||
#
|
#
|
||||||
|
|
||||||
class DomainBlock < ApplicationRecord
|
class DomainBlock < ApplicationRecord
|
||||||
include DomainNormalizable
|
include DomainNormalizable
|
||||||
|
|
||||||
enum severity: [:silence, :suspend, :noop]
|
enum severity: [:noop, :force_unlisted, :silence, :suspend]
|
||||||
|
|
||||||
validates :domain, presence: true, uniqueness: true
|
validates :domain, presence: true, uniqueness: true
|
||||||
|
|
||||||
|
@ -28,10 +29,15 @@ class DomainBlock < ApplicationRecord
|
||||||
where(domain: domain, severity: :suspend).exists?
|
where(domain: domain, severity: :suspend).exists?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.force_unlisted?(domain)
|
||||||
|
where(domain: domain, severity: :force_unlisted).exists?
|
||||||
|
end
|
||||||
|
|
||||||
def stricter_than?(other_block)
|
def stricter_than?(other_block)
|
||||||
return true if suspend?
|
return true if suspend?
|
||||||
return false if other_block.suspend? && (silence? || noop?)
|
return false if other_block.suspend? && !suspend?
|
||||||
return false if other_block.silence? && noop?
|
return false if other_block.silence? && (noop? || force_unlisted?)
|
||||||
|
return false if other_block.force_unlisted? && noop?
|
||||||
(reject_media || !other_block.reject_media) && (reject_reports || !other_block.reject_reports)
|
(reject_media || !other_block.reject_media) && (reject_reports || !other_block.reject_reports)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -40,8 +40,6 @@ class Status < ApplicationRecord
|
||||||
|
|
||||||
# match both with and without U+FE0F (the emoji variation selector)
|
# match both with and without U+FE0F (the emoji variation selector)
|
||||||
LOCAL_ONLY_TOKENS = /(?:#!|\u{1f441}\ufe0f?)\u200b?\z/
|
LOCAL_ONLY_TOKENS = /(?:#!|\u{1f441}\ufe0f?)\u200b?\z/
|
||||||
FORCE_SENSITIVE = ENV.fetch('FORCE_SENSITIVE', '').chomp.split(/\.?\s+/).freeze
|
|
||||||
FORCE_UNLISTED = ENV.fetch('FORCE_UNLISTED', '').chomp.split(/\.?\s+/).freeze
|
|
||||||
|
|
||||||
# If `override_timestamps` is set at creation time, Snowflake ID creation
|
# If `override_timestamps` is set at creation time, Snowflake ID creation
|
||||||
# will be based on current time instead of `created_at`
|
# will be based on current time instead of `created_at`
|
||||||
|
@ -561,9 +559,6 @@ class Status < ApplicationRecord
|
||||||
def set_visibility
|
def set_visibility
|
||||||
self.visibility = reblog.visibility if reblog? && visibility.nil?
|
self.visibility = reblog.visibility if reblog? && visibility.nil?
|
||||||
self.visibility = (account.locked? ? :private : :public) if visibility.nil?
|
self.visibility = (account.locked? ? :private : :public) if visibility.nil?
|
||||||
self.visibility = :unlisted if visibility == :public && account.domain.in?(FORCE_UNLISTED)
|
|
||||||
self.sensitive = true if account.domain.in?(FORCE_SENSITIVE)
|
|
||||||
self.sensitive = false if sensitive.nil?
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_locality
|
def set_locality
|
||||||
|
|
|
@ -309,6 +309,10 @@ class User < ApplicationRecord
|
||||||
@hide_captions ||= (settings.hide_captions || false)
|
@hide_captions ||= (settings.hide_captions || false)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def default_sensitive?
|
||||||
|
@default_sensitive ||= settings.default_sensitive
|
||||||
|
end
|
||||||
|
|
||||||
def setting_default_privacy
|
def setting_default_privacy
|
||||||
settings.default_privacy || 'public'
|
settings.default_privacy || 'public'
|
||||||
end
|
end
|
||||||
|
|
|
@ -29,6 +29,22 @@ class AccountPolicy < ApplicationPolicy
|
||||||
staff?
|
staff?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def force_unlisted?
|
||||||
|
staff?
|
||||||
|
end
|
||||||
|
|
||||||
|
def allow_public?
|
||||||
|
staff?
|
||||||
|
end
|
||||||
|
|
||||||
|
def force_sensitive?
|
||||||
|
staff?
|
||||||
|
end
|
||||||
|
|
||||||
|
def allow_nonsensitive?
|
||||||
|
staff?
|
||||||
|
end
|
||||||
|
|
||||||
def redownload?
|
def redownload?
|
||||||
admin?
|
admin?
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,7 +6,8 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer
|
||||||
context :security
|
context :security
|
||||||
|
|
||||||
context_extensions :manually_approves_followers, :featured, :also_known_as,
|
context_extensions :manually_approves_followers, :featured, :also_known_as,
|
||||||
:moved_to, :property_value, :hashtag, :emoji, :identity_proof
|
:moved_to, :property_value, :hashtag, :emoji, :identity_proof,
|
||||||
|
:adults_only
|
||||||
|
|
||||||
attributes :id, :type, :following, :followers,
|
attributes :id, :type, :following, :followers,
|
||||||
:inbox, :outbox, :featured,
|
:inbox, :outbox, :featured,
|
||||||
|
@ -20,6 +21,7 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer
|
||||||
|
|
||||||
attribute :moved_to, if: :moved?
|
attribute :moved_to, if: :moved?
|
||||||
attribute :also_known_as, if: :also_known_as?
|
attribute :also_known_as, if: :also_known_as?
|
||||||
|
attribute :adults_only, if: :adults_only?
|
||||||
|
|
||||||
class EndpointsSerializer < ActivityPub::Serializer
|
class EndpointsSerializer < ActivityPub::Serializer
|
||||||
include RoutingHelper
|
include RoutingHelper
|
||||||
|
@ -66,6 +68,10 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer
|
||||||
account_collection_url(object, :featured)
|
account_collection_url(object, :featured)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def adults_only
|
||||||
|
18
|
||||||
|
end
|
||||||
|
|
||||||
def endpoints
|
def endpoints
|
||||||
object
|
object
|
||||||
end
|
end
|
||||||
|
@ -126,6 +132,10 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer
|
||||||
!object.also_known_as.empty?
|
!object.also_known_as.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def adults_only?
|
||||||
|
object.adults_only
|
||||||
|
end
|
||||||
|
|
||||||
class CustomEmojiSerializer < ActivityPub::EmojiSerializer
|
class CustomEmojiSerializer < ActivityPub::EmojiSerializer
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,8 @@ class REST::AccountSerializer < ActiveModel::Serializer
|
||||||
|
|
||||||
attributes :id, :username, :acct, :display_name, :locked, :bot, :created_at,
|
attributes :id, :username, :acct, :display_name, :locked, :bot, :created_at,
|
||||||
:note, :url, :avatar, :avatar_static, :header, :header_static,
|
:note, :url, :avatar, :avatar_static, :header, :header_static,
|
||||||
:followers_count, :following_count, :statuses_count, :replies
|
:followers_count, :following_count, :statuses_count, :replies,
|
||||||
|
:adults_only
|
||||||
|
|
||||||
has_one :moved_to_account, key: :moved, serializer: REST::AccountSerializer, if: :moved_and_not_nested?
|
has_one :moved_to_account, key: :moved, serializer: REST::AccountSerializer, if: :moved_and_not_nested?
|
||||||
has_many :emojis, serializer: REST::CustomEmojiSerializer
|
has_many :emojis, serializer: REST::CustomEmojiSerializer
|
||||||
|
|
|
@ -48,11 +48,13 @@ class ActivityPub::ProcessAccountService < BaseService
|
||||||
|
|
||||||
def create_account
|
def create_account
|
||||||
@account = Account.new
|
@account = Account.new
|
||||||
@account.username = @username
|
@account.username = @username
|
||||||
@account.domain = @domain
|
@account.domain = @domain
|
||||||
@account.private_key = nil
|
@account.private_key = nil
|
||||||
@account.suspended_at = domain_block.created_at if auto_suspend?
|
@account.suspended_at = domain_block.created_at if auto_suspend?
|
||||||
@account.silenced_at = domain_block.created_at if auto_silence?
|
@account.silenced_at = domain_block.created_at if auto_silence?
|
||||||
|
@account.force_unlisted = true if force_unlisted?
|
||||||
|
@account.force_sensitive = true if force_sensitive?
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_account
|
def update_account
|
||||||
|
@ -75,6 +77,7 @@ class ActivityPub::ProcessAccountService < BaseService
|
||||||
@account.display_name = @json['name'] || ''
|
@account.display_name = @json['name'] || ''
|
||||||
@account.note = @json['summary'] || ''
|
@account.note = @json['summary'] || ''
|
||||||
@account.locked = @json['manuallyApprovesFollowers'] || false
|
@account.locked = @json['manuallyApprovesFollowers'] || false
|
||||||
|
@account.adults_only = @json['suggestedMinAge'].to_i >= 18
|
||||||
@account.fields = property_values || {}
|
@account.fields = property_values || {}
|
||||||
@account.also_known_as = as_array(@json['alsoKnownAs'] || []).map { |item| value_or_id(item) }
|
@account.also_known_as = as_array(@json['alsoKnownAs'] || []).map { |item| value_or_id(item) }
|
||||||
@account.actor_type = actor_type
|
@account.actor_type = actor_type
|
||||||
|
@ -195,6 +198,14 @@ class ActivityPub::ProcessAccountService < BaseService
|
||||||
domain_block&.silence?
|
domain_block&.silence?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def auto_force_unlisted?
|
||||||
|
domain_block&.force_unlisted?
|
||||||
|
end
|
||||||
|
|
||||||
|
def auto_force_sensitive?
|
||||||
|
domain_block&.force_sensitive?
|
||||||
|
end
|
||||||
|
|
||||||
def domain_block
|
def domain_block
|
||||||
return @domain_block if defined?(@domain_block)
|
return @domain_block if defined?(@domain_block)
|
||||||
@domain_block = DomainBlock.find_by(domain: @domain)
|
@domain_block = DomainBlock.find_by(domain: @domain)
|
||||||
|
|
|
@ -12,8 +12,11 @@ class BlockDomainService < BaseService
|
||||||
|
|
||||||
def process_domain_block!
|
def process_domain_block!
|
||||||
clear_media! if domain_block.reject_media?
|
clear_media! if domain_block.reject_media?
|
||||||
|
force_accounts_sensitive! if domain_block.force_sensitive?
|
||||||
|
|
||||||
if domain_block.silence?
|
if domain_block.force_unlisted?
|
||||||
|
force_accounts_unlisted!
|
||||||
|
elsif domain_block.silence?
|
||||||
silence_accounts!
|
silence_accounts!
|
||||||
elsif domain_block.suspend?
|
elsif domain_block.suspend?
|
||||||
suspend_accounts!
|
suspend_accounts!
|
||||||
|
@ -28,6 +31,24 @@ class BlockDomainService < BaseService
|
||||||
@affected_status_ids.each { |id| Rails.cache.delete_matched("statuses/#{id}-*") }
|
@affected_status_ids.each { |id| Rails.cache.delete_matched("statuses/#{id}-*") }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def force_accounts_sensitive!
|
||||||
|
ApplicationRecord.transaction do
|
||||||
|
blocked_domain_accounts.in_batches.update_all(force_sensitive: true)
|
||||||
|
blocked_domain_accounts.reorder(nil).find_each do |account|
|
||||||
|
account.statuses.where(sensitive: false).in_batches.update_all(sensitive: true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def force_accounts_unlisted!
|
||||||
|
ApplicationRecord.transaction do
|
||||||
|
blocked_domain_accounts.in_batches.update_all(force_unlisted: true)
|
||||||
|
blocked_domain_accounts.reorder(nil).find_each do |account|
|
||||||
|
account.statuses.with_public_visibility.in_batches.update_all(visibility: :unlisted)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def silence_accounts!
|
def silence_accounts!
|
||||||
blocked_domain_accounts.without_silenced.in_batches.update_all(silenced_at: @domain_block.created_at)
|
blocked_domain_accounts.without_silenced.in_batches.update_all(silenced_at: @domain_block.created_at)
|
||||||
end
|
end
|
||||||
|
@ -44,7 +65,6 @@ class BlockDomainService < BaseService
|
||||||
|
|
||||||
def suspend_accounts!
|
def suspend_accounts!
|
||||||
blocked_domain_accounts.without_suspended.reorder(nil).find_each do |account|
|
blocked_domain_accounts.without_suspended.reorder(nil).find_each do |account|
|
||||||
UnsubscribeService.new.call(account) if account.subscribed?
|
|
||||||
SuspendAccountService.new.call(account, suspended_at: @domain_block.created_at)
|
SuspendAccountService.new.call(account, suspended_at: @domain_block.created_at)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -30,6 +30,7 @@ class PostStatusService < BaseService
|
||||||
@in_reply_to = @options[:thread]
|
@in_reply_to = @options[:thread]
|
||||||
@tags = @options[:tags]
|
@tags = @options[:tags]
|
||||||
@local_only = @options[:local_only]
|
@local_only = @options[:local_only]
|
||||||
|
@sensitive = (@account.force_sensitive? ? true : @options[:sensitive])
|
||||||
|
|
||||||
return idempotency_duplicate if idempotency_given? && idempotency_duplicate?
|
return idempotency_duplicate if idempotency_given? && idempotency_duplicate?
|
||||||
|
|
||||||
|
@ -58,7 +59,7 @@ class PostStatusService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
@visibility = @options[:visibility] || @account.user&.setting_default_privacy
|
@visibility = @options[:visibility] || @account.user&.setting_default_privacy
|
||||||
@visibility = :unlisted if @visibility == :public && @account.silenced?
|
@visibility = :unlisted if @visibility.in?([nil, 'public']) && @account.silenced? || @account.force_unlisted
|
||||||
|
|
||||||
if @in_reply_to.present? && @in_reply_to.visibility.present?
|
if @in_reply_to.present? && @in_reply_to.visibility.present?
|
||||||
v = %w(public unlisted private direct limited)
|
v = %w(public unlisted private direct limited)
|
||||||
|
@ -67,6 +68,8 @@ class PostStatusService < BaseService
|
||||||
|
|
||||||
@local_only = true if @account.user_always_local? || @in_reply_to&.local_only
|
@local_only = true if @account.user_always_local? || @in_reply_to&.local_only
|
||||||
|
|
||||||
|
@sensitive = (@account.default_sensitive? || @options[:spoiler_text].present?) if @sensitive.nil?
|
||||||
|
|
||||||
@scheduled_at = @options[:scheduled_at]&.to_datetime
|
@scheduled_at = @options[:scheduled_at]&.to_datetime
|
||||||
@scheduled_at = nil if scheduled_in_the_past?
|
@scheduled_at = nil if scheduled_in_the_past?
|
||||||
rescue ArgumentError
|
rescue ArgumentError
|
||||||
|
@ -176,7 +179,7 @@ class PostStatusService < BaseService
|
||||||
media_attachments: @media || [],
|
media_attachments: @media || [],
|
||||||
thread: @in_reply_to,
|
thread: @in_reply_to,
|
||||||
poll_attributes: poll_attributes,
|
poll_attributes: poll_attributes,
|
||||||
sensitive: (@options[:sensitive].nil? ? @account.user&.setting_default_sensitive : @options[:sensitive]) || @options[:spoiler_text].present?,
|
sensitive: @sensitive,
|
||||||
spoiler_text: @options[:spoiler_text] || '',
|
spoiler_text: @options[:spoiler_text] || '',
|
||||||
visibility: @visibility,
|
visibility: @visibility,
|
||||||
local_only: @local_only,
|
local_only: @local_only,
|
||||||
|
|
|
@ -27,6 +27,13 @@ class UnblockDomainService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def domain_block_impact
|
def domain_block_impact
|
||||||
domain_block.silence? ? :silenced_at : :suspended_at
|
case domain_block.severity
|
||||||
|
when :force_unlisted
|
||||||
|
:force_unlisted
|
||||||
|
when :silence
|
||||||
|
:silenced_at
|
||||||
|
when :suspend
|
||||||
|
:suspended_at
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -141,42 +141,51 @@
|
||||||
= fa_icon DeliveryFailureTracker.unavailable?(@account.shared_inbox_url) ? 'times' : 'check'
|
= fa_icon DeliveryFailureTracker.unavailable?(@account.shared_inbox_url) ? 'times' : 'check'
|
||||||
|
|
||||||
%div{ style: 'overflow: hidden' }
|
%div{ style: 'overflow: hidden' }
|
||||||
%div{ style: 'float: right' }
|
- if @account.local? && @account.user_approved?
|
||||||
- if @account.local?
|
= link_to t('admin.accounts.warn'), new_admin_account_action_path(@account.id, type: 'none'), class: 'button' if can?(:warn, @account)
|
||||||
= link_to t('admin.accounts.reset_password'), admin_account_reset_path(@account.id), method: :create, class: 'button' if can?(:reset_password, @account.user)
|
|
||||||
- if @account.user&.otp_required_for_login?
|
- if @account.force_sensitive?
|
||||||
= link_to t('admin.accounts.disable_two_factor_authentication'), admin_user_two_factor_authentication_path(@account.user.id), method: :delete, class: 'button' if can?(:disable_2fa, @account.user)
|
= link_to t('admin.accounts.allow_nonsensitive'), allow_nonsensitive_admin_account_path(@account.id), method: :post, class: 'button' if can?(:allow_nonsensitive, @account)
|
||||||
- if !@account.memorial? && @account.user_approved?
|
- elsif !@account.local? || @account.user_approved?
|
||||||
= link_to t('admin.accounts.memorialize'), memorialize_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive' if can?(:memorialize, @account)
|
= link_to t('admin.accounts.force_sensitive'), new_admin_account_action_path(@account.id, type: 'force_sensitive'), class: 'button button--destructive' if can?(:force_sensitive, @account)
|
||||||
|
|
||||||
|
- if @account.force_unlisted?
|
||||||
|
= link_to t('admin.accounts.allow_public'), allow_public_admin_account_path(@account.id), method: :post, class: 'button' if can?(:allow_public, @account)
|
||||||
|
- elsif !@account.local? || @account.user_approved?
|
||||||
|
= link_to t('admin.accounts.force_unlisted'), new_admin_account_action_path(@account.id, type: 'force_unlisted'), class: 'button button--destructive' if can?(:force_unlisted, @account)
|
||||||
|
|
||||||
|
- if @account.silenced?
|
||||||
|
= link_to t('admin.accounts.undo_silenced'), unsilence_admin_account_path(@account.id), method: :post, class: 'button' if can?(:unsilence, @account)
|
||||||
|
- elsif !@account.local? || @account.user_approved?
|
||||||
|
= 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.user_pending?
|
||||||
|
= link_to t('admin.accounts.approve'), approve_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button' if can?(:approve, @account.user)
|
||||||
|
= link_to t('admin.accounts.reject'), reject_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive' if can?(:reject, @account.user)
|
||||||
|
|
||||||
|
- unless @account.user_confirmed?
|
||||||
|
= link_to t('admin.accounts.confirm'), admin_account_confirmation_path(@account.id), method: :post, class: 'button' if can?(:confirm, @account.user)
|
||||||
|
|
||||||
|
- if @account.suspended?
|
||||||
|
= link_to t('admin.accounts.undo_suspension'), unsuspend_admin_account_path(@account.id), method: :post, class: 'button' if can?(:unsuspend, @account)
|
||||||
|
- elsif !@account.local? || @account.user_approved?
|
||||||
|
= 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)
|
||||||
|
|
||||||
|
- unless @account.local?
|
||||||
|
- if DomainBlock.where(domain: @account.domain).exists?
|
||||||
|
= link_to t('admin.domain_blocks.undo'), admin_instance_path(@account.domain), class: 'button'
|
||||||
- else
|
- else
|
||||||
= link_to t('admin.accounts.redownload'), redownload_admin_account_path(@account.id), method: :post, class: 'button' if can?(:redownload, @account)
|
= link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: @account.domain), class: 'button button--destructive'
|
||||||
|
|
||||||
%div{ style: 'float: left' }
|
- if @account.local?
|
||||||
- if @account.local? && @account.user_approved?
|
= link_to t('admin.accounts.reset_password'), admin_account_reset_path(@account.id), method: :create, class: 'button' if can?(:reset_password, @account.user)
|
||||||
= link_to t('admin.accounts.warn'), new_admin_account_action_path(@account.id, type: 'none'), class: 'button' if can?(:warn, @account)
|
- if @account.user&.otp_required_for_login?
|
||||||
- if @account.silenced?
|
= link_to t('admin.accounts.disable_two_factor_authentication'), admin_user_two_factor_authentication_path(@account.user.id), method: :delete, class: 'button' if can?(:disable_2fa, @account.user)
|
||||||
= link_to t('admin.accounts.undo_silenced'), unsilence_admin_account_path(@account.id), method: :post, class: 'button' if can?(:unsilence, @account)
|
- if !@account.memorial? && @account.user_approved?
|
||||||
- elsif !@account.local? || @account.user_approved?
|
= link_to t('admin.accounts.memorialize'), memorialize_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive' if can?(:memorialize, @account)
|
||||||
= link_to t('admin.accounts.silence'), new_admin_account_action_path(@account.id, type: 'silence'), class: 'button button--destructive' if can?(:silence, @account)
|
- else
|
||||||
|
= link_to t('admin.accounts.redownload'), redownload_admin_account_path(@account.id), method: :post, class: 'button' if can?(:redownload, @account)
|
||||||
- if @account.local?
|
|
||||||
- if @account.user_pending?
|
|
||||||
= link_to t('admin.accounts.approve'), approve_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button' if can?(:approve, @account.user)
|
|
||||||
= link_to t('admin.accounts.reject'), reject_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive' if can?(:reject, @account.user)
|
|
||||||
|
|
||||||
- unless @account.user_confirmed?
|
|
||||||
= link_to t('admin.accounts.confirm'), admin_account_confirmation_path(@account.id), method: :post, class: 'button' if can?(:confirm, @account.user)
|
|
||||||
|
|
||||||
- if @account.suspended?
|
|
||||||
= link_to t('admin.accounts.undo_suspension'), unsuspend_admin_account_path(@account.id), method: :post, class: 'button' if can?(:unsuspend, @account)
|
|
||||||
- elsif !@account.local? || @account.user_approved?
|
|
||||||
= 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)
|
|
||||||
|
|
||||||
- unless @account.local?
|
|
||||||
- if DomainBlock.where(domain: @account.domain).exists?
|
|
||||||
= link_to t('admin.domain_blocks.undo'), admin_instance_path(@account.domain), class: 'button'
|
|
||||||
- else
|
|
||||||
= link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: @account.domain), class: 'button button--destructive'
|
|
||||||
|
|
||||||
%hr.spacer/
|
%hr.spacer/
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
.fields-row__column.fields-row__column-6.fields-group
|
.fields-row__column.fields-row__column-6.fields-group
|
||||||
= f.input :severity, collection: DomainBlock.severities.keys, wrapper: :with_label, include_blank: false, label_method: lambda { |type| t(".severity.#{type}") }, hint: t('.severity.desc_html')
|
= f.input :severity, collection: DomainBlock.severities.keys, wrapper: :with_label, include_blank: false, label_method: lambda { |type| t(".severity.#{type}") }, hint: t('.severity.desc_html')
|
||||||
|
|
||||||
|
.fields-group
|
||||||
|
= f.input :force_sensitive, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.force_sensitive'), hint: I18n.t('admin.domain_blocks.force_sensitive_hint')
|
||||||
|
|
||||||
.fields-group
|
.fields-group
|
||||||
= f.input :reject_media, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_media'), hint: I18n.t('admin.domain_blocks.reject_media_hint')
|
= f.input :reject_media, as: :boolean, wrapper: :with_label, label: I18n.t('admin.domain_blocks.reject_media'), hint: I18n.t('admin.domain_blocks.reject_media_hint')
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,9 @@
|
||||||
= f.input :unlisted, as: :boolean, wrapper: :with_label, hint: t('simple_form.hints.defaults.unlisted')
|
= f.input :unlisted, as: :boolean, wrapper: :with_label, hint: t('simple_form.hints.defaults.unlisted')
|
||||||
= f.input :replies, as: :boolean, wrapper: :with_label
|
= f.input :replies, as: :boolean, wrapper: :with_label
|
||||||
|
|
||||||
|
.fields-group
|
||||||
|
= f.input :adults_only, as: :boolean, wrapper: :with_label, hint: t('simple_form.hints.defaults.adults_only')
|
||||||
|
|
||||||
.fields-group
|
.fields-group
|
||||||
= f.input :bot, as: :boolean, wrapper: :with_label, hint: t('simple_form.hints.defaults.bot')
|
= f.input :bot, as: :boolean, wrapper: :with_label, hint: t('simple_form.hints.defaults.bot')
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,7 @@ en:
|
||||||
moderator: Mod
|
moderator: Mod
|
||||||
kobold: Gently the kobold
|
kobold: Gently the kobold
|
||||||
gentlies_kobolds: Gentlies kobolds
|
gentlies_kobolds: Gentlies kobolds
|
||||||
|
adults_only: 🔞 Adult content
|
||||||
unavailable: Profile unavailable
|
unavailable: Profile unavailable
|
||||||
unfollow: Unfollow
|
unfollow: Unfollow
|
||||||
admin:
|
admin:
|
||||||
|
@ -134,6 +135,8 @@ en:
|
||||||
active: Active
|
active: Active
|
||||||
all: All
|
all: All
|
||||||
pending: Pending
|
pending: Pending
|
||||||
|
force_sensitive: Sensitive
|
||||||
|
force_unlisted: Unlisted
|
||||||
silenced: Silenced
|
silenced: Silenced
|
||||||
suspended: Suspended
|
suspended: Suspended
|
||||||
title: Moderation
|
title: Moderation
|
||||||
|
@ -175,6 +178,8 @@ en:
|
||||||
show:
|
show:
|
||||||
created_reports: Made reports
|
created_reports: Made reports
|
||||||
targeted_reports: Reported by others
|
targeted_reports: Reported by others
|
||||||
|
force_unlisted: Force unlisted
|
||||||
|
force_sensitive: Force sensitive
|
||||||
silence: Silence
|
silence: Silence
|
||||||
silenced: Silenced
|
silenced: Silenced
|
||||||
statuses: Statuses
|
statuses: Statuses
|
||||||
|
@ -182,6 +187,8 @@ en:
|
||||||
suspended: Suspended
|
suspended: Suspended
|
||||||
title: Accounts
|
title: Accounts
|
||||||
unconfirmed_email: Unconfirmed email
|
unconfirmed_email: Unconfirmed email
|
||||||
|
allow_nonsensitive: Allow non-sensitive
|
||||||
|
allow_public: Allow public
|
||||||
undo_silenced: Undo silence
|
undo_silenced: Undo silence
|
||||||
undo_suspension: Undo suspension
|
undo_suspension: Undo suspension
|
||||||
unsubscribe: Unsubscribe
|
unsubscribe: Unsubscribe
|
||||||
|
@ -213,9 +220,14 @@ en:
|
||||||
reopen_report: "%{name} reopened report %{target}"
|
reopen_report: "%{name} reopened report %{target}"
|
||||||
reset_password_user: "%{name} reset password of creature %{target}"
|
reset_password_user: "%{name} reset password of creature %{target}"
|
||||||
resolve_report: "%{name} resolved report %{target}"
|
resolve_report: "%{name} resolved report %{target}"
|
||||||
|
force_sensitive_user: "%{name} forced %{target}'s media to be marked sensitive"
|
||||||
|
force_sensitive_account: "%{name} forced %{target}'s media to be marked sensitive"
|
||||||
|
force_unlisted_account: "%{name} forced %{target}'s roars to be marked unlisted"
|
||||||
silence_account: "%{name} silenced %{target}'s account"
|
silence_account: "%{name} silenced %{target}'s account"
|
||||||
suspend_account: "%{name} suspended %{target}'s account"
|
suspend_account: "%{name} suspended %{target}'s account"
|
||||||
unassigned_report: "%{name} unassigned report %{target}"
|
unassigned_report: "%{name} unassigned report %{target}"
|
||||||
|
allow_nonsensitive_account: "%{name} allowed non-sensitive media from %{target}'s account"
|
||||||
|
allow_public_account: "%{name} allowed public roars from %{target}'s account"
|
||||||
unsilence_account: "%{name} unsilenced %{target}'s account"
|
unsilence_account: "%{name} unsilenced %{target}'s account"
|
||||||
unsuspend_account: "%{name} unsuspended %{target}'s account"
|
unsuspend_account: "%{name} unsuspended %{target}'s account"
|
||||||
update_custom_emoji: "%{name} updated emoji %{target}"
|
update_custom_emoji: "%{name} updated emoji %{target}"
|
||||||
|
@ -281,11 +293,14 @@ en:
|
||||||
create: Create block
|
create: Create block
|
||||||
hint: The domain block will not prevent creation of account entries in the database, but will retroactively and automatically apply specific moderation methods on those accounts.
|
hint: The domain block will not prevent creation of account entries in the database, but will retroactively and automatically apply specific moderation methods on those accounts.
|
||||||
severity:
|
severity:
|
||||||
desc_html: "<strong>Silence</strong> will make the account's roars invisible to anyone who isn't following them. <strong>Suspend</strong> will remove all of the account's content, media, and profile data. Use <strong>None</strong> if you just want to reject media files."
|
desc_html: "<strong>Force Unlisted</strong> will force the account's roars to a maximum of unlisted visibility. <strong>Silence</strong> will make the account's roars invisible to anyone who isn't following them as well as disable notification. <strong>Suspend</strong> will remove all of the account's content, media, and profile data. Use <strong>None</strong> if you just want to reject media files."
|
||||||
noop: None
|
noop: None
|
||||||
|
force_unlisted: Force unlisted
|
||||||
silence: Silence
|
silence: Silence
|
||||||
suspend: Suspend
|
suspend: Suspend
|
||||||
title: New domain block
|
title: New domain block
|
||||||
|
force_sensitive: Mark media sensitive
|
||||||
|
force_sensitive_hint: Forces all media from this domain to be marked sensitive.
|
||||||
reject_media: Reject media files
|
reject_media: Reject media files
|
||||||
reject_media_hint: Removes locally stored media files and refuses to download any in the future. Irrelevant for suspensions
|
reject_media_hint: Removes locally stored media files and refuses to download any in the future. Irrelevant for suspensions
|
||||||
reject_reports: Reject reports
|
reject_reports: Reject reports
|
||||||
|
@ -293,15 +308,17 @@ en:
|
||||||
rejecting_media: rejecting media files
|
rejecting_media: rejecting media files
|
||||||
rejecting_reports: rejecting reports
|
rejecting_reports: rejecting reports
|
||||||
severity:
|
severity:
|
||||||
|
force_unlisted: force unlisted
|
||||||
silence: silenced
|
silence: silenced
|
||||||
suspend: suspended
|
suspend: suspended
|
||||||
show:
|
show:
|
||||||
affected_accounts:
|
affected_accounts:
|
||||||
one: One account in the database affected
|
one: One account affected
|
||||||
other: "%{count} accounts in the database affected"
|
other: "%{count} accounts affected"
|
||||||
retroactive:
|
retroactive:
|
||||||
silence: Unsilence existing affected accounts from this domain
|
silence: Unsilence existing affected accounts from this domain
|
||||||
suspend: Unsuspend existing affected accounts from this domain
|
suspend: Unsuspend existing affected accounts from this domain
|
||||||
|
force_unlisted: Allow public roars on all existing accounts from this domain
|
||||||
title: Undo domain block for %{domain}
|
title: Undo domain block for %{domain}
|
||||||
undo: Undo
|
undo: Undo
|
||||||
undo: Undo domain block
|
undo: Undo domain block
|
||||||
|
@ -1057,18 +1074,24 @@ en:
|
||||||
warning:
|
warning:
|
||||||
explanation:
|
explanation:
|
||||||
disable: While your account is frozen, your account data remains intact, but you cannot perform any actions until it is unlocked.
|
disable: While your account is frozen, your account data remains intact, but you cannot perform any actions until it is unlocked.
|
||||||
|
force_sensitive: Your account's media has been forced to sensitive visibility until this limit is removed by a moderator.
|
||||||
|
force_unlisted: Your account's roars have been forced to unlisted visibility until this limit is removed by a moderator.
|
||||||
silence: While your account is limited, only monsters who are already following you will see your roars on this server, and you may be excluded from various public listings. However, others may still manually join your pack.
|
silence: While your account is limited, only monsters who are already following you will see your roars on this server, and you may be excluded from various public listings. However, others may still manually join your pack.
|
||||||
suspend: Your account has been suspended, and all of your roars and your uploaded media files have been irreversibly removed from this server, and servers where you had packmates.
|
suspend: Your account has been suspended. All of your roars and your uploaded media files have been irreversibly removed from this server, and servers where you had packmates.
|
||||||
review_server_policies: Review server policies
|
review_server_policies: Review server policies
|
||||||
subject:
|
subject:
|
||||||
disable: Your account %{acct} has been frozen
|
disable: "%{acct}, you account has been frozen."
|
||||||
none: Warning for %{acct}
|
none: "%{acct}, you've been given a moderation warning."
|
||||||
silence: Your account %{acct} has been limited
|
force_sensitive: "%{acct}, your account's media visibility has been limited."
|
||||||
suspend: Your account %{acct} has been suspended
|
force_unlisted: "%{acct}, your account's roar visibility has been limited."
|
||||||
|
silence: "%{acct}, your account has been silenced."
|
||||||
|
suspend: "%{acct}, your account has been suspended."
|
||||||
title:
|
title:
|
||||||
disable: Account frozen
|
disable: Account frozen
|
||||||
none: Warning
|
none: Warning
|
||||||
silence: Account limited
|
force_sensitive: Media visibility limited
|
||||||
|
force_unlisted: Roar visibility limited
|
||||||
|
silence: Account silenced
|
||||||
suspend: Account suspended
|
suspend: Account suspended
|
||||||
welcome:
|
welcome:
|
||||||
edit_profile_action: Setup profile
|
edit_profile_action: Setup profile
|
||||||
|
|
|
@ -11,6 +11,7 @@ en:
|
||||||
warning_preset_id: Optional. You can still add custom text to end of the preset
|
warning_preset_id: Optional. You can still add custom text to end of the preset
|
||||||
defaults:
|
defaults:
|
||||||
hidden: Toggles whether your public profile is publicaly accessible
|
hidden: Toggles whether your public profile is publicaly accessible
|
||||||
|
adults_only: This account may contain mature or sensitive content
|
||||||
unlisted: Excludes you from public repeated/admired by lists of *local* monsters
|
unlisted: Excludes you from public repeated/admired by lists of *local* monsters
|
||||||
autofollow: People who sign up through the invite will automatically join your pack
|
autofollow: People who sign up through the invite will automatically join your pack
|
||||||
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
|
||||||
|
@ -66,11 +67,14 @@ en:
|
||||||
types:
|
types:
|
||||||
disable: Disable
|
disable: Disable
|
||||||
none: Do nothing
|
none: Do nothing
|
||||||
|
force_sensitive: Force sensitive
|
||||||
|
force_unlisted: Force unlisted
|
||||||
silence: Silence
|
silence: Silence
|
||||||
suspend: Suspend and irreversibly delete account data
|
suspend: Suspend and irreversibly delete account data
|
||||||
warning_preset_id: Use a warning preset
|
warning_preset_id: Use a warning preset
|
||||||
defaults:
|
defaults:
|
||||||
hidden: Disable your public profile
|
hidden: Disable your public profile
|
||||||
|
adults_only: Adult content
|
||||||
unlisted: Exclude from public interaction lists
|
unlisted: Exclude from public interaction lists
|
||||||
replies: Show your public replies
|
replies: Show your public replies
|
||||||
autofollow: Invite to join your pack
|
autofollow: Invite to join your pack
|
||||||
|
|
|
@ -188,6 +188,10 @@ Rails.application.routes.draw do
|
||||||
post :subscribe
|
post :subscribe
|
||||||
post :unsubscribe
|
post :unsubscribe
|
||||||
post :enable
|
post :enable
|
||||||
|
post :force_sensitive
|
||||||
|
post :force_unlisted
|
||||||
|
post :allow_public
|
||||||
|
post :allow_nonsensitive
|
||||||
post :unsilence
|
post :unsilence
|
||||||
post :unsuspend
|
post :unsuspend
|
||||||
post :redownload
|
post :redownload
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
require Rails.root.join('lib', 'mastodon', 'migration_helpers')
|
||||||
|
class AddForceSensitiveToDomainBlocks < ActiveRecord::Migration[5.2]
|
||||||
|
include Mastodon::MigrationHelpers
|
||||||
|
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def up
|
||||||
|
safety_assured do
|
||||||
|
add_column_with_default :domain_blocks, :force_sensitive, :boolean, default: false, allow_null: false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
remove_column :domain_blocks, :force_sensitive
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,6 @@
|
||||||
|
class AddNetworkIndexToStatuses < ActiveRecord::Migration[5.2]
|
||||||
|
disable_ddl_transaction!
|
||||||
|
def change
|
||||||
|
add_index :statuses, :network, where: :network, algorithm: :concurrently
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,19 @@
|
||||||
|
class UpdateDomainBlockSeverityEnum < ActiveRecord::Migration[5.2]
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def up
|
||||||
|
DomainBlock.where(severity: :force_unlisted).each do |block|
|
||||||
|
block.severity = :suspend
|
||||||
|
block.save
|
||||||
|
end
|
||||||
|
|
||||||
|
DomainBlock.where(severity: :noop).each do |block|
|
||||||
|
block.severity = :silence
|
||||||
|
block.save
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
raise ActiveRecord::IrreversibleMigration
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,8 @@
|
||||||
|
class AddForceOptionsToAccounts < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
safety_assured {
|
||||||
|
add_column :accounts, :force_unlisted, :boolean, null: false, default: false
|
||||||
|
add_column :accounts, :force_sensitive, :boolean, null: false, default: false
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddAdultsOnlyToAccounts < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
safety_assured { add_column :accounts, :adults_only, :boolean, null: false, default: false }
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,19 @@
|
||||||
|
class UpdateAccountWarningActionEnum < ActiveRecord::Migration[5.2]
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def up
|
||||||
|
AccountWarning.where(action: :force_unlisted).each do |warning|
|
||||||
|
warning.severity = :suspend
|
||||||
|
warning.save
|
||||||
|
end
|
||||||
|
|
||||||
|
AccountWarning.where(action: :force_sensitive).each do |warning|
|
||||||
|
warning.severity = :silence
|
||||||
|
warning.save
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
raise ActiveRecord::IrreversibleMigration
|
||||||
|
end
|
||||||
|
end
|
|
@ -151,6 +151,9 @@ ActiveRecord::Schema.define(version: 2019_05_19_130537) do
|
||||||
t.jsonb "vars", default: {}, null: false
|
t.jsonb "vars", default: {}, null: false
|
||||||
t.boolean "replies", default: true, null: false
|
t.boolean "replies", default: true, null: false
|
||||||
t.boolean "unlisted", default: false, null: false
|
t.boolean "unlisted", default: false, null: false
|
||||||
|
t.boolean "force_unlisted", default: false, null: false
|
||||||
|
t.boolean "force_sensitive", default: false, null: false
|
||||||
|
t.boolean "adults_only", default: false, null: false
|
||||||
t.index "(((setweight(to_tsvector('simple'::regconfig, (display_name)::text), 'A'::\"char\") || setweight(to_tsvector('simple'::regconfig, (username)::text), 'B'::\"char\")) || setweight(to_tsvector('simple'::regconfig, (COALESCE(domain, ''::character varying))::text), 'C'::\"char\")))", name: "search_index", using: :gin
|
t.index "(((setweight(to_tsvector('simple'::regconfig, (display_name)::text), 'A'::\"char\") || setweight(to_tsvector('simple'::regconfig, (username)::text), 'B'::\"char\")) || setweight(to_tsvector('simple'::regconfig, (COALESCE(domain, ''::character varying))::text), 'C'::\"char\")))", name: "search_index", using: :gin
|
||||||
t.index "lower((username)::text), lower((domain)::text)", name: "index_accounts_on_username_and_domain_lower", unique: true
|
t.index "lower((username)::text), lower((domain)::text)", name: "index_accounts_on_username_and_domain_lower", unique: true
|
||||||
t.index ["moved_to_account_id"], name: "index_accounts_on_moved_to_account_id"
|
t.index ["moved_to_account_id"], name: "index_accounts_on_moved_to_account_id"
|
||||||
|
@ -258,6 +261,7 @@ ActiveRecord::Schema.define(version: 2019_05_19_130537) do
|
||||||
t.integer "severity", default: 0
|
t.integer "severity", default: 0
|
||||||
t.boolean "reject_media", default: false, null: false
|
t.boolean "reject_media", default: false, null: false
|
||||||
t.boolean "reject_reports", default: false, null: false
|
t.boolean "reject_reports", default: false, null: false
|
||||||
|
t.boolean "force_sensitive", default: false, null: false
|
||||||
t.index ["domain"], name: "index_domain_blocks_on_domain", unique: true
|
t.index ["domain"], name: "index_domain_blocks_on_domain", unique: true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -651,6 +655,7 @@ ActiveRecord::Schema.define(version: 2019_05_19_130537) do
|
||||||
t.index ["account_id", "id", "visibility", "updated_at"], name: "index_statuses_20180106", order: { id: :desc }
|
t.index ["account_id", "id", "visibility", "updated_at"], name: "index_statuses_20180106", order: { id: :desc }
|
||||||
t.index ["in_reply_to_account_id"], name: "index_statuses_on_in_reply_to_account_id"
|
t.index ["in_reply_to_account_id"], name: "index_statuses_on_in_reply_to_account_id"
|
||||||
t.index ["in_reply_to_id"], name: "index_statuses_on_in_reply_to_id"
|
t.index ["in_reply_to_id"], name: "index_statuses_on_in_reply_to_id"
|
||||||
|
t.index ["network"], name: "index_statuses_on_network", where: "network"
|
||||||
t.index ["reblog_of_id", "account_id"], name: "index_statuses_on_reblog_of_id_and_account_id"
|
t.index ["reblog_of_id", "account_id"], name: "index_statuses_on_reblog_of_id_and_account_id"
|
||||||
t.index ["tsv"], name: "tsv_idx", using: :gin
|
t.index ["tsv"], name: "tsv_idx", using: :gin
|
||||||
t.index ["uri"], name: "index_statuses_on_uri", unique: true
|
t.index ["uri"], name: "index_statuses_on_uri", unique: true
|
||||||
|
|
Loading…
Reference in New Issue