diff --git a/.env.production.sample b/.env.production.sample index eb0df86d39..9eb02287e1 100644 --- a/.env.production.sample +++ b/.env.production.sample @@ -270,7 +270,7 @@ MAX_POLL_OPTIONS=5 MAX_POLL_OPTION_CHARS=100 # Maximum number of emoji reactions per toot and user (minimum 1) -MAX_STATUS_REACTIONS=8 +MAX_REACTIONS=8 # Maximum image and video/audio upload sizes # Units are in bytes diff --git a/app/javascript/flavours/glitch/components/status_reactions_bar.js b/app/javascript/flavours/glitch/components/status_reactions_bar.js index db1905be4f..ac57341bcc 100644 --- a/app/javascript/flavours/glitch/components/status_reactions_bar.js +++ b/app/javascript/flavours/glitch/components/status_reactions_bar.js @@ -11,13 +11,14 @@ import React from 'react'; import unicodeMapping from '../features/emoji/emoji_unicode_mapping_light'; import AnimatedNumber from './animated_number'; import { assetHost } from '../utils/config'; -import { autoPlayGif } from '../initial_state'; +import { autoPlayGif, maxReactions } from '../initial_state'; export default class StatusReactionsBar extends ImmutablePureComponent { static propTypes = { statusId: PropTypes.string.isRequired, reactions: ImmutablePropTypes.list.isRequired, + reactionLimit: PropTypes.number.isRequired, addReaction: PropTypes.func.isRequired, removeReaction: PropTypes.func.isRequired, emojiMap: ImmutablePropTypes.map.isRequired, @@ -62,7 +63,7 @@ export default class StatusReactionsBar extends ImmutablePureComponent { /> ))} - {visibleReactions.size < 8 && } />} + {visibleReactions.size < maxReactions && } />} )} diff --git a/app/javascript/flavours/glitch/initial_state.js b/app/javascript/flavours/glitch/initial_state.js index bbf25c8a85..4391b0c75d 100644 --- a/app/javascript/flavours/glitch/initial_state.js +++ b/app/javascript/flavours/glitch/initial_state.js @@ -148,4 +148,7 @@ export const pollLimits = (initialState && initialState.poll_limits); export const defaultContentType = getMeta('default_content_type'); export const useSystemEmojiFont = getMeta('system_emoji_font'); +// nyastodon-specific settings +export const maxReactions = (initialState && initialState.max_reactions) || 8; + export default initialState; diff --git a/app/serializers/initial_state_serializer.rb b/app/serializers/initial_state_serializer.rb index d23daaf85c..0ac196b7a0 100644 --- a/app/serializers/initial_state_serializer.rb +++ b/app/serializers/initial_state_serializer.rb @@ -6,7 +6,7 @@ class InitialStateSerializer < ActiveModel::Serializer attributes :meta, :compose, :accounts, :media_attachments, :settings, :max_toot_chars, :poll_limits, - :languages + :languages, :max_reactions has_one :push_subscription, serializer: REST::WebPushSubscriptionSerializer has_one :role, serializer: REST::RoleSerializer @@ -15,6 +15,10 @@ class InitialStateSerializer < ActiveModel::Serializer StatusLengthValidator::MAX_CHARS end + def max_reactions + StatusReactionValidator::LIMIT + end + def poll_limits { max_options: PollValidator::MAX_OPTIONS, diff --git a/app/services/status_reaction_service.rb b/app/services/status_reaction_service.rb index 17acfe7488..e823f6bd88 100644 --- a/app/services/status_reaction_service.rb +++ b/app/services/status_reaction_service.rb @@ -5,12 +5,11 @@ class StatusReactionService < BaseService include Payloadable def call(account, status, emoji) - reaction = StatusReaction.find_by(account: account, status: status) + name, domain = emoji.split('@') + custom_emoji = CustomEmoji.find_by(shortcode: name, domain: domain) + reaction = StatusReaction.find_by(account: account, status: status, name: name, custom_emoji: custom_emoji) return reaction unless reaction.nil? - name, domain = emoji.split("@") - - custom_emoji = CustomEmoji.find_by(shortcode: name, domain: domain) reaction = StatusReaction.create!(account: account, status: status, name: name, custom_emoji: custom_emoji) json = Oj.dump(serialize_payload(reaction, ActivityPub::EmojiReactionSerializer)) diff --git a/app/validators/status_reaction_validator.rb b/app/validators/status_reaction_validator.rb index 113e9342ba..fa6fb2e765 100644 --- a/app/validators/status_reaction_validator.rb +++ b/app/validators/status_reaction_validator.rb @@ -3,13 +3,13 @@ class StatusReactionValidator < ActiveModel::Validator SUPPORTED_EMOJIS = Oj.load_file(Rails.root.join('app', 'javascript', 'mastodon', 'features', 'emoji', 'emoji_map.json').to_s).keys.freeze - LIMIT = [1, (ENV['MAX_STATUS_REACTIONS'] || 1).to_i].max + LIMIT = [1, (ENV['MAX_REACTIONS'] || 8).to_i].max def validate(reaction) return if reaction.name.blank? reaction.errors.add(:name, I18n.t('reactions.errors.unrecognized_emoji')) if reaction.custom_emoji_id.blank? && !unicode_emoji?(reaction.name) - reaction.errors.add(:base, I18n.t('reactions.errors.limit_reached')) if new_reaction?(reaction) && limit_reached?(reaction) + reaction.errors.add(:base, I18n.t('reactions.errors.limit_reached')) if limit_reached?(reaction) end private @@ -23,6 +23,6 @@ class StatusReactionValidator < ActiveModel::Validator end def limit_reached?(reaction) - reaction.status.status_reactions.where.not(name: reaction.name).count('distinct name') >= LIMIT + reaction.status.status_reactions.where(status: reaction.status, account: reaction.account).count >= LIMIT end end