make frontend fetch reaction limit

the maximum number of reactions was previously
hardcoded to 8.  this commit also fixes an
incorrect query in StatusReactionValidator where
it didn't count per-user reactions but the total
amount of different ones.
This commit is contained in:
fef 2022-11-29 00:39:40 +00:00 committed by Jeremy Kescher
parent c369bd3154
commit f1952244d1
No known key found for this signature in database
GPG key ID: 80A419A7A613DFA4
6 changed files with 18 additions and 11 deletions

View file

@ -270,7 +270,7 @@ MAX_POLL_OPTIONS=5
MAX_POLL_OPTION_CHARS=100 MAX_POLL_OPTION_CHARS=100
# Maximum number of emoji reactions per toot and user (minimum 1) # 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 # Maximum image and video/audio upload sizes
# Units are in bytes # Units are in bytes

View file

@ -11,13 +11,14 @@ import React from 'react';
import unicodeMapping from '../features/emoji/emoji_unicode_mapping_light'; import unicodeMapping from '../features/emoji/emoji_unicode_mapping_light';
import AnimatedNumber from './animated_number'; import AnimatedNumber from './animated_number';
import { assetHost } from '../utils/config'; import { assetHost } from '../utils/config';
import { autoPlayGif } from '../initial_state'; import { autoPlayGif, maxReactions } from '../initial_state';
export default class StatusReactionsBar extends ImmutablePureComponent { export default class StatusReactionsBar extends ImmutablePureComponent {
static propTypes = { static propTypes = {
statusId: PropTypes.string.isRequired, statusId: PropTypes.string.isRequired,
reactions: ImmutablePropTypes.list.isRequired, reactions: ImmutablePropTypes.list.isRequired,
reactionLimit: PropTypes.number.isRequired,
addReaction: PropTypes.func.isRequired, addReaction: PropTypes.func.isRequired,
removeReaction: PropTypes.func.isRequired, removeReaction: PropTypes.func.isRequired,
emojiMap: ImmutablePropTypes.map.isRequired, emojiMap: ImmutablePropTypes.map.isRequired,
@ -62,7 +63,7 @@ export default class StatusReactionsBar extends ImmutablePureComponent {
/> />
))} ))}
{visibleReactions.size < 8 && <EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} button={<Icon id='plus' />} />} {visibleReactions.size < maxReactions && <EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} button={<Icon id='plus' />} />}
</div> </div>
)} )}
</TransitionMotion> </TransitionMotion>

View file

@ -159,4 +159,7 @@ export const pollLimits = (initialState && initialState.poll_limits);
export const defaultContentType = getMeta('default_content_type'); export const defaultContentType = getMeta('default_content_type');
export const useSystemEmojiFont = getMeta('system_emoji_font'); export const useSystemEmojiFont = getMeta('system_emoji_font');
// nyastodon-specific settings
export const maxReactions = (initialState && initialState.max_reactions) || 8;
export default initialState; export default initialState;

View file

@ -6,7 +6,7 @@ class InitialStateSerializer < ActiveModel::Serializer
attributes :meta, :compose, :accounts, attributes :meta, :compose, :accounts,
:media_attachments, :settings, :media_attachments, :settings,
:max_toot_chars, :poll_limits, :max_toot_chars, :poll_limits,
:languages :languages, :max_reactions
has_one :push_subscription, serializer: REST::WebPushSubscriptionSerializer has_one :push_subscription, serializer: REST::WebPushSubscriptionSerializer
has_one :role, serializer: REST::RoleSerializer has_one :role, serializer: REST::RoleSerializer
@ -15,6 +15,10 @@ class InitialStateSerializer < ActiveModel::Serializer
StatusLengthValidator::MAX_CHARS StatusLengthValidator::MAX_CHARS
end end
def max_reactions
StatusReactionValidator::LIMIT
end
def poll_limits def poll_limits
{ {
max_options: PollValidator::MAX_OPTIONS, max_options: PollValidator::MAX_OPTIONS,

View file

@ -5,12 +5,11 @@ class StatusReactionService < BaseService
include Payloadable include Payloadable
def call(account, status, emoji) 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? 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) reaction = StatusReaction.create!(account: account, status: status, name: name, custom_emoji: custom_emoji)
json = Oj.dump(serialize_payload(reaction, ActivityPub::EmojiReactionSerializer)) json = Oj.dump(serialize_payload(reaction, ActivityPub::EmojiReactionSerializer))

View file

@ -3,13 +3,13 @@
class StatusReactionValidator < ActiveModel::Validator class StatusReactionValidator < ActiveModel::Validator
SUPPORTED_EMOJIS = Oj.load_file(Rails.root.join('app', 'javascript', 'mastodon', 'features', 'emoji', 'emoji_map.json').to_s).keys.freeze 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) def validate(reaction)
return if reaction.name.blank? 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(: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 end
private private
@ -23,6 +23,6 @@ class StatusReactionValidator < ActiveModel::Validator
end end
def limit_reached?(reaction) 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
end end