From 62d8ec7edb60c879ce269187221b453832c4800d Mon Sep 17 00:00:00 2001 From: Shivam Mishra Date: Fri, 13 Oct 2023 16:33:50 +0530 Subject: [PATCH] feat: support reply to for incoming messages on facebook (#8076) Co-authored-by: Pranav Raj S --- .../messages/facebook/message_builder.rb | 3 ++ .../widgets/conversation/Message.vue | 3 +- .../widgets/conversation/bubble/ReplyTo.vue | 15 ++++++- app/javascript/shared/mixins/inboxMixin.js | 1 - app/models/message.rb | 15 +++++++ lib/integrations/facebook/message_parser.rb | 4 ++ spec/models/message_spec.rb | 45 +++++++++++++++++++ 7 files changed, 83 insertions(+), 3 deletions(-) diff --git a/app/builders/messages/facebook/message_builder.rb b/app/builders/messages/facebook/message_builder.rb index e0343c0a0..3efb184b9 100644 --- a/app/builders/messages/facebook/message_builder.rb +++ b/app/builders/messages/facebook/message_builder.rb @@ -93,6 +93,9 @@ class Messages::Facebook::MessageBuilder < Messages::Messenger::MessageBuilder message_type: @message_type, content: response.content, source_id: response.identifier, + content_attributes: { + in_reply_to_external_id: response.in_reply_to_external_id + }, sender: @outgoing_echo ? nil : @contact_inbox.contact } end diff --git a/app/javascript/dashboard/components/widgets/conversation/Message.vue b/app/javascript/dashboard/components/widgets/conversation/Message.vue index 70f680db6..19d05f138 100644 --- a/app/javascript/dashboard/components/widgets/conversation/Message.vue +++ b/app/javascript/dashboard/components/widgets/conversation/Message.vue @@ -35,8 +35,9 @@ />
import MessagePreview from 'dashboard/components/widgets/conversation/MessagePreview.vue'; +import { MESSAGE_TYPE } from 'shared/constants/messages'; export default { name: 'ReplyTo', @@ -23,6 +29,13 @@ export default { type: Object, required: true, }, + messageType: { + type: Number, + required: true, + }, + }, + data() { + return { MESSAGE_TYPE }; }, }; diff --git a/app/javascript/shared/mixins/inboxMixin.js b/app/javascript/shared/mixins/inboxMixin.js index dd80ebad2..35819d7ae 100644 --- a/app/javascript/shared/mixins/inboxMixin.js +++ b/app/javascript/shared/mixins/inboxMixin.js @@ -20,7 +20,6 @@ export const INBOX_FEATURES = { export const INBOX_FEATURE_MAP = { [INBOX_FEATURES.REPLY_TO]: [ INBOX_TYPES.WEB, - INBOX_TYPES.FB, INBOX_TYPES.TWITTER, INBOX_TYPES.WHATSAPP, INBOX_TYPES.LINE, diff --git a/app/models/message.rb b/app/models/message.rb index 0a6763949..702c1193e 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -60,6 +60,7 @@ class Message < ApplicationRecord before_validation :ensure_content_type before_save :ensure_processed_message_content + before_save :ensure_in_reply_to validates :account_id, presence: true validates :inbox_id, presence: true @@ -233,6 +234,20 @@ class Message < ApplicationRecord self.processed_message_content = message_content&.truncate(150_000) end + # fetch the in_reply_to message and set the external id + def ensure_in_reply_to + in_reply_to = content_attributes[:in_reply_to] + in_reply_to_external_id = content_attributes[:in_reply_to_external_id] + + if in_reply_to.present? && in_reply_to_external_id.blank? + message = conversation.messages.find_by(id: in_reply_to) + content_attributes[:in_reply_to_external_id] = message.try(:source_id) + elsif in_reply_to_external_id.present? && in_reply_to.blank? + message = conversation.messages.find_by(source_id: in_reply_to_external_id) + content_attributes[:in_reply_to] = message.try(:id) + end + end + def ensure_content_type self.content_type ||= Message.content_types[:text] end diff --git a/lib/integrations/facebook/message_parser.rb b/lib/integrations/facebook/message_parser.rb index ea70ca442..123b521cb 100644 --- a/lib/integrations/facebook/message_parser.rb +++ b/lib/integrations/facebook/message_parser.rb @@ -47,6 +47,10 @@ class Integrations::Facebook::MessageParser def sent_from_chatwoot_app? app_id && app_id == GlobalConfigService.load('FB_APP_ID', '').to_i end + + def in_reply_to_external_id + @messaging.dig('message', 'reply_to', 'mid') + end end # Sample Response diff --git a/spec/models/message_spec.rb b/spec/models/message_spec.rb index 88a0bd898..9f8ea00a1 100644 --- a/spec/models/message_spec.rb +++ b/spec/models/message_spec.rb @@ -415,4 +415,49 @@ RSpec.describe Message do expect(instagram_message.reload.attachments.count).to eq 1 end end + + describe '#ensure_in_reply_to' do + let(:conversation) { create(:conversation) } + let(:message) { create(:message, conversation: conversation, source_id: 12_345) } + + context 'when in_reply_to is present' do + let(:content_attributes) { { in_reply_to: message.id } } + let(:new_message) { build(:message, conversation: conversation, content_attributes: content_attributes) } + + it 'sets in_reply_to_external_id based on the source_id of the referenced message' do + new_message.send(:ensure_in_reply_to) + expect(new_message.content_attributes[:in_reply_to_external_id]).to eq(message.source_id) + end + end + + context 'when in_reply_to is not present' do + let(:content_attributes) { { in_reply_to_external_id: message.source_id } } + let(:new_message) { build(:message, conversation: conversation, content_attributes: content_attributes) } + + it 'sets in_reply_to based on the source_id of the referenced message' do + new_message.send(:ensure_in_reply_to) + expect(new_message.content_attributes[:in_reply_to]).to eq(message.id) + end + end + + context 'when the referenced message is not found' do + let(:content_attributes) { { in_reply_to: message.id + 1 } } + let(:new_message) { build(:message, conversation: conversation, content_attributes: content_attributes) } + + it 'does not set in_reply_to_external_id' do + new_message.send(:ensure_in_reply_to) + expect(new_message.content_attributes[:in_reply_to_external_id]).to be_nil + end + end + + context 'when the source message is not found' do + let(:content_attributes) { { in_reply_to_external_id: 'source-id-that-does-not-exist' } } + let(:new_message) { build(:message, conversation: conversation, content_attributes: content_attributes) } + + it 'does not set in_reply_to' do + new_message.send(:ensure_in_reply_to) + expect(new_message.content_attributes[:in_reply_to]).to be_nil + end + end + end end