diff --git a/app/javascript/mastodon/components/status_action_bar.jsx b/app/javascript/mastodon/components/status_action_bar.jsx
index ced931f3f8..593fd55461 100644
--- a/app/javascript/mastodon/components/status_action_bar.jsx
+++ b/app/javascript/mastodon/components/status_action_bar.jsx
@@ -394,9 +394,15 @@ 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 emojiPickerButton = (
);
+ const emojiPickerDropdown = (writtenByMe || ((denyFromAll) && (following) && (followed))) && (
+
+ );
return (
@@ -404,7 +410,7 @@ class StatusActionBar extends ImmutablePureComponent {
-
+ {emojiPickerDropdown}
{filterButton}
diff --git a/app/models/account.rb b/app/models/account.rb
index 41830211e8..670b2c6083 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -335,6 +335,27 @@ class Account < ApplicationRecord
false
end
+ def emoji_reactions_must_following?
+ return user&.settings&.[]('emoji_reactions.must_be_following') || false if user.present?
+ return settings['emoji_reactions_must_be_following'] || false if settings.present?
+
+ false
+ end
+
+ def emoji_reactions_must_follower?
+ 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 user&.settings&.[]('emoji_reactions.deny_from_all') || false if user.present?
+ return settings['emoji_reaction_deny_from_all'] || false if settings.present?
+
+ false
+ end
+
def public_settings
config = {
'noindex' => noindex?,
@@ -343,6 +364,9 @@ class Account < ApplicationRecord
'hide_statuses_count' => hide_statuses_count?,
'hide_following_count' => hide_following_count?,
'hide_followers_count' => hide_followers_count?,
+ '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?,
}
config = config.merge(settings) if settings.present?
config
diff --git a/app/models/user_settings.rb b/app/models/user_settings.rb
index a4a3548704..34ebe0484d 100644
--- a/app/models/user_settings.rb
+++ b/app/models/user_settings.rb
@@ -69,6 +69,12 @@ class UserSettings
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 5243ed516c..58e8117ead 100644
--- a/app/services/notify_service.rb
+++ b/app/services/notify_service.rb
@@ -51,6 +51,18 @@ class NotifyService < BaseService
@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
@@ -120,6 +132,8 @@ class NotifyService < BaseService
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 9d1ff556a6..4d45a77468 100644
--- a/app/validators/emoji_reaction_validator.rb
+++ b/app/validators/emoji_reaction_validator.rb
@@ -8,6 +8,7 @@ class EmojiReactionValidator < ActiveModel::Validator
emoji_reaction.errors.add(:name, I18n.t('reactions.errors.unrecognized_emoji')) if emoji_reaction.custom_emoji_id.blank? && !unicode_emoji?(emoji_reaction.name)
emoji_reaction.errors.add(:name, I18n.t('reactions.errors.unrecognized_emoji')) if emoji_reaction.custom_emoji_id.present? && disabled_custom_emoji?(emoji_reaction.custom_emoji)
+ emoji_reaction.errors.add(:name, I18n.t('reactions.errors.banned')) if deny_from_all?(emoji_reaction) || non_follower?(emoji_reaction) || non_following?(emoji_reaction)
end
private
@@ -19,4 +20,25 @@ class EmojiReactionValidator < ActiveModel::Validator
def disabled_custom_emoji?(custom_emoji)
custom_emoji.nil? ? false : custom_emoji.disabled
end
+
+ def deny_from_all?(emoji_reaction)
+ return false if emoji_reaction.status.account.user.nil?
+ return false if emoji_reaction.status.account_id == emoji_reaction.account_id
+
+ emoji_reaction.status.account.user.settings['emoji_reactions.deny_from_all']
+ end
+
+ def non_following?(emoji_reaction)
+ return false if emoji_reaction.status.account.user.nil?
+ return false if emoji_reaction.status.account_id == emoji_reaction.account_id
+
+ emoji_reaction.status.account.user.settings['emoji_reactions.must_be_following'] && !emoji_reaction.status.account.following?(emoji_reaction.account)
+ end
+
+ def non_follower?(emoji_reaction)
+ return false if emoji_reaction.status.account.user.nil?
+ return false if emoji_reaction.status.account_id == emoji_reaction.account_id
+
+ emoji_reaction.status.account.user.settings['emoji_reactions.must_be_follower'] && !emoji_reaction.account.following?(emoji_reaction.status.account)
+ end
end
diff --git a/app/views/settings/preferences/notifications/show.html.haml b/app/views/settings/preferences/notifications/show.html.haml
index 2730507922..a87b765da9 100644
--- a/app/views/settings/preferences/notifications/show.html.haml
+++ b/app/views/settings/preferences/notifications/show.html.haml
@@ -33,6 +33,9 @@
= 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')
+ = 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/config/locales/en.yml b/config/locales/en.yml
index 5fc0b6429f..9867ab6a58 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -1590,6 +1590,7 @@ en:
title: Privacy Policy
reactions:
errors:
+ banned: Banned reaction from the user
duplication: Cannot react same things
limit_reached: Limit of different reactions reached
unrecognized_emoji: is not a recognized emoji
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index 929971b06f..1dbd259a34 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -1577,6 +1577,7 @@ ja:
title: プライバシーポリシー
reactions:
errors:
+ banned: 指定ユーザーからのリアクションは禁止されています
duplication: 同じリアクションを複数行おうとしました
limit_reached: リアクションの種類が上限に達しました
unrecognized_emoji: は絵文字として認識されていません
diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml
index 6af12751a8..749ab6eb82 100644
--- a/config/locales/simple_form.en.yml
+++ b/config/locales/simple_form.en.yml
@@ -257,6 +257,10 @@ en:
whole_word: Whole word
email_domain_block:
with_dns_records: Include MX records and IPs of the domain
+ emoji_reactions:
+ deny_from_all: Block all stamps
+ must_be_follower: Block stamps from non-followers
+ must_be_following: Block stamps from people you don't follow
featured_tag:
name: Hashtag
filters:
diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml
index 6e4d7663a9..cbddd7d72f 100644
--- a/config/locales/simple_form.ja.yml
+++ b/config/locales/simple_form.ja.yml
@@ -265,6 +265,10 @@ ja:
whole_word: 単語全体にマッチ
email_domain_block:
with_dns_records: ドメインのMXレコードとIPアドレスを含む
+ emoji_reactions:
+ deny_from_all: 自分以外すべてのスタンプをブロック
+ must_be_follower: フォロワー以外からのスタンプをブロック
+ must_be_following: フォローしていないユーザーからのスタンプをブロック
featured_tag:
name: ハッシュタグ
filters: