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:
parent
c369bd3154
commit
f1952244d1
6 changed files with 18 additions and 11 deletions
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue