Add: #363 特定サーバーの投稿にスタンプを付けることを禁止する管理者設定 (#364)

* Add: #363 特定サーバーの投稿にスタンプを付けることを禁止する管理者設定

* Fix test
This commit is contained in:
KMY(雪あすか) 2023-12-19 08:33:06 +09:00 committed by GitHub
parent 08f2fcb72b
commit 7b8fedb3cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 157 additions and 26 deletions

View file

@ -0,0 +1,34 @@
# frozen_string_literal: true
module Admin
class SpecialInstancesController < BaseController
def show
authorize :instance, :show?
@admin_settings = Form::AdminSettings.new
end
def create
authorize :instance, :destroy?
@admin_settings = Form::AdminSettings.new(settings_params)
if @admin_settings.save
flash[:notice] = I18n.t('generic.changes_saved_msg')
redirect_to after_update_redirect_path
else
render :show
end
end
private
def after_update_redirect_path
admin_special_instances_path
end
def settings_params
params.require(:form_admin_settings).permit(*Form::AdminSettings::KEYS)
end
end
end

View file

@ -9,11 +9,17 @@ module Account::OtherSettings
end end
def noai? def noai?
user&.setting_noai || (settings.present? && settings['noai']) || false return user.setting_noai if local? && user.present?
return settings['noai'] if settings.present? && settings.key?('noai')
false
end end
def translatable_private? def translatable_private?
user&.setting_translatable_private || (settings.present? && settings['translatable_private']) || false return user.setting_translatable_private if local? && user.present?
return settings['translatable_private'] if settings.present? && settings.key?('translatable_private')
false
end end
def link_preview? def link_preview?
@ -31,30 +37,31 @@ module Account::OtherSettings
end end
def hide_statuses_count? def hide_statuses_count?
return user&.setting_hide_statuses_count unless user&.setting_hide_statuses_count.nil? return user&.setting_hide_statuses_count if local? && user.present?
return settings['hide_statuses_count'] if settings.present? return settings['hide_statuses_count'] if settings.present? && settings.key?('hide_statuses_count')
false false
end end
def hide_following_count? def hide_following_count?
return user&.setting_hide_following_count unless user&.setting_hide_following_count.nil? return user&.setting_hide_following_count if local? && user.present?
return settings['hide_following_count'] if settings.present? return settings['hide_following_count'] if settings.present? && settings.key?('hide_following_count')
false false
end end
def hide_followers_count? def hide_followers_count?
return user&.setting_hide_followers_count unless user&.setting_hide_followers_count.nil? return user&.setting_hide_followers_count if local? && user.present?
return settings['hide_followers_count'] if settings.present? return settings['hide_followers_count'] if settings.present? && settings.key?('hide_followers_count')
false false
end end
def emoji_reaction_policy def emoji_reaction_policy
return settings['emoji_reaction_policy']&.to_sym || :allow if settings.present? && user.nil? return :block if !local? && Setting.emoji_reaction_disallow_domains&.include?(domain)
return settings['emoji_reaction_policy']&.to_sym || :allow if settings.present? && !local?
return :allow if user.nil? return :allow if user.nil?
return :block if local? && !Setting.enable_emoji_reaction return :block if local? && !Setting.enable_emoji_reaction # for federation
user.setting_emoji_reaction_policy&.to_sym user.setting_emoji_reaction_policy&.to_sym
end end
@ -88,7 +95,7 @@ module Account::OtherSettings
def public_settings def public_settings
# Please update `app/javascript/mastodon/api_types/accounts.ts` when making changes to the attributes # Please update `app/javascript/mastodon/api_types/accounts.ts` when making changes to the attributes
config = { {
'noindex' => noindex?, 'noindex' => noindex?,
'noai' => noai?, 'noai' => noai?,
'hide_network' => hide_collections, 'hide_network' => hide_collections,
@ -98,10 +105,8 @@ module Account::OtherSettings
'translatable_private' => translatable_private?, 'translatable_private' => translatable_private?,
'link_preview' => link_preview?, 'link_preview' => link_preview?,
'allow_quote' => allow_quote?, 'allow_quote' => allow_quote?,
'emoji_reaction_policy' => Setting.enable_emoji_reaction ? emoji_reaction_policy : :block, 'emoji_reaction_policy' => Setting.enable_emoji_reaction ? emoji_reaction_policy.to_s : 'block',
} }
config = config.merge(settings) if settings.present?
config
end end
def public_settings_for_local def public_settings_for_local

