diff --git a/app/services/whatsapp/incoming_message_baileys_service.rb b/app/services/whatsapp/incoming_message_baileys_service.rb index fe4ba67b1..34a0fc296 100644 --- a/app/services/whatsapp/incoming_message_baileys_service.rb +++ b/app/services/whatsapp/incoming_message_baileys_service.rb @@ -46,6 +46,7 @@ class Whatsapp::IncomingMessageBaileysService < Whatsapp::IncomingMessageBaseSer end def handle_message + return if jid_type != 'user' return if find_message_by_source_id(message_id) || message_under_process? cache_message_source_id_in_redis @@ -62,16 +63,23 @@ class Whatsapp::IncomingMessageBaileysService < Whatsapp::IncomingMessageBaseSer end def set_contact - phone_number_from_jid = @raw_message[:key][:remoteJid].split('@').first.split(':').first - + # NOTE: jid shape is `_:@` + # https://github.com/WhiskeySockets/Baileys/blob/v6.7.16/src/WABinary/jid-utils.ts#L19 + phone_number_from_jid = @raw_message[:key][:remoteJid].split('@').first.split(':').first.split('_').first + phone_number_formatted = "+#{phone_number_from_jid}" + # NOTE: We're assuming `pushName` will always be present when `fromMe: false`. + # This assumption might be incorrect, so let's keep an eye out for contacts being created with empty name. + push_name = @raw_message[:key][:fromMe] ? phone_number_formatted : @raw_message[:pushName].to_s contact_inbox = ::ContactInboxWithContactBuilder.new( source_id: phone_number_from_jid, inbox: inbox, - contact_attributes: { name: @raw_message[:pushName], phone_number: "+#{phone_number_from_jid}" } + contact_attributes: { name: push_name, phone_number: phone_number_formatted } ).perform @contact_inbox = contact_inbox @contact = contact_inbox.contact + + @contact.update!(name: push_name) if @contact.name == phone_number_formatted && !@raw_message[:key][:fromMe] end def handle_create_message @@ -83,9 +91,34 @@ class Whatsapp::IncomingMessageBaileysService < Whatsapp::IncomingMessageBaseSer end end + def jid_type # rubocop:disable Metrics/CyclomaticComplexity + jid = @raw_message[:key][:remoteJid] + server = jid.split('@').last + + # NOTE: Based on Baileys internal functions + # https://github.com/WhiskeySockets/Baileys/blob/v6.7.16/src/WABinary/jid-utils.ts#L48-L58 + case server + when 's.whatsapp.net', 'c.us' + 'user' + when 'g.us' + 'group' + when 'lid' + 'lid' + when 'broadcast' + jid.start_with?('status@') ? 'status' : 'broadcast' + when 'newsletter' + 'newsletter' + when 'call' + 'call' + else + 'unknown' + end + end + def message_type # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity msg = @raw_message[:message] - return 'text' if msg.key?(:conversation) || msg.dig(:extendedTextMessage, :text) + + return 'text' if msg.key?(:conversation) || msg.dig(:extendedTextMessage, :text).present? return 'contacts' if msg.key?(:contactMessage) return 'image' if msg.key?(:imageMessage) return 'audio' if msg.key?(:audioMessage) diff --git a/spec/services/whatsapp/incoming_message_baileys_service_spec.rb b/spec/services/whatsapp/incoming_message_baileys_service_spec.rb index 88411fff0..4bc7ab5bd 100644 --- a/spec/services/whatsapp/incoming_message_baileys_service_spec.rb +++ b/spec/services/whatsapp/incoming_message_baileys_service_spec.rb @@ -173,6 +173,32 @@ describe Whatsapp::IncomingMessageBaileysService do end end + context 'when message is not from a user' do + let(:raw_message) do + { + key: { id: 'msg_123', remoteJid: 'status@broadcast', participant: '5511912345678@s.whatsapp.net', fromMe: false }, + message: { extendedTextMessage: { text: 'message' } }, + pushName: 'John Doe' + } + end + let(:params) do + { + webhookVerifyToken: webhook_verify_token, + event: 'messages.upsert', + data: { + type: 'notify', + messages: [raw_message] + } + } + end + + it 'does not create a conversation' do + described_class.new(inbox: inbox, params: params).perform + + expect(inbox.conversations).to be_empty + end + end + context 'when message type is text' do let(:raw_message) do { @@ -206,8 +232,9 @@ describe Whatsapp::IncomingMessageBaileysService do end it 'creates an outgoing message' do + number = '5511912345678' raw_message_outgoing = raw_message.merge( - key: { id: 'msg_123', remoteJid: '5511912345678@s.whatsapp.net', fromMe: true } + key: { id: 'msg_123', remoteJid: "#{number}@s.whatsapp.net", fromMe: true } ) params_outgoing = params.merge(data: { type: 'notify', messages: [raw_message_outgoing] }) create(:account_user, account: inbox.account) @@ -219,6 +246,15 @@ describe Whatsapp::IncomingMessageBaileysService do expect(message).to be_present expect(message.content).to eq('Hello from Baileys') expect(message.message_type).to eq('outgoing') + expect(conversation.contact.name).to eq("+#{number}") + end + + it 'updates the contact name if the current name is a phone number when a incoming message is received' do + create(:contact, account: inbox.account, name: '+5511912345678', phone_number: '+5511912345678') + described_class.new(inbox: inbox, params: params).perform + + conversation = inbox.conversations.last + expect(conversation.contact.name).to eq('John Doe') end it 'creates a message on an existing conversation' do @@ -265,7 +301,7 @@ describe Whatsapp::IncomingMessageBaileysService do let(:raw_message) do { key: { id: 'msg_123', remoteJid: '5511912345678@s.whatsapp.net', fromMe: false }, - message: { 'extendedTextMessage': { text: 'Hello from Baileys' } }, + message: { extendedTextMessage: { text: 'Hello from Baileys' } }, pushName: 'John Doe' } end