Add: #559 公開投稿を禁止する管理者設定 (#564)

This commit is contained in:
KMY(雪あすか) 2024-02-16 18:43:43 +09:00 committed by GitHub
parent f1ce14e396
commit c534c3d7fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 29 additions and 3 deletions

View file

@ -28,6 +28,7 @@ module KmyblueCapabilitiesHelper
end end
capabilities << :kmyblue_visibility_public_unlisted if Setting.enable_public_unlisted_visibility capabilities << :kmyblue_visibility_public_unlisted if Setting.enable_public_unlisted_visibility
capabilities << :kmyblue_searchability_public_unlisted if Setting.enable_public_unlisted_visibility capabilities << :kmyblue_searchability_public_unlisted if Setting.enable_public_unlisted_visibility
capabilities << :kmyblue_no_public_visibility unless Setting.enable_public_visibility
capabilities << :timeline_no_local unless Setting.enable_local_timeline capabilities << :timeline_no_local unless Setting.enable_local_timeline
capabilities capabilities

View file

@ -35,6 +35,7 @@ const messages = defineMessages({
suspended: { id: 'about.domain_blocks.suspended.title', defaultMessage: 'Suspended' }, suspended: { id: 'about.domain_blocks.suspended.title', defaultMessage: 'Suspended' },
suspendedExplanation: { id: 'about.domain_blocks.suspended.explanation', defaultMessage: 'No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.' }, suspendedExplanation: { id: 'about.domain_blocks.suspended.explanation', defaultMessage: 'No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.' },
publicUnlistedVisibility: { id: 'privacy.public_unlisted.short', defaultMessage: 'Public unlisted' }, publicUnlistedVisibility: { id: 'privacy.public_unlisted.short', defaultMessage: 'Public unlisted' },
publicVisibility: { id: 'about.public_visibility', defaultMessage: 'Public visibility' },
emojiReaction: { id: 'status.emoji_reaction', defaultMessage: 'Emoji reaction' }, emojiReaction: { id: 'status.emoji_reaction', defaultMessage: 'Emoji reaction' },
enabled: { id: 'about.enabled', defaultMessage: 'Enabled' }, enabled: { id: 'about.enabled', defaultMessage: 'Enabled' },
disabled: { id: 'about.disabled', defaultMessage: 'Disabled' }, disabled: { id: 'about.disabled', defaultMessage: 'Disabled' },
@ -157,6 +158,7 @@ class About extends PureComponent {
const fedibirdCapabilities = server.get('fedibird_capabilities') || []; // thinking about isLoading is true const fedibirdCapabilities = server.get('fedibird_capabilities') || []; // thinking about isLoading is true
const isPublicUnlistedVisibility = fedibirdCapabilities.includes('kmyblue_visibility_public_unlisted'); const isPublicUnlistedVisibility = fedibirdCapabilities.includes('kmyblue_visibility_public_unlisted');
const isPublicVisibility = !fedibirdCapabilities.includes('kmyblue_no_public_visibility');
const isEmojiReaction = fedibirdCapabilities.includes('emoji_reaction'); const isEmojiReaction = fedibirdCapabilities.includes('emoji_reaction');
const isLocalTimeline = !fedibirdCapabilities.includes('timeline_no_local'); const isLocalTimeline = !fedibirdCapabilities.includes('timeline_no_local');
@ -232,6 +234,9 @@ class About extends PureComponent {
<li> <li>
<span className='rules-list__text'>{intl.formatMessage(messages.emojiReaction)}: <CapabilityIcon state={isEmojiReaction} intl={intl} /></span> <span className='rules-list__text'>{intl.formatMessage(messages.emojiReaction)}: <CapabilityIcon state={isEmojiReaction} intl={intl} /></span>
</li> </li>
<li>
<span className='rules-list__text'>{intl.formatMessage(messages.publicVisibility)}: <CapabilityIcon state={isPublicVisibility} intl={intl} /></span>
</li>
<li> <li>
<span className='rules-list__text'>{intl.formatMessage(messages.publicUnlistedVisibility)}: <CapabilityIcon state={isPublicUnlistedVisibility} intl={intl} /></span> <span className='rules-list__text'>{intl.formatMessage(messages.publicUnlistedVisibility)}: <CapabilityIcon state={isPublicUnlistedVisibility} intl={intl} /></span>
</li> </li>

View file

@ -20,7 +20,7 @@ import QuietTimeIcon from '@/material-icons/400-24px/quiet_time.svg?react';
import ReplyIcon from '@/material-icons/400-24px/reply.svg?react'; import ReplyIcon from '@/material-icons/400-24px/reply.svg?react';
import LimitedIcon from '@/material-icons/400-24px/shield.svg?react'; import LimitedIcon from '@/material-icons/400-24px/shield.svg?react';
import { Icon } from 'mastodon/components/icon'; import { Icon } from 'mastodon/components/icon';
import { enableLoginPrivacy, enableLocalPrivacy } from 'mastodon/initial_state'; import { enableLoginPrivacy, enableLocalPrivacy, enablePublicPrivacy } from 'mastodon/initial_state';
const messages = defineMessages({ const messages = defineMessages({
public_short: { id: 'privacy.public.short', defaultMessage: 'Public' }, public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
@ -279,6 +279,10 @@ class PrivacyDropdown extends PureComponent {
this.options = this.options.filter((opt) => opt.value !== 'public_unlisted'); this.options = this.options.filter((opt) => opt.value !== 'public_unlisted');
} }
if (!enablePublicPrivacy) {
this.options = this.options.filter((opt) => opt.value !== 'public');
}
this.selectableOptions = [...this.options]; this.selectableOptions = [...this.options];
} }

View file

@ -38,6 +38,7 @@
* @property {boolean} enable_local_privacy * @property {boolean} enable_local_privacy
* @property {boolean} enable_local_timeline * @property {boolean} enable_local_timeline
* @property {boolean} enable_dtl_menu * @property {boolean} enable_dtl_menu
* @property {boolean} enable_public_privacy
* @property {boolean=} expand_spoilers * @property {boolean=} expand_spoilers
* @property {HideItemsDefinition[]} hide_items * @property {HideItemsDefinition[]} hide_items
* @property {boolean} limited_federation_mode * @property {boolean} limited_federation_mode
@ -122,6 +123,7 @@ export const domain = getMeta('domain');
export const dtlTag = getMeta('dtl_tag'); export const dtlTag = getMeta('dtl_tag');
export const enableEmojiReaction = getMeta('enable_emoji_reaction'); export const enableEmojiReaction = getMeta('enable_emoji_reaction');
export const enableLocalPrivacy = getMeta('enable_local_privacy'); export const enableLocalPrivacy = getMeta('enable_local_privacy');
export const enablePublicPrivacy = getMeta('enable_public_privacy');
export const enableLocalTimeline = getMeta('enable_local_timeline'); export const enableLocalTimeline = getMeta('enable_local_timeline');
export const enableLoginPrivacy = getMeta('enable_login_privacy'); export const enableLoginPrivacy = getMeta('enable_login_privacy');
export const enableDtlMenu = getMeta('enable_dtl_menu'); export const enableDtlMenu = getMeta('enable_dtl_menu');

View file

@ -16,6 +16,7 @@
"about.kmyblue_capability": "このサーバーは、kmyblueというMastodonフォークを利用しています。kmyblue独自機能の一部は、サーバー管理者によって有効・無効を切り替えることができます。", "about.kmyblue_capability": "このサーバーは、kmyblueというMastodonフォークを利用しています。kmyblue独自機能の一部は、サーバー管理者によって有効・無効を切り替えることができます。",
"about.not_available": "この情報はこのサーバーでは利用できません。", "about.not_available": "この情報はこのサーバーでは利用できません。",
"about.powered_by": "{mastodon}による分散型ソーシャルメディア", "about.powered_by": "{mastodon}による分散型ソーシャルメディア",
"about.public_visibility": "公開投稿を許可",
"about.rules": "サーバーのルール", "about.rules": "サーバーのルール",
"account.account_note_header": "メモ", "account.account_note_header": "メモ",
"account.add_or_remove_from_antenna": "アンテナから追加または外す", "account.add_or_remove_from_antenna": "アンテナから追加または外す",

View file

@ -56,7 +56,7 @@ import {
import { REDRAFT } from '../actions/statuses'; import { REDRAFT } from '../actions/statuses';
import { STORE_HYDRATE } from '../actions/store'; import { STORE_HYDRATE } from '../actions/store';
import { TIMELINE_DELETE } from '../actions/timelines'; import { TIMELINE_DELETE } from '../actions/timelines';
import { enableLocalPrivacy, enableLoginPrivacy, me } from '../initial_state'; import { enableLocalPrivacy, enableLoginPrivacy, enablePublicPrivacy, me } from '../initial_state';
import { unescapeHTML } from '../utils/html'; import { unescapeHTML } from '../utils/html';
import { uuid } from '../uuid'; import { uuid } from '../uuid';
@ -142,7 +142,7 @@ function clearAll(state) {
map.set('default_privacy', state.get('privacy')); map.set('default_privacy', state.get('privacy'));
} }
if ((map.get('privacy') === 'login' && !enableLoginPrivacy) || (map.get('privacy') === 'public_unlisted' && !enableLocalPrivacy)) { if ((map.get('privacy') === 'login' && !enableLoginPrivacy) || (map.get('privacy') === 'public_unlisted' && !enableLocalPrivacy)) {
map.set('privacy', 'public'); map.set('privacy', enablePublicPrivacy ? 'public' : 'unlisted');
} }
if (!state.get('in_reply_to')) { if (!state.get('in_reply_to')) {
map.set('posted_on_this_session', true); map.set('posted_on_this_session', true);

View file

@ -57,6 +57,7 @@ class Form::AdminSettings
streaming_local_emoji_reaction streaming_local_emoji_reaction
enable_emoji_reaction enable_emoji_reaction
check_lts_version_only check_lts_version_only
enable_public_visibility
enable_public_unlisted_visibility enable_public_unlisted_visibility
unlocked_friend unlocked_friend
enable_local_timeline enable_local_timeline
@ -95,6 +96,7 @@ class Form::AdminSettings
streaming_local_emoji_reaction streaming_local_emoji_reaction
enable_emoji_reaction enable_emoji_reaction
check_lts_version_only check_lts_version_only
enable_public_visibility
enable_public_unlisted_visibility enable_public_unlisted_visibility
unlocked_friend unlocked_friend
stranger_mention_from_local_ng stranger_mention_from_local_ng

View file

@ -496,6 +496,7 @@ class Status < ApplicationRecord
def selectable_visibilities def selectable_visibilities
vs = visibilities.keys - %w(direct limited) vs = visibilities.keys - %w(direct limited)
vs -= %w(public_unlisted) unless Setting.enable_public_unlisted_visibility vs -= %w(public_unlisted) unless Setting.enable_public_unlisted_visibility
vs -= %w(public) unless Setting.enable_public_visibility
vs vs
end end

View file

@ -118,6 +118,7 @@ class InitialStateSerializer < ActiveModel::Serializer
domain: Addressable::IDNA.to_unicode(instance_presenter.domain), domain: Addressable::IDNA.to_unicode(instance_presenter.domain),
dtl_tag: dtl_enabled? ? dtl_tag_name : nil, dtl_tag: dtl_enabled? ? dtl_tag_name : nil,
enable_local_privacy: Setting.enable_public_unlisted_visibility, enable_local_privacy: Setting.enable_public_unlisted_visibility,
enable_public_privacy: Setting.enable_public_visibility,
enable_local_timeline: Setting.enable_local_timeline, enable_local_timeline: Setting.enable_local_timeline,
limited_federation_mode: Rails.configuration.x.limited_federation_mode, limited_federation_mode: Rails.configuration.x.limited_federation_mode,
locale: I18n.locale, locale: I18n.locale,

View file

@ -74,6 +74,7 @@ class PostStatusService < BaseService
@visibility = :limited if %w(mutual circle reply).include?(@options[:visibility]) @visibility = :limited if %w(mutual circle reply).include?(@options[:visibility])
@visibility = :unlisted if (@visibility == :public || @visibility == :public_unlisted || @visibility == :login) && @account.silenced? @visibility = :unlisted if (@visibility == :public || @visibility == :public_unlisted || @visibility == :login) && @account.silenced?
@visibility = :public_unlisted if @visibility == :public && !@options[:force_visibility] && !@options[:application]&.superapp && @account.user&.setting_public_post_to_unlisted && Setting.enable_public_unlisted_visibility @visibility = :public_unlisted if @visibility == :public && !@options[:force_visibility] && !@options[:application]&.superapp && @account.user&.setting_public_post_to_unlisted && Setting.enable_public_unlisted_visibility
@visibility = Setting.enable_public_unlisted_visibility ? :public_unlisted : :unlisted unless Setting.enable_public_visibility
@limited_scope = @options[:visibility]&.to_sym if @visibility == :limited && @options[:visibility] != 'limited' @limited_scope = @options[:visibility]&.to_sym if @visibility == :limited && @options[:visibility] != 'limited'
@searchability = searchability @searchability = searchability
@searchability = :private if @account.silenced? && %i(public public_unlisted).include?(@searchability&.to_sym) @searchability = :private if @account.silenced? && %i(public public_unlisted).include?(@searchability&.to_sym)

View file

@ -45,6 +45,9 @@
%h4= t('admin.settings.discovery.visibilities') %h4= t('admin.settings.discovery.visibilities')
.fields-group
= f.input :enable_public_visibility, as: :boolean, wrapper: :with_label, kmyblue: true
.fields-group .fields-group
= f.input :enable_public_unlisted_visibility, as: :boolean, wrapper: :with_label, kmyblue: true = f.input :enable_public_unlisted_visibility, as: :boolean, wrapper: :with_label, kmyblue: true

View file

@ -101,6 +101,7 @@ en:
custom_css: You can apply custom styles on the web version of Mastodon. custom_css: You can apply custom styles on the web version of Mastodon.
enable_local_timeline: While enabling this feature will allow for interaction between like-minded users, it may also strengthen the internal atmosphere; since Mastodon is supposed to have a local timeline, we recommend annotating it in the server introduction if it is to be disabled. enable_local_timeline: While enabling this feature will allow for interaction between like-minded users, it may also strengthen the internal atmosphere; since Mastodon is supposed to have a local timeline, we recommend annotating it in the server introduction if it is to be disabled.
enable_public_unlisted_visibility: If true, your community maybe closed-minded. If turn it false, strongly recommend that you disclose that you have disabled this setting! enable_public_unlisted_visibility: If true, your community maybe closed-minded. If turn it false, strongly recommend that you disclose that you have disabled this setting!
enable_public_visibility: If disabled, public submissions will be forcibly replaced with "Public unlisted" or "Unlisted" submissions.
mascot: Overrides the illustration in the advanced web interface. mascot: Overrides the illustration in the advanced web interface.
media_cache_retention_period: Downloaded media files will be deleted after the specified number of days when set to a positive value, and re-downloaded on demand. media_cache_retention_period: Downloaded media files will be deleted after the specified number of days when set to a positive value, and re-downloaded on demand.
peers_api_enabled: A list of domain names this server has encountered in the fediverse. No data is included here about whether you federate with a given server, just that your server knows about it. This is used by services that collect statistics on federation in a general sense. peers_api_enabled: A list of domain names this server has encountered in the fediverse. No data is included here about whether you federate with a given server, just that your server knows about it. This is used by services that collect statistics on federation in a general sense.
@ -349,6 +350,7 @@ en:
enable_emoji_reaction: Enable emoji reaction function enable_emoji_reaction: Enable emoji reaction function
enable_local_timeline: Enable local timeline enable_local_timeline: Enable local timeline
enable_public_unlisted_visibility: Enable public-unlisted visibility / public-unlisted searchability enable_public_unlisted_visibility: Enable public-unlisted visibility / public-unlisted searchability
enable_public_visibility: Enable public visibility
mascot: Custom mascot (legacy) mascot: Custom mascot (legacy)
media_cache_retention_period: Media cache retention period media_cache_retention_period: Media cache retention period
peers_api_enabled: Publish list of discovered servers in the API peers_api_enabled: Publish list of discovered servers in the API

View file

@ -112,6 +112,7 @@ ja:
custom_css: ウェブ版のMastodonでカスタムスタイルを適用できます。 custom_css: ウェブ版のMastodonでカスタムスタイルを適用できます。
enable_local_timeline: 有効にすると気の合ったユーザー同士の交流が捗る反面、内輪の雰囲気が強くなるかもしれません。Mastodonはローカルタイムラインがあるものだと思われているので、無効にする場合はサーバー紹介での注記をおすすめします。 enable_local_timeline: 有効にすると気の合ったユーザー同士の交流が捗る反面、内輪の雰囲気が強くなるかもしれません。Mastodonはローカルタイムラインがあるものだと思われているので、無効にする場合はサーバー紹介での注記をおすすめします。
enable_public_unlisted_visibility: 有効にするとあなたのコミュニティは閉鎖的になるかもしれません。この設定はkmyblueの主要機能の1つであり、無効にする場合は概要などに記載することを強くおすすめします。 enable_public_unlisted_visibility: 有効にするとあなたのコミュニティは閉鎖的になるかもしれません。この設定はkmyblueの主要機能の1つであり、無効にする場合は概要などに記載することを強くおすすめします。
enable_public_visibility: 無効にすると公開投稿は強制的に「ローカル公開」または「非収載」に置き換えられます。
mascot: 上級者向けWebインターフェースのイラストを上書きします。 mascot: 上級者向けWebインターフェースのイラストを上書きします。
media_cache_retention_period: 正の値に設定されている場合、ダウンロードされたメディアファイルは指定された日数の後に削除され、リクエストに応じて再ダウンロードされます。 media_cache_retention_period: 正の値に設定されている場合、ダウンロードされたメディアファイルは指定された日数の後に削除され、リクエストに応じて再ダウンロードされます。
peers_api_enabled: このサーバーが Fediverse で遭遇したドメイン名のリストです。このサーバーが知っているだけで、特定のサーバーと連合しているかのデータは含まれません。これは一般的に Fediverse に関する統計情報を収集するサービスによって使用されます。 peers_api_enabled: このサーバーが Fediverse で遭遇したドメイン名のリストです。このサーバーが知っているだけで、特定のサーバーと連合しているかのデータは含まれません。これは一般的に Fediverse に関する統計情報を収集するサービスによって使用されます。
@ -362,6 +363,7 @@ ja:
enable_emoji_reaction: 絵文字リアクション機能を有効にする enable_emoji_reaction: 絵文字リアクション機能を有効にする
enable_local_timeline: ローカルタイムラインを有効にする enable_local_timeline: ローカルタイムラインを有効にする
enable_public_unlisted_visibility: 公開範囲「ローカル公開」と検索許可「ローカルとフォロワー」を有効にする enable_public_unlisted_visibility: 公開範囲「ローカル公開」と検索許可「ローカルとフォロワー」を有効にする
enable_public_visibility: 公開範囲「公開」を有効にする
mascot: カスタムマスコット(レガシー) mascot: カスタムマスコット(レガシー)
media_cache_retention_period: メディアキャッシュの保持期間 media_cache_retention_period: メディアキャッシュの保持期間
peers_api_enabled: 発見したサーバーのリストをAPIで公開する peers_api_enabled: 発見したサーバーのリストをAPIで公開する

View file

@ -50,6 +50,7 @@ defaults: &defaults
streaming_local_emoji_reaction: true streaming_local_emoji_reaction: true
enable_emoji_reaction: true enable_emoji_reaction: true
check_lts_version_only: true check_lts_version_only: true
enable_public_visibility: true
enable_public_unlisted_visibility: true enable_public_unlisted_visibility: true
unlocked_friend: false unlocked_friend: false
stranger_mention_from_local_ng: true stranger_mention_from_local_ng: true