View file

@ -52,6 +52,7 @@ class Form::AdminSettings
enable_public_unlisted_visibility enable_public_unlisted_visibility
unlocked_friend unlocked_friend
enable_local_timeline enable_local_timeline
emoji_reaction_disallow_domains
).freeze ).freeze
INTEGER_KEYS = %i( INTEGER_KEYS = %i(
@ -99,6 +100,7 @@ class Form::AdminSettings
ng_words_for_stranger_mention ng_words_for_stranger_mention
sensitive_words sensitive_words
sensitive_words_for_full sensitive_words_for_full
emoji_reaction_disallow_domains
).freeze ).freeze
attr_accessor(*KEYS) attr_accessor(*KEYS)

View file

@ -0,0 +1,14 @@
- content_for :page_title do
= t('admin.special_instances.title')
- content_for :header_tags do
= javascript_pack_tag 'admin', async: true, crossorigin: 'anonymous'
= simple_form_for @admin_settings, url: admin_special_instances_path, html: { method: :post } do |f|
= render 'shared/error_messages', object: @admin_settings
.fields-group
= f.input :emoji_reaction_disallow_domains, wrapper: :with_label, as: :text, input_html: { rows: 6 }, label: t('admin.special_instances.emoji_reaction_disallow_domains'), hint: t('admin.special_instances.emoji_reaction_disallow_domains_hint')
.actions
= f.button :button, t('generic.save_changes'), type: :submit

View file

@ -911,6 +911,10 @@ en:
minor: Minor release minor: Minor release
patch: Patch release — bugfixes and easy to apply changes patch: Patch release — bugfixes and easy to apply changes
version: Version version: Version
special_instances:
emoji_reaction_disallow_domains: Domains we are not permitted stamp
emoji_reaction_disallow_domains_hint: If you need to be considerate to your coalition partners, set the domain with a new line separator. It is not possible to put a stamp on a post from a set domain.
title: Special servers
statuses: statuses:
account: Author account: Author
application: Application application: Application

View file

@ -909,6 +909,10 @@ ja:
minor: マイナーリリース minor: マイナーリリース
patch: パッチ (バグ修正のみ) patch: パッチ (バグ修正のみ)
version: バージョン version: バージョン
special_instances:
emoji_reaction_disallow_domains: 自分がスタンプをつけることを許可しないドメイン
emoji_reaction_disallow_domains_hint: 連合先に配慮する必要がある場合、ドメインを改行区切りで設定します。設定されたドメインの投稿にスタンプを付けることはできません。
title: 特殊なサーバー
statuses: statuses:
account: 作成者 account: 作成者
application: アプリ application: アプリ

View file

