chatwoot-develop/app/services/whatsapp/baileys_handlers/messages_update.rb

87 lines
2.6 KiB
Ruby
Executable File

module Whatsapp::BaileysHandlers::MessagesUpdate
include Whatsapp::BaileysHandlers::Helpers
class MessageNotFoundError < StandardError; end
private
def process_messages_update
updates = processed_params[:data]
updates.each do |update|
@message = nil
@raw_message = update
next handle_update if incoming?
# NOTE: Shared lock with Whatsapp::SendOnWhatsappService
# Avoids race conditions when sending messages.
with_baileys_channel_lock_on_outgoing_message(inbox.channel.id) { handle_update }
end
end
def handle_update
raise MessageNotFoundError unless find_message_by_source_id(raw_message_id)
update_status if @raw_message.dig(:update, :status).present?
handle_edited_content if @raw_message.dig(:update, :message).present?
end
def update_status
status = status_mapper
update_last_seen_at if incoming? && status == 'read'
@message.update!(status: status) if status.present? && status_transition_allowed?(status)
end
def status_mapper
# NOTE: Baileys status codes vs. Chatwoot support:
# - (0) ERROR → (3) failed
# - (1) PENDING → (0) sent
# - (2) SERVER_ACK → (0) sent
# - (3) DELIVERY_ACK → (1) delivered
# - (4) READ → (2) read
# - (5) PLAYED → (unsupported: PLAYED)
# For details: https://github.com/WhiskeySockets/Baileys/blob/v6.7.16/WAProto/index.d.ts#L36694
status = @raw_message.dig(:update, :status)
case status
when 0
'failed'
when 1, 2
'sent'
when 3
'delivered'
when 4
'read'
when 5
Rails.logger.warn 'Baileys unsupported message update status: PLAYED(5)'
nil
else
Rails.logger.warn "Baileys unsupported message update status: #{status}"
nil
end
end
def update_last_seen_at
conversation = @message.conversation
to_update = { agent_last_seen_at: Time.current }
to_update[:assignee_last_seen_at] = Time.current if conversation.assignee_id.present?
conversation.update_columns(to_update) # rubocop:disable Rails/SkipsModelValidations
end
def status_transition_allowed?(new_status)
return false if @message.status == 'read'
return false if @message.status == 'delivered' && new_status == 'sent'
true
end
def handle_edited_content
@raw_message = @raw_message.dig(:update, :message, :editedMessage)
content = message_content
return @message.update!(content: content, is_edited: true, previous_content: @message.content) if content
Rails.logger.warn 'No valid message content found in the edit event'
end
end