feat: support reply to for incoming messages on facebook (#8076)

Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
This commit is contained in:
Shivam Mishra
2023-10-13 16:33:50 +05:30
committed by GitHub
parent 7b09fa4a03
commit 62d8ec7edb
7 changed files with 83 additions and 3 deletions

View File

@@ -93,6 +93,9 @@ class Messages::Facebook::MessageBuilder < Messages::Messenger::MessageBuilder
message_type: @message_type, message_type: @message_type,
content: response.content, content: response.content,
source_id: response.identifier, source_id: response.identifier,
content_attributes: {
in_reply_to_external_id: response.in_reply_to_external_id
},
sender: @outgoing_echo ? nil : @contact_inbox.contact sender: @outgoing_echo ? nil : @contact_inbox.contact
} }
end end

View File

@@ -35,8 +35,9 @@
/> />
</blockquote> </blockquote>
<bubble-reply-to <bubble-reply-to
v-if="inReplyToMessageId && inboxSupportsReplyTo" v-if="inReplyToMessageId"
:message="inReplyTo" :message="inReplyTo"
:message-type="data.message_type"
/> />
<bubble-text <bubble-text
v-if="data.content" v-if="data.content"

View File

@@ -1,6 +1,11 @@
<template> <template>
<div <div
class="px-2 py-1.5 -mx-2 rounded-md bg-woot-600 text-woot-50 min-w-[15rem] mb-2" class="px-2 py-1.5 -mx-2 rounded-sm min-w-[15rem] mb-2"
:class="{
'bg-slate-100 dark:bg-slate-600 dark:text-slate-50':
messageType === MESSAGE_TYPE.INCOMING,
'bg-woot-600 text-woot-50': messageType === MESSAGE_TYPE.OUTGOING,
}"
> >
<message-preview <message-preview
:message="message" :message="message"
@@ -12,6 +17,7 @@
<script> <script>
import MessagePreview from 'dashboard/components/widgets/conversation/MessagePreview.vue'; import MessagePreview from 'dashboard/components/widgets/conversation/MessagePreview.vue';
import { MESSAGE_TYPE } from 'shared/constants/messages';
export default { export default {
name: 'ReplyTo', name: 'ReplyTo',
@@ -23,6 +29,13 @@ export default {
type: Object, type: Object,
required: true, required: true,
}, },
messageType: {
type: Number,
required: true,
},
},
data() {
return { MESSAGE_TYPE };
}, },
}; };
</script> </script>

View File

@@ -20,7 +20,6 @@ export const INBOX_FEATURES = {
export const INBOX_FEATURE_MAP = { export const INBOX_FEATURE_MAP = {
[INBOX_FEATURES.REPLY_TO]: [ [INBOX_FEATURES.REPLY_TO]: [
INBOX_TYPES.WEB, INBOX_TYPES.WEB,
INBOX_TYPES.FB,
INBOX_TYPES.TWITTER, INBOX_TYPES.TWITTER,
INBOX_TYPES.WHATSAPP, INBOX_TYPES.WHATSAPP,
INBOX_TYPES.LINE, INBOX_TYPES.LINE,

View File

@@ -60,6 +60,7 @@ class Message < ApplicationRecord
before_validation :ensure_content_type before_validation :ensure_content_type
before_save :ensure_processed_message_content before_save :ensure_processed_message_content
before_save :ensure_in_reply_to
validates :account_id, presence: true validates :account_id, presence: true
validates :inbox_id, presence: true validates :inbox_id, presence: true
@@ -233,6 +234,20 @@ class Message < ApplicationRecord
self.processed_message_content = message_content&.truncate(150_000) self.processed_message_content = message_content&.truncate(150_000)
end 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 def ensure_content_type
self.content_type ||= Message.content_types[:text] self.content_type ||= Message.content_types[:text]
end end

View File

@@ -47,6 +47,10 @@ class Integrations::Facebook::MessageParser
def sent_from_chatwoot_app? def sent_from_chatwoot_app?
app_id && app_id == GlobalConfigService.load('FB_APP_ID', '').to_i app_id && app_id == GlobalConfigService.load('FB_APP_ID', '').to_i
end end
def in_reply_to_external_id
@messaging.dig('message', 'reply_to', 'mid')
end
end end
# Sample Response # Sample Response

View File

@@ -415,4 +415,49 @@ RSpec.describe Message do
expect(instagram_message.reload.attachments.count).to eq 1 expect(instagram_message.reload.attachments.count).to eq 1
end end
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 end