fix: Fixes reply-to in WhatsApp Cloud API (#13467)
This change https://github.com/chatwoot/chatwoot/pull/13371 broke the functionality. When a user replies to a WhatsApp message, the reply context wasn't being properly stored in Chatwoot due to #13371 WhatsApp sends reply messages with a `context` field containing the original message ID: ```json { "messages": [{ "context": { "from": "phone_number", "id": "wamid.ORIGINAL_MESSAGE_ID" }, "from": "phone_number", "id": "wamid.REPLY_MESSAGE_ID", "text": { "body": "This is a reply" } }] } ``` However, the in_reply_to_external_id was being overridden when building the message because content_attributes was explicitly set to either { external_echo: true } or {}, which discarded the reply-to information.
This commit is contained in:
@@ -144,7 +144,7 @@ jobs:
|
|||||||
# Backend tests with parallelization
|
# Backend tests with parallelization
|
||||||
backend-tests:
|
backend-tests:
|
||||||
<<: *defaults
|
<<: *defaults
|
||||||
parallelism: 20
|
parallelism: 18
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- node/install:
|
- node/install:
|
||||||
@@ -350,12 +350,12 @@ jobs:
|
|||||||
destination: coverage
|
destination: coverage
|
||||||
|
|
||||||
build:
|
build:
|
||||||
<<: *defaults
|
<<: *defaults
|
||||||
steps:
|
steps:
|
||||||
- run:
|
- run:
|
||||||
name: Legacy build aggregator
|
name: Legacy build aggregator
|
||||||
command: |
|
command: |
|
||||||
echo "All main jobs passed; build job kept only for GitHub required check compatibility."
|
echo "All main jobs passed; build job kept only for GitHub required check compatibility."
|
||||||
|
|
||||||
workflows:
|
workflows:
|
||||||
version: 2
|
version: 2
|
||||||
|
|||||||
@@ -175,6 +175,9 @@ class Whatsapp::IncomingMessageBaseService
|
|||||||
end
|
end
|
||||||
|
|
||||||
def create_message(message, source_id: nil)
|
def create_message(message, source_id: nil)
|
||||||
|
content_attrs = outgoing_echo ? { external_echo: true } : {}
|
||||||
|
content_attrs[:in_reply_to_external_id] = @in_reply_to_external_id if @in_reply_to_external_id.present?
|
||||||
|
|
||||||
@message = @conversation.messages.build(
|
@message = @conversation.messages.build(
|
||||||
content: message_content(message),
|
content: message_content(message),
|
||||||
account_id: @inbox.account_id,
|
account_id: @inbox.account_id,
|
||||||
@@ -184,8 +187,7 @@ class Whatsapp::IncomingMessageBaseService
|
|||||||
status: outgoing_echo ? :delivered : :sent,
|
status: outgoing_echo ? :delivered : :sent,
|
||||||
sender: outgoing_echo ? nil : @contact,
|
sender: outgoing_echo ? nil : @contact,
|
||||||
source_id: (source_id || message[:id]).to_s,
|
source_id: (source_id || message[:id]).to_s,
|
||||||
content_attributes: outgoing_echo ? { external_echo: true } : {},
|
content_attributes: content_attrs
|
||||||
in_reply_to_external_id: @in_reply_to_external_id
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -102,6 +102,65 @@ describe Whatsapp::IncomingMessageWhatsappCloudService do
|
|||||||
expect(whatsapp_channel.inbox.messages.count).to eq(0)
|
expect(whatsapp_channel.inbox.messages.count).to eq(0)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when message is a reply (has context)' do
|
||||||
|
let(:reply_params) do
|
||||||
|
{
|
||||||
|
phone_number: whatsapp_channel.phone_number,
|
||||||
|
object: 'whatsapp_business_account',
|
||||||
|
entry: [{
|
||||||
|
changes: [{
|
||||||
|
value: {
|
||||||
|
contacts: [{ profile: { name: 'Pranav' }, wa_id: '16503071063' }],
|
||||||
|
messages: [{
|
||||||
|
context: {
|
||||||
|
from: '16503071063',
|
||||||
|
id: 'wamid.ORIGINAL_MESSAGE_ID'
|
||||||
|
},
|
||||||
|
from: '16503071063',
|
||||||
|
id: 'wamid.REPLY_MESSAGE_ID',
|
||||||
|
timestamp: '1770407829',
|
||||||
|
text: { body: 'This is a reply' },
|
||||||
|
type: 'text'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}.with_indifferent_access
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the original message exists in Chatwoot' do
|
||||||
|
it 'sets in_reply_to to reference the existing message' do
|
||||||
|
# Create a conversation and the original message that will be replied to first
|
||||||
|
contact = create(:contact, phone_number: '+16503071063', account: whatsapp_channel.account)
|
||||||
|
contact_inbox = create(:contact_inbox, contact: contact, inbox: whatsapp_channel.inbox, source_id: '16503071063')
|
||||||
|
conversation = create(:conversation, contact: contact, inbox: whatsapp_channel.inbox, contact_inbox: contact_inbox)
|
||||||
|
|
||||||
|
original_message = create(:message,
|
||||||
|
conversation: conversation,
|
||||||
|
source_id: 'wamid.ORIGINAL_MESSAGE_ID',
|
||||||
|
content: 'Original message')
|
||||||
|
|
||||||
|
described_class.new(inbox: whatsapp_channel.inbox, params: reply_params).perform
|
||||||
|
|
||||||
|
reply_message = whatsapp_channel.inbox.messages.last
|
||||||
|
expect(reply_message.content).to eq('This is a reply')
|
||||||
|
expect(reply_message.content_attributes['in_reply_to']).to eq(original_message.id)
|
||||||
|
expect(reply_message.content_attributes['in_reply_to_external_id']).to eq('wamid.ORIGINAL_MESSAGE_ID')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the original message does not exist in Chatwoot' do
|
||||||
|
it 'does not set in_reply_to (discards the reply reference)' do
|
||||||
|
described_class.new(inbox: whatsapp_channel.inbox, params: reply_params).perform
|
||||||
|
|
||||||
|
reply_message = whatsapp_channel.inbox.messages.last
|
||||||
|
expect(reply_message.content).to eq('This is a reply')
|
||||||
|
expect(reply_message.content_attributes['in_reply_to']).to be_nil
|
||||||
|
expect(reply_message.content_attributes['in_reply_to_external_id']).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Métodos auxiliares para reduzir o tamanho do exemplo
|
# Métodos auxiliares para reduzir o tamanho do exemplo
|
||||||
|
|||||||
Reference in New Issue
Block a user