@ -54,6 +54,7 @@ SimpleNavigation::Configuration.run do |navigation|
s.item :invites, safe_join([fa_icon('user-plus fw'), t('admin.invites.title')]), admin_invites_path, if: -> { current_user.can?(:manage_invites) } s.item :invites, safe_join([fa_icon('user-plus fw'), t('admin.invites.title')]), admin_invites_path, if: -> { current_user.can?(:manage_invites) }
s.item :follow_recommendations, safe_join([fa_icon('user-plus fw'), t('admin.follow_recommendations.title')]), admin_follow_recommendations_path, highlights_on: %r{/admin/follow_recommendations}, if: -> { current_user.can?(:manage_taxonomies) } s.item :follow_recommendations, safe_join([fa_icon('user-plus fw'), t('admin.follow_recommendations.title')]), admin_follow_recommendations_path, highlights_on: %r{/admin/follow_recommendations}, if: -> { current_user.can?(:manage_taxonomies) }
s.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_path(limited: limited_federation_mode? ? nil : '1'), highlights_on: %r{/admin/instances|/admin/domain_blocks|/admin/domain_allows}, if: -> { current_user.can?(:manage_federation) } s.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_path(limited: limited_federation_mode? ? nil : '1'), highlights_on: %r{/admin/instances|/admin/domain_blocks|/admin/domain_allows}, if: -> { current_user.can?(:manage_federation) }
s.item :special_instances, safe_join([fa_icon('list fw'), t('admin.special_instances.title')]), admin_special_instances_path, highlights_on: %r{/admin/special_instances}, if: -> { current_user.can?(:manage_federation) }
s.item :email_domain_blocks, safe_join([fa_icon('envelope fw'), t('admin.email_domain_blocks.title')]), admin_email_domain_blocks_path, highlights_on: %r{/admin/email_domain_blocks}, if: -> { current_user.can?(:manage_blocks) } s.item :email_domain_blocks, safe_join([fa_icon('envelope fw'), t('admin.email_domain_blocks.title')]), admin_email_domain_blocks_path, highlights_on: %r{/admin/email_domain_blocks}, if: -> { current_user.can?(:manage_blocks) }
s.item :ip_blocks, safe_join([fa_icon('ban fw'), t('admin.ip_blocks.title')]), admin_ip_blocks_path, highlights_on: %r{/admin/ip_blocks}, if: -> { current_user.can?(:manage_blocks) } s.item :ip_blocks, safe_join([fa_icon('ban fw'), t('admin.ip_blocks.title')]), admin_ip_blocks_path, highlights_on: %r{/admin/ip_blocks}, if: -> { current_user.can?(:manage_blocks) }
s.item :action_logs, safe_join([fa_icon('bars fw'), t('admin.action_logs.title')]), admin_action_logs_path, if: -> { current_user.can?(:view_audit_log) } s.item :action_logs, safe_join([fa_icon('bars fw'), t('admin.action_logs.title')]), admin_action_logs_path, if: -> { current_user.can?(:view_audit_log) }

View file

@ -34,6 +34,7 @@ namespace :admin do
resources :warning_presets, except: [:new, :show] resources :warning_presets, except: [:new, :show]
resource :ng_words, only: [:show, :create] resource :ng_words, only: [:show, :create]
resource :sensitive_words, only: [:show, :create] resource :sensitive_words, only: [:show, :create]
resource :special_instances, only: [:show, :create]
resources :announcements, except: [:show] do resources :announcements, except: [:show] do
member do member do

View file

@ -46,6 +46,7 @@ defaults: &defaults
unlocked_friend: false unlocked_friend: false
stranger_mention_from_local_ng: true stranger_mention_from_local_ng: true
enable_local_timeline: true enable_local_timeline: true
emoji_reaction_disallow_domains: []
development: development:
<<: *defaults <<: *defaults

View file

