87 lines
2.4 KiB
Ruby
87 lines
2.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class Chat::ChatMessageReactor
|
|
ADD_REACTION = :add
|
|
REMOVE_REACTION = :remove
|
|
MAX_REACTIONS_LIMIT = 30
|
|
|
|
def initialize(user, chat_channel)
|
|
@user = user
|
|
@chat_channel = chat_channel
|
|
@guardian = Guardian.new(user)
|
|
end
|
|
|
|
def react!(message_id:, react_action:, emoji:)
|
|
@guardian.ensure_can_join_chat_channel!(@chat_channel)
|
|
@guardian.ensure_can_react!
|
|
validate_channel_status!
|
|
validate_reaction!(react_action, emoji)
|
|
message = ensure_chat_message!(message_id)
|
|
validate_max_reactions!(message, react_action, emoji)
|
|
|
|
reaction = nil
|
|
ActiveRecord::Base.transaction do
|
|
enforce_channel_membership!
|
|
reaction = create_reaction(message, react_action, emoji)
|
|
end
|
|
|
|
publish_reaction(message, react_action, emoji)
|
|
|
|
reaction
|
|
end
|
|
|
|
private
|
|
|
|
def ensure_chat_message!(message_id)
|
|
message = ChatMessage.find_by(id: message_id, chat_channel: @chat_channel)
|
|
raise Discourse::NotFound unless message
|
|
message
|
|
end
|
|
|
|
def validate_reaction!(react_action, emoji)
|
|
if ![ADD_REACTION, REMOVE_REACTION].include?(react_action) || !Emoji.exists?(emoji)
|
|
raise Discourse::InvalidParameters
|
|
end
|
|
end
|
|
|
|
def enforce_channel_membership!
|
|
Chat::ChatChannelMembershipManager.new(@chat_channel).follow(@user)
|
|
end
|
|
|
|
def validate_channel_status!
|
|
return if @guardian.can_create_channel_message?(@chat_channel)
|
|
raise Discourse::InvalidAccess.new(
|
|
nil,
|
|
nil,
|
|
custom_message: "chat.errors.channel_modify_message_disallowed",
|
|
custom_message_params: {
|
|
status: @chat_channel.status_name,
|
|
},
|
|
)
|
|
end
|
|
|
|
def validate_max_reactions!(message, react_action, emoji)
|
|
if react_action == ADD_REACTION &&
|
|
message.reactions.count("DISTINCT emoji") >= MAX_REACTIONS_LIMIT &&
|
|
!message.reactions.exists?(emoji: emoji)
|
|
raise Discourse::InvalidAccess.new(
|
|
nil,
|
|
nil,
|
|
custom_message: "chat.errors.max_reactions_limit_reached",
|
|
)
|
|
end
|
|
end
|
|
|
|
def create_reaction(message, react_action, emoji)
|
|
if react_action == ADD_REACTION
|
|
message.reactions.find_or_create_by!(user: @user, emoji: emoji)
|
|
else
|
|
message.reactions.where(user: @user, emoji: emoji).destroy_all
|
|
end
|
|
end
|
|
|
|
def publish_reaction(message, react_action, emoji)
|
|
ChatPublisher.publish_reaction!(@chat_channel, message, react_action, @user, emoji)
|
|
end
|
|
end
|