fix: Duplicate messages in Whatsapp Channel (#6220)

fixes: #5433
This commit is contained in:
Sojan Jose
2023-01-10 18:57:34 +05:30
committed by GitHub
parent 60f16e8954
commit c16624dc5d
2 changed files with 42 additions and 31 deletions

View File

@@ -7,26 +7,36 @@ class Whatsapp::IncomingMessageBaseService
def perform def perform
processed_params processed_params
perform_statuses if processed_params[:statuses].present?
process_statuses
elsif processed_params[:messages].present?
process_messages
end
end
private
def find_message_by_source_id(source_id)
return unless source_id
@message = Message.find_by(source_id: source_id)
end
def process_messages
# message allready exists so we don't need to process
return if find_message_by_source_id(@processed_params[:messages].first[:id])
set_contact set_contact
return unless @contact return unless @contact
set_conversation set_conversation
create_messages
perform_messages
end end
private def process_statuses
return unless find_message_by_source_id(@processed_params[:statuses].first[:id])
def perform_statuses update_message_with_status(@message, @processed_params[:statuses].first)
return if @processed_params[:statuses].blank?
status = @processed_params[:statuses].first
@message = Message.find_by(source_id: status[:id])
return unless @message
update_message_with_status(@message, status)
end end
def update_message_with_status(message, status) def update_message_with_status(message, status)
@@ -38,8 +48,8 @@ class Whatsapp::IncomingMessageBaseService
message.save! message.save!
end end
def perform_messages def create_messages
return if @processed_params[:messages].blank? || unprocessable_message_type? return if unprocessable_message_type?
@message = @conversation.messages.build( @message = @conversation.messages.build(
content: message_content(@processed_params[:messages].first), content: message_content(@processed_params[:messages].first),
@@ -50,7 +60,7 @@ class Whatsapp::IncomingMessageBaseService
source_id: @processed_params[:messages].first[:id].to_s source_id: @processed_params[:messages].first[:id].to_s
) )
attach_files attach_files
attach_location attach_location if message_type == 'location'
@message.save! @message.save!
end end
@@ -60,9 +70,7 @@ class Whatsapp::IncomingMessageBaseService
def message_content(message) def message_content(message)
# TODO: map interactive messages back to button messages in chatwoot # TODO: map interactive messages back to button messages in chatwoot
message.dig(:text, :body) || message.dig(:text, :body) || message.dig(:button, :text) || message.dig(:interactive, :button_reply, :title) ||
message.dig(:button, :text) ||
message.dig(:interactive, :button_reply, :title) ||
message.dig(:interactive, :list_reply, :title) message.dig(:interactive, :list_reply, :title)
end end
@@ -142,8 +150,6 @@ class Whatsapp::IncomingMessageBaseService
end end
def attach_location def attach_location
return unless @processed_params[:messages].first[:type] == 'location'
location = @processed_params[:messages].first['location'] location = @processed_params[:messages].first['location']
location_name = location['name'] ? "#{location['name']}, #{location['address']}" : '' location_name = location['name'] ? "#{location['name']}, #{location['address']}" : ''
@message.attachments.new( @message.attachments.new(

View File

@@ -7,14 +7,16 @@ describe Whatsapp::IncomingMessageService do
end end
let!(:whatsapp_channel) { create(:channel_whatsapp, sync_templates: false) } let!(:whatsapp_channel) { create(:channel_whatsapp, sync_templates: false) }
let!(:params) do
{
'contacts' => [{ 'profile' => { 'name' => 'Sojan Jose' }, 'wa_id' => '2423423243' }],
'messages' => [{ 'from' => '2423423243', 'id' => 'SDFADSf23sfasdafasdfa', 'text' => { 'body' => 'Test' },
'timestamp' => '1633034394', 'type' => 'text' }]
}.with_indifferent_access
end
context 'when valid text message params' do context 'when valid text message params' do
it 'creates appropriate conversations, message and contacts' do it 'creates appropriate conversations, message and contacts' do
params = {
'contacts' => [{ 'profile' => { 'name' => 'Sojan Jose' }, 'wa_id' => '2423423243' }],
'messages' => [{ 'from' => '2423423243', 'id' => 'SDFADSf23sfasdafasdfa', 'text' => { 'body' => 'Test' },
'timestamp' => '1633034394', 'type' => 'text' }]
}.with_indifferent_access
described_class.new(inbox: whatsapp_channel.inbox, params: params).perform described_class.new(inbox: whatsapp_channel.inbox, params: params).perform
expect(whatsapp_channel.inbox.conversations.count).not_to eq(0) expect(whatsapp_channel.inbox.conversations.count).not_to eq(0)
expect(Contact.all.first.name).to eq('Sojan Jose') expect(Contact.all.first.name).to eq('Sojan Jose')
@@ -22,12 +24,6 @@ describe Whatsapp::IncomingMessageService do
end end
it 'appends to last conversation when if conversation already exisits' do it 'appends to last conversation when if conversation already exisits' do
params = {
'contacts' => [{ 'profile' => { 'name' => 'Sojan Jose' }, 'wa_id' => '2423423243' }],
'messages' => [{ 'from' => '2423423243', 'id' => 'SDFADSf23sfasdafasdfa', 'text' => { 'body' => 'Test' },
'timestamp' => '1633034394', 'type' => 'text' }]
}.with_indifferent_access
contact_inbox = create(:contact_inbox, inbox: whatsapp_channel.inbox, source_id: params[:messages].first[:from]) contact_inbox = create(:contact_inbox, inbox: whatsapp_channel.inbox, source_id: params[:messages].first[:from])
2.times.each { create(:conversation, inbox: whatsapp_channel.inbox, contact_inbox: contact_inbox) } 2.times.each { create(:conversation, inbox: whatsapp_channel.inbox, contact_inbox: contact_inbox) }
last_conversation = create(:conversation, inbox: whatsapp_channel.inbox, contact_inbox: contact_inbox) last_conversation = create(:conversation, inbox: whatsapp_channel.inbox, contact_inbox: contact_inbox)
@@ -37,6 +33,15 @@ describe Whatsapp::IncomingMessageService do
# message appended to the last conversation # message appended to the last conversation
expect(last_conversation.messages.last.content).to eq(params[:messages].first[:text][:body]) expect(last_conversation.messages.last.content).to eq(params[:messages].first[:text][:body])
end end
it 'will not create duplicate messages when same message is received' do
described_class.new(inbox: whatsapp_channel.inbox, params: params).perform
expect(whatsapp_channel.inbox.messages.count).to eq(1)
# this shouldn't create a duplicate message
described_class.new(inbox: whatsapp_channel.inbox, params: params).perform
expect(whatsapp_channel.inbox.messages.count).to eq(1)
end
end end
context 'when unsupported message types' do context 'when unsupported message types' do