86 lines
2.4 KiB
Ruby
86 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_see_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)
|
||
|
|
||
|
ActiveRecord::Base.transaction do
|
||
|
enforce_channel_membership!
|
||
|
create_reaction(message, react_action, emoji)
|
||
|
end
|
||
|
|
||
|
publish_reaction(message, react_action, emoji)
|
||
|
|
||
|
message
|
||
|
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
|