99 lines
3.3 KiB
Ruby
99 lines
3.3 KiB
Ruby
module Whatsapp
|
|
class IncomingMessageWuzapiService < IncomingMessageBaseService
|
|
def perform
|
|
parser = Whatsapp::Providers::Wuzapi::PayloadParser.new(params)
|
|
|
|
# 1. Message Type Check (V1: Text + Presence)
|
|
# Fail fast for unsupported types (like ReadReceipts)
|
|
return unless [:text, :chat_presence].include?(parser.message_type)
|
|
|
|
# 2. V1 Scope: Ignore Groups
|
|
if parser.group_message?
|
|
Rails.logger.info "WuzAPI: Ignoring group message (ID: #{parser.external_id})"
|
|
return
|
|
end
|
|
|
|
# 3. Strong Dedupe (Critical for Sync)
|
|
# Skip dedupe for ChatPresence as it doesn't have a unique ID
|
|
if parser.message_type != :chat_presence && parser.external_id.present? && Message.exists?(source_id: parser.external_id, inbox_id: inbox.id)
|
|
Rails.logger.info "WuzAPI: Ignoring duplicate message (ID: #{parser.external_id})"
|
|
return
|
|
end
|
|
|
|
if parser.sender_phone_number.blank?
|
|
Rails.logger.warn "WuzAPI: Skipping processing for event with no valid phone (Type: #{parser.message_type})"
|
|
return
|
|
end
|
|
|
|
# 4. Process
|
|
Rails.logger.info "WuzAPI: Processing message from #{parser.sender_phone_number} (Type: #{parser.message_type})"
|
|
ActiveRecord::Base.transaction do
|
|
@contact = find_or_create_contact(parser)
|
|
Rails.logger.info "WuzAPI: Contact found/created: #{@contact.id}"
|
|
|
|
@conversation = find_or_create_conversation(@contact)
|
|
Rails.logger.info "WuzAPI: Conversation found/created: #{@conversation.id}"
|
|
|
|
if parser.message_type == :chat_presence
|
|
status = parser.presence_state == 'composing' ? 'on' : 'off'
|
|
@conversation.toggle_typing_status(status)
|
|
return
|
|
end
|
|
|
|
message = create_message(parser, @conversation)
|
|
Rails.logger.info "WuzAPI: Message created: #{message.id}"
|
|
end
|
|
rescue StandardError => e
|
|
Rails.logger.error "WuzAPI Error: #{e.message}"
|
|
Rails.logger.error e.backtrace.join("\n")
|
|
raise e
|
|
end
|
|
|
|
private
|
|
|
|
def find_or_create_contact(parser)
|
|
# Normalize phone
|
|
phone = parser.sender_phone_number
|
|
normalized_phone = "+#{phone}"
|
|
|
|
contact_inbox = ::ContactInboxWithContactBuilder.new(
|
|
source_id: phone,
|
|
inbox: inbox,
|
|
contact_attributes: {
|
|
name: parser.push_name || phone,
|
|
phone_number: normalized_phone
|
|
}
|
|
).perform
|
|
|
|
contact_inbox.contact
|
|
end
|
|
|
|
def find_or_create_conversation(contact)
|
|
conversation = inbox.conversations.where(contact_id: contact.id)
|
|
.where.not(status: :resolved)
|
|
.last
|
|
|
|
conversation || ::Conversation.create!(
|
|
account_id: inbox.account_id,
|
|
inbox_id: inbox.id,
|
|
contact_id: contact.id,
|
|
contact_inbox_id: ContactInbox.find_by(contact_id: contact.id, inbox_id: inbox.id)&.id
|
|
)
|
|
end
|
|
|
|
def create_message(parser, conversation)
|
|
is_outgoing = parser.from_me?
|
|
|
|
conversation.messages.create!(
|
|
content: parser.text_content,
|
|
account_id: inbox.account_id,
|
|
inbox_id: inbox.id,
|
|
message_type: is_outgoing ? :outgoing : :incoming,
|
|
sender: is_outgoing ? nil : @contact,
|
|
source_id: parser.external_id,
|
|
created_at: parser.timestamp
|
|
)
|
|
end
|
|
end
|
|
end
|