diff --git a/app/javascript/mastodon/components/status.jsx b/app/javascript/mastodon/components/status.jsx index a5e89339959980..682051c7d559f5 100644 --- a/app/javascript/mastodon/components/status.jsx +++ b/app/javascript/mastodon/components/status.jsx @@ -577,7 +577,8 @@ class Status extends ImmutablePureComponent { let emojiReactionsBar = null; if (!this.props.withoutEmojiReactions && status.get('emoji_reactions')) { const emojiReactions = status.get('emoji_reactions'); - if (emojiReactions.size > 0 && enableEmojiReaction) { + const emojiReactionPolicy = status.getIn(['account', 'other_settings', 'emoji_reaction_policy']) || 'allow'; + if (emojiReactions.size > 0 && enableEmojiReaction && emojiReactionPolicy !== 'block_and_hide') { emojiReactionsBar = ; } } diff --git a/app/javascript/mastodon/components/status_action_bar.jsx b/app/javascript/mastodon/components/status_action_bar.jsx index 79169e909f6759..c9e8ab4646df6e 100644 --- a/app/javascript/mastodon/components/status_action_bar.jsx +++ b/app/javascript/mastodon/components/status_action_bar.jsx @@ -410,13 +410,16 @@ class StatusActionBar extends ImmutablePureComponent { ); - const following = !account.getIn(['other_settings', 'emoji_reaction_must_follower']) || (relationship && relationship.get('following')); - const followed = !account.getIn(['other_settings', 'emoji_reaction_must_following']) || (relationship && relationship.get('followed_by')); - const denyFromAll = !account.getIn(['other_settings', 'emoji_reaction_deny_from_all']); + const emojiReactionPolicy = account.getIn(['other_settings', 'emoji_reaction_policy']) || 'allow'; + const following = emojiReactionPolicy !== 'followees_only' || (relationship && relationship.get('following')); + const followed = emojiReactionPolicy !== 'followers_only' || (relationship && relationship.get('followed_by')); + const mutual = emojiReactionPolicy !== 'mutuals_only' || (relationship && relationship.get('following') && relationship.get('followed_by')); + const outside = emojiReactionPolicy !== 'outside_only' || (relationship && (relationship.get('following') || relationship.get('followed_by'))); + const denyFromAll = emojiReactionPolicy !== 'block' && emojiReactionPolicy !== 'block_and_hide'; const emojiPickerButton = ( ); - const emojiPickerDropdown = enableEmojiReaction && (writtenByMe || ((denyFromAll) && (following) && (followed))) && ( + const emojiPickerDropdown = enableEmojiReaction && (writtenByMe || (denyFromAll && following && followed && mutual && outside)) && ( ); diff --git a/app/javascript/mastodon/features/status/components/action_bar.jsx b/app/javascript/mastodon/features/status/components/action_bar.jsx index 4d0cda9ed36ef8..411530f967c073 100644 --- a/app/javascript/mastodon/features/status/components/action_bar.jsx +++ b/app/javascript/mastodon/features/status/components/action_bar.jsx @@ -326,13 +326,16 @@ class ActionBar extends PureComponent { reblogTitle = intl.formatMessage(messages.cannot_reblog); } - const following = !account.getIn(['other_settings', 'emoji_reaction_must_follower']) || (relationship && relationship.get('following')); - const followed = !account.getIn(['other_settings', 'emoji_reaction_must_following']) || (relationship && relationship.get('followed_by')); - const denyFromAll = !account.getIn(['other_settings', 'emoji_reaction_deny_from_all']); + const emojiReactionPolicy = account.getIn(['other_settings', 'emoji_reaction_policy']) || 'allow'; + const following = emojiReactionPolicy !== 'followees_only' || (relationship && relationship.get('following')); + const followed = emojiReactionPolicy !== 'followers_only' || (relationship && relationship.get('followed_by')); + const mutual = emojiReactionPolicy !== 'mutuals_only' || (relationship && relationship.get('following') && relationship.get('followed_by')); + const outside = emojiReactionPolicy !== 'outside_only' || (relationship && (relationship.get('following') || relationship.get('followed_by'))); + const denyFromAll = emojiReactionPolicy !== 'block' && emojiReactionPolicy !== 'block_and_hide'; const emojiPickerButton = ( ); - const emojiPickerDropdown = enableEmojiReaction && (writtenByMe || ((denyFromAll) && (following) && (followed))) && ( + const emojiPickerDropdown = enableEmojiReaction && (writtenByMe || (denyFromAll && following && followed && mutual && outside)) && (
); diff --git a/app/javascript/mastodon/features/status/components/detailed_status.jsx b/app/javascript/mastodon/features/status/components/detailed_status.jsx index 37f6537072eb04..a3f48490edd635 100644 --- a/app/javascript/mastodon/features/status/components/detailed_status.jsx +++ b/app/javascript/mastodon/features/status/components/detailed_status.jsx @@ -241,7 +241,8 @@ class DetailedStatus extends ImmutablePureComponent { let emojiReactionsBar = null; if (status.get('emoji_reactions')) { const emojiReactions = status.get('emoji_reactions'); - if (emojiReactions.size > 0 && enableEmojiReaction) { + const emojiReactionPolicy = status.getIn(['account', 'other_settings', 'emoji_reaction_policy']) || 'allow'; + if (emojiReactions.size > 0 && enableEmojiReaction && emojiReactionPolicy !== 'block_and_hide') { emojiReactionsBar = ; } } diff --git a/app/models/account.rb b/app/models/account.rb index fcc0514e4b490c..28c024877a7719 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -363,28 +363,12 @@ def hide_followers_count? false end - def emoji_reactions_must_following? - return false unless Setting.enable_block_emoji_reaction_settings || !local? - return user&.settings&.[]('emoji_reactions.must_be_following') || false if user.present? - return settings['emoji_reactions_must_be_following'] || false if settings.present? + def emoji_reaction_policy + return :allow unless Setting.enable_block_emoji_reaction_settings || !local? + return settings['emoji_reaction_policy']&.to_sym || :allow if settings.present? + return :allow if user.nil? - false - end - - def emoji_reactions_must_follower? - return false unless Setting.enable_block_emoji_reaction_settings || !local? - return user&.settings&.[]('emoji_reactions.must_be_follower') || false if user.present? - return settings['emoji_reaction_must_be_follower'] || false if settings.present? - - false - end - - def emoji_reactions_deny_from_all? - return false unless Setting.enable_block_emoji_reaction_settings || !local? - return user&.settings&.[]('emoji_reactions.deny_from_all') || false if user.present? - return settings['emoji_reaction_deny_from_all'] || false if settings.present? - - false + user.settings&.[]('emoji_reaction_policy')&.to_sym end def public_settings @@ -400,9 +384,7 @@ def public_settings } if Setting.enable_block_emoji_reaction_settings config = config.merge({ - 'emoji_reaction_must_following' => emoji_reactions_must_following?, - 'emoji_reaction_must_follower' => emoji_reactions_must_follower?, - 'emoji_reaction_deny_from_all' => emoji_reactions_deny_from_all?, + 'emoji_reaction_policy' => user&.setting_emoji_reaction_policy, }) end config = config.merge(settings) if settings.present? diff --git a/app/models/concerns/account_interactions.rb b/app/models/concerns/account_interactions.rb index 42a42e8f9f386b..8c0a635d02e451 100644 --- a/app/models/concerns/account_interactions.rb +++ b/app/models/concerns/account_interactions.rb @@ -211,6 +211,10 @@ def followed_by?(other_account) other_account.following?(self) end + def mutual?(other_account) + following?(other_account) && followed_by?(other_account) + end + def blocking?(other_account) block_relationships.where(target_account: other_account).exists? end diff --git a/app/models/concerns/has_user_settings.rb b/app/models/concerns/has_user_settings.rb index 0d91a0e1e2b5da..00ddfde6dda1a1 100644 --- a/app/models/concerns/has_user_settings.rb +++ b/app/models/concerns/has_user_settings.rb @@ -79,6 +79,10 @@ def setting_emoji_reaction_streaming_notify_impl2 false end + def setting_emoji_reaction_policy + settings['emoji_reaction_policy'] + end + def setting_unfollow_modal settings['web.unfollow_modal'] end diff --git a/app/models/status.rb b/app/models/status.rb index 2333470c72a8b7..3b0e0dbbb370bb 100644 --- a/app/models/status.rb +++ b/app/models/status.rb @@ -350,6 +350,8 @@ def add_status_referred_by_count!(diff) end def emoji_reactions_grouped_by_name(account = nil) + return [] if self.account.emoji_reaction_policy == :block_and_hide + (Oj.load(status_stat&.emoji_reactions || '', mode: :strict) || []).tap do |emoji_reactions| if account.present? remove_emoji_reactions = [] diff --git a/app/models/user_settings.rb b/app/models/user_settings.rb index df6af8f38b94e6..f275cb6904c523 100644 --- a/app/models/user_settings.rb +++ b/app/models/user_settings.rb @@ -36,6 +36,7 @@ class KeyError < Error; end setting :reaction_deck, default: nil setting :stop_emoji_reaction_streaming, default: false setting :emoji_reaction_streaming_notify_impl2, default: false + setting :emoji_reaction_policy, default: :allow, in: %w(allow outside_only followers_only followees_only mutuals_only block block_and_hide) setting :unsafe_limited_distribution, default: false setting :dtl_force_with_tag, default: :none, in: %w(full searchability none) setting :dtl_force_subscribable, default: false @@ -84,12 +85,6 @@ class KeyError < Error; end setting :must_be_following_dm, default: false end - namespace :emoji_reactions do - setting :must_be_follower, default: false - setting :must_be_following, default: false - setting :deny_from_all, default: false - end - def initialize(original_hash) @original_hash = original_hash || {} end diff --git a/app/services/notify_service.rb b/app/services/notify_service.rb index 58e8117ead8038..5243ed516cb179 100644 --- a/app/services/notify_service.rb +++ b/app/services/notify_service.rb @@ -51,18 +51,6 @@ def optional_non_following? @recipient.user.settings['interactions.must_be_following'] && !following_sender? end - def optional_non_follower_emoji_reaction? - emoji_reaction? && @recipient.user.settings['emoji_reactions.must_be_follower'] && !@notification.from_account.following?(@recipient) - end - - def optional_non_following_emoji_reaction? - emoji_reaction? && @recipient.user.settings['emoji_reactions.must_be_following'] && !following_sender? - end - - def emoji_reaction? - @notification.type == :emoji_reaction - end - def message? @notification.type == :mention end @@ -132,8 +120,6 @@ def blocked? blocked ||= optional_non_follower? blocked ||= optional_non_following? blocked ||= optional_non_following_and_direct? - blocked ||= optional_non_follower_emoji_reaction? - blocked ||= optional_non_following_emoji_reaction? blocked ||= conversation_muted? blocked ||= blocked_mention? if @notification.type == :mention blocked diff --git a/app/validators/emoji_reaction_validator.rb b/app/validators/emoji_reaction_validator.rb index fb6ef325654a01..16461a3d7e8a14 100644 --- a/app/validators/emoji_reaction_validator.rb +++ b/app/validators/emoji_reaction_validator.rb @@ -24,20 +24,29 @@ def disabled_custom_emoji?(custom_emoji) def deny_emoji_reactions?(emoji_reaction) return false unless Setting.enable_block_emoji_reaction_settings return false if emoji_reaction.status.account.user.nil? - return false if emoji_reaction.status.account_id == emoji_reaction.account_id + return deny_from_all?(emoji_reaction) if emoji_reaction.status.account_id == emoji_reaction.account_id + return false if emoji_reaction.status.account.emoji_reaction_policy == :allow - deny_from_all?(emoji_reaction) || non_follower?(emoji_reaction) || non_following?(emoji_reaction) + deny_from_all?(emoji_reaction) || non_outside?(emoji_reaction) || non_follower?(emoji_reaction) || non_following?(emoji_reaction) || non_mutual?(emoji_reaction) end def deny_from_all?(emoji_reaction) - emoji_reaction.status.account.emoji_reactions_deny_from_all? + %i(block block_and_hide).include?(emoji_reaction.status.account.emoji_reaction_policy) end def non_following?(emoji_reaction) - emoji_reaction.status.account.emoji_reactions_must_following? && !emoji_reaction.status.account.following?(emoji_reaction.account) + emoji_reaction.status.account.emoji_reaction_policy == :followees_only && !emoji_reaction.status.account.following?(emoji_reaction.account) end def non_follower?(emoji_reaction) - emoji_reaction.status.account.emoji_reactions_must_follower? && !emoji_reaction.account.following?(emoji_reaction.status.account) + emoji_reaction.status.account.emoji_reaction_policy == :followers_only && !emoji_reaction.account.following?(emoji_reaction.status.account) + end + + def non_outside?(emoji_reaction) + emoji_reaction.status.account.emoji_reaction_policy == :outside_only && !emoji_reaction.account.following?(emoji_reaction.status.account) && !emoji_reaction.status.account.following?(emoji_reaction.account) + end + + def non_mutual?(emoji_reaction) + emoji_reaction.status.account.emoji_reaction_policy == :mutuals_only && !emoji_reaction.status.account.mutual?(emoji_reaction.account) end end diff --git a/app/views/settings/preferences/notifications/show.html.haml b/app/views/settings/preferences/notifications/show.html.haml index 3e40a736ee4111..924a351b1a2635 100644 --- a/app/views/settings/preferences/notifications/show.html.haml +++ b/app/views/settings/preferences/notifications/show.html.haml @@ -42,10 +42,6 @@ = ff.input :'interactions.must_be_follower', wrapper: :with_label, label: I18n.t('simple_form.labels.interactions.must_be_follower') = ff.input :'interactions.must_be_following', wrapper: :with_label, label: I18n.t('simple_form.labels.interactions.must_be_following') = ff.input :'interactions.must_be_following_dm', wrapper: :with_label, label: I18n.t('simple_form.labels.interactions.must_be_following_dm') - - if Setting.enable_block_emoji_reaction_settings - = ff.input :'emoji_reactions.must_be_follower', kmyblue: true, wrapper: :with_label, label: I18n.t('simple_form.labels.emoji_reactions.must_be_follower') - = ff.input :'emoji_reactions.must_be_following', kmyblue: true, wrapper: :with_label, label: I18n.t('simple_form.labels.emoji_reactions.must_be_following') - = ff.input :'emoji_reactions.deny_from_all', kmyblue: true, wrapper: :with_label, label: I18n.t('simple_form.labels.emoji_reactions.deny_from_all') = f.simple_fields_for :settings, current_user.settings do |ff| .fields-group diff --git a/app/views/settings/preferences/other/show.html.haml b/app/views/settings/preferences/other/show.html.haml index 18dded05ebcc93..4d3a11c6f4c264 100644 --- a/app/views/settings/preferences/other/show.html.haml +++ b/app/views/settings/preferences/other/show.html.haml @@ -20,6 +20,9 @@ .fields-group = ff.input :default_sensitive, wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_default_sensitive'), hint: I18n.t('simple_form.hints.defaults.setting_default_sensitive') + - if Setting.enable_block_emoji_reaction_settings + = ff.input :emoji_reaction_policy, kmyblue: true, collection: ['allow', 'outside_only', 'followers_only', 'followees_only', 'mutuals_only', 'block', 'block_and_hide'], label_method: lambda { |item| safe_join([t("simple_form.labels.defaults.setting_emoji_reaction_policy_items.#{item}")]) }, as: :radio_buttons, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', wrapper: :with_floating_label, label: I18n.t('simple_form.labels.defaults.setting_emoji_reaction_policy') + - if @dtl_enabled %h4= t 'preferences.dtl' diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index 5c4c861e8f0ce8..6816ba7bacc5dd 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -244,6 +244,15 @@ en: setting_emoji_reaction_streaming_notify_impl2: Enable stamp notification compat with Nyastodon, Catstodon, glitch-soc setting_enable_emoji_reaction: Show emoji reaction on your display setting_enable_login_privacy: Enable login visibility + setting_emoji_reaction_policy: Stamp policy + setting_emoji_reaction_policy_items: + allow: Allow all + block: Block all + block_and_hide: Block and hide + followees_only: Followings only + followers_only: Followers only + mutuals_only: Mutuals only + outside_only: Followings or followers only setting_expand_spoilers: Always expand posts marked with content warnings setting_hide_followers_count: Hide followers count setting_hide_following_count: Hide following count diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml index 06960624282f60..b8fe0d14caccfe 100644 --- a/config/locales/simple_form.ja.yml +++ b/config/locales/simple_form.ja.yml @@ -252,6 +252,15 @@ ja: setting_dtl_force_with_tag: DTL参加時の投稿設定 setting_dtl_menu: Webクライアントのメニューにディープタイムラインを追加する setting_enable_login_privacy: 公開範囲「ログインユーザーのみ」をWeb UIで選択可能にする + setting_emoji_reaction_policy: スタンプ受け入れ設定 + setting_emoji_reaction_policy_items: + allow: 全員に許可 + block: 全員禁止 + block_and_hide: 全員禁止し、既存のスタンプも非表示にする + followees_only: フォロー中の相手のみ許可 + followers_only: フォロワーのみ許可 + mutuals_only: 相互のみ許可 + outside_only: フォロー中、またはフォロワーのみに許可 setting_emoji_reaction_streaming_notify_impl2: Nyastodon, Catstodon, glitch-soc互換のスタンプ機能を有効にする setting_enable_emoji_reaction: 自分の画面に絵文字リアクションを表示する setting_expand_spoilers: 閲覧注意としてマークされた投稿を常に展開する