@ -270,38 +270,38 @@ RSpec.describe Account do
reactioned.follow!(mutual) reactioned.follow!(mutual)
end end
shared_examples 'with policy' do |override_policy, anyone_r, followee_r, follower_r, mutual_r, self_r| # rubocop:disable Metrics/ParameterLists shared_examples 'with policy' do |override_policy, permitted|
context "when policy is #{override_policy}" do context "when policy is #{override_policy}" do
let(:policy) { override_policy } let(:policy) { override_policy }
it 'allows anyone' do it 'allows anyone' do
expect(reactioned.allow_emoji_reaction?(anyone)).to be anyone_r expect(reactioned.allow_emoji_reaction?(anyone)).to be permitted.include?(:anyone)
end end
it 'allows followee' do it 'allows followee' do
expect(reactioned.allow_emoji_reaction?(followee)).to be followee_r expect(reactioned.allow_emoji_reaction?(followee)).to be permitted.include?(:following)
end end
it 'allows follower' do it 'allows follower' do
expect(reactioned.allow_emoji_reaction?(follower)).to be follower_r expect(reactioned.allow_emoji_reaction?(follower)).to be permitted.include?(:followers)
end end
it 'allows mutual' do it 'allows mutual' do
expect(reactioned.allow_emoji_reaction?(mutual)).to be mutual_r expect(reactioned.allow_emoji_reaction?(mutual)).to be permitted.include?(:mutuals)
end end
it 'allows self' do it 'allows self' do
expect(reactioned.allow_emoji_reaction?(reactioned)).to be self_r expect(reactioned.allow_emoji_reaction?(reactioned)).to be permitted.include?(:self)
end end
end end
end end
it_behaves_like 'with policy', :allow, true, true, true, true, true it_behaves_like 'with policy', :allow, %i(anyone following followers mutuals self)
it_behaves_like 'with policy', :outside_only, false, true, true, true, true it_behaves_like 'with policy', :outside_only, %i(following followers mutuals self)
it_behaves_like 'with policy', :following_only, false, true, false, true, true it_behaves_like 'with policy', :following_only, %i(following mutuals self)
it_behaves_like 'with policy', :followers_only, false, false, true, true, true it_behaves_like 'with policy', :followers_only, %i(followers mutuals self)
it_behaves_like 'with policy', :mutuals_only, false, false, false, true, true it_behaves_like 'with policy', :mutuals_only, %i(mutuals self)
it_behaves_like 'with policy', :block, false, false, false, false, false it_behaves_like 'with policy', :block, %i()
shared_examples 'allow local only' do |override_policy| shared_examples 'allow local only' do |override_policy|
context "when policy is #{override_policy} but allow local only" do context "when policy is #{override_policy} but allow local only" do
@ -371,6 +371,71 @@ RSpec.describe Account do
end end
end end
describe '#emoji_reaction_policy' do
subject { account.emoji_reaction_policy }
let(:domains) { 'example.com' }
let(:account) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/actor') }
before do
Form::AdminSettings.new(emoji_reaction_disallow_domains: domains).save
end
it 'blocked if target domain' do
expect(subject).to eq :block
end
context 'when other domain' do
let(:account) { Fabricate(:account, domain: 'allow.example.com', uri: 'https://allow.example.com/actor') }
it 'allowed if target domain' do
expect(subject).to_not eq :block
end
end
end
describe '#public_settings_for_local' do
subject { account.public_settings_for_local }
let(:account) { Fabricate(:user, settings: { link_preview: false, allow_quote: true, hide_statuses_count: true, emoji_reaction_policy: :followers_only }).account }
shared_examples 'some settings' do |permitted, emoji_reaction_policy|
it 'link_preview is disallowed' do
expect(subject['link_preview']).to be permitted.include?(:link_preview)
end
it 'allow_quote is allowed' do
expect(subject['allow_quote']).to be permitted.include?(:allow_quote)
end
it 'hide_statuses_count is allowed' do
expect(subject['hide_statuses_count']).to be permitted.include?(:hide_statuses_count)
end
it 'hide_following_count is disallowed' do
expect(subject['hide_following_count']).to be permitted.include?(:hide_following_count)
end
it 'emoji_reaction is allowed followers' do
expect(subject['emoji_reaction_policy']).to eq emoji_reaction_policy
end
end
it_behaves_like 'some settings', %i(allow_quote hide_statuses_count), 'followers_only'
context 'when remote user' do
let(:account) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/actor', settings: { 'link_preview' => false, 'allow_quote' => true, 'hide_statuses_count' => true, 'emoji_reaction_policy' => 'followers_only' }) }
it_behaves_like 'some settings', %i(allow_quote hide_statuses_count), 'followers_only'
end
context 'when remote user by server other_settings is not supported' do
let(:account) { Fabricate(:account, domain: 'example.com', uri: 'https://example.com/actor') }
it_behaves_like 'some settings', %i(link_preview allow_quote), 'allow'
end
end
describe '#favourited?' do describe '#favourited?' do
subject { Fabricate(:account) } subject { Fabricate(:account) }