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: 閲覧注意としてマークされた投稿を常に展開する