feat: Instagram story replies will display the original story link (#6846)

This commit is contained in:
Tejaswini Chile
2023-04-26 15:27:07 +05:30
committed by GitHub
parent 5d30dabf97
commit 3c2d6faf68
7 changed files with 112 additions and 3 deletions

View File

@@ -70,17 +70,28 @@ class Messages::Instagram::MessageBuilder < Messages::Messenger::MessageBuilder
@messaging[:message][:text] @messaging[:message][:text]
end end
def story_reply_attributes
message[:reply_to][:story] if message[:reply_to].present? && message[:reply_to][:story].present?
end
def build_message def build_message
return if @outgoing_echo && already_sent_from_chatwoot? return if @outgoing_echo && already_sent_from_chatwoot?
return if message_content.blank? && all_unsupported_files? return if message_content.blank? && all_unsupported_files?
@message = conversation.messages.create!(message_params) @message = conversation.messages.create!(message_params)
save_story_id
attachments.each do |attachment| attachments.each do |attachment|
process_attachment(attachment) process_attachment(attachment)
end end
end end
def save_story_id
return if story_reply_attributes.blank?
@message.save_story_info(story_reply_attributes)
end
def build_conversation def build_conversation
@contact_inbox ||= contact.contact_inboxes.find_by!(source_id: message_source_id) @contact_inbox ||= contact.contact_inboxes.find_by!(source_id: message_source_id)
Conversation.create!(conversation_params.merge( Conversation.create!(conversation_params.merge(

View File

@@ -22,6 +22,14 @@
:bcc="emailHeadAttributes.bcc" :bcc="emailHeadAttributes.bcc"
:is-incoming="isIncoming" :is-incoming="isIncoming"
/> />
<blockquote v-if="storyReply" class="story-reply-quote">
<span>{{ $t('CONVERSATION.REPLIED_TO_STORY') }}</span>
<bubble-image
v-if="!hasStoryError"
:url="storyUrl"
@error="onStoryLoadError"
/>
</blockquote>
<bubble-text <bubble-text
v-if="data.content" v-if="data.content"
:message="message" :message="message"
@@ -79,7 +87,7 @@
:sender="data.sender" :sender="data.sender"
:story-sender="storySender" :story-sender="storySender"
:external-error="externalError" :external-error="externalError"
:story-id="storyId" :story-id="`${storyId}`"
:is-a-tweet="isATweet" :is-a-tweet="isATweet"
:is-a-whatsapp-channel="isAWhatsAppChannel" :is-a-whatsapp-channel="isAWhatsAppChannel"
:has-instagram-story="hasInstagramStory" :has-instagram-story="hasInstagramStory"
@@ -192,6 +200,7 @@ export default {
hasImageError: false, hasImageError: false,
contextMenuPosition: {}, contextMenuPosition: {},
showBackgroundHighlight: false, showBackgroundHighlight: false,
hasStoryError: false,
}; };
}, },
computed: { computed: {
@@ -277,6 +286,12 @@ export default {
storyId() { storyId() {
return this.contentAttributes.story_id || null; return this.contentAttributes.story_id || null;
}, },
storyUrl() {
return this.contentAttributes.story_url || null;
},
storyReply() {
return this.storyUrl && this.hasInstagramStory;
},
contentType() { contentType() {
const { const {
data: { content_type: contentType }, data: { content_type: contentType },
@@ -414,10 +429,12 @@ export default {
watch: { watch: {
data() { data() {
this.hasImageError = false; this.hasImageError = false;
this.hasStoryError = false;
}, },
}, },
mounted() { mounted() {
this.hasImageError = false; this.hasImageError = false;
this.hasStoryError = false;
bus.$on(BUS_EVENTS.ON_MESSAGE_LIST_SCROLL, this.closeContextMenu); bus.$on(BUS_EVENTS.ON_MESSAGE_LIST_SCROLL, this.closeContextMenu);
this.setupHighlightTimer(); this.setupHighlightTimer();
}, },
@@ -432,6 +449,9 @@ export default {
const { file_type: fileType } = attachments[0]; const { file_type: fileType } = attachments[0];
return fileType === type && !this.hasImageError; return fileType === type && !this.hasImageError;
} }
if (this.storyReply) {
return true;
}
return false; return false;
}, },
handleContextMenuClick() { handleContextMenuClick() {
@@ -443,6 +463,9 @@ export default {
onImageLoadError() { onImageLoadError() {
this.hasImageError = true; this.hasImageError = true;
}, },
onStoryLoadError() {
this.hasStoryError = true;
},
openContextMenu(e) { openContextMenu(e) {
const shouldSkipContextMenu = const shouldSkipContextMenu =
e.target?.classList.contains('skip-context-menu') || e.target?.classList.contains('skip-context-menu') ||
@@ -672,7 +695,6 @@ li.right {
blockquote { blockquote {
border-left: var(--space-micro) solid var(--s-75); border-left: var(--space-micro) solid var(--s-75);
color: var(--s-800); color: var(--s-800);
padding: var(--space-smaller) var(--space-small);
margin: var(--space-smaller) 0; margin: var(--space-smaller) 0;
padding: var(--space-small) var(--space-small) 0 var(--space-normal); padding: var(--space-small) var(--space-small) 0 var(--space-normal);
} }
@@ -704,4 +726,11 @@ li.right {
} }
} }
} }
.story-reply-quote {
border-left: var(--space-micro) solid var(--s-75);
color: var(--s-600);
margin: var(--space-small) var(--space-normal) 0;
padding: var(--space-small) var(--space-small) 0 var(--space-small);
}
</style> </style>

View File

@@ -195,7 +195,7 @@ export default {
return ''; return '';
} }
const { storySender, storyId } = this; const { storySender, storyId } = this;
return `https://www.instagram.com/stories/${storySender}/${storyId}`; return `https://www.instagram.com/stories/direct/${storySender}_${storyId}`;
}, },
showStatusIndicators() { showStatusIndicators() {
if ((this.isOutgoing || this.isTemplate) && !this.isPrivate) { if ((this.isOutgoing || this.isTemplate) && !this.isPrivate) {

View File

@@ -37,6 +37,7 @@
"UNKNOWN_FILE_TYPE": "Unknown File", "UNKNOWN_FILE_TYPE": "Unknown File",
"SAVE_CONTACT": "Save", "SAVE_CONTACT": "Save",
"UPLOADING_ATTACHMENTS": "Uploading attachments...", "UPLOADING_ATTACHMENTS": "Uploading attachments...",
"REPLIED_TO_STORY": "Replied to your story",
"SUCCESS_DELETE_MESSAGE": "Message deleted successfully", "SUCCESS_DELETE_MESSAGE": "Message deleted successfully",
"FAIL_DELETE_MESSSAGE": "Couldn't delete message! Try again", "FAIL_DELETE_MESSSAGE": "Couldn't delete message! Try again",
"NO_RESPONSE": "No response", "NO_RESPONSE": "No response",

View File

@@ -198,6 +198,17 @@ class Message < ApplicationRecord
outgoing? && human_response? && not_created_by_automation? && !private? outgoing? && human_response? && not_created_by_automation? && !private?
end end
def save_story_info(story_info)
self.content_attributes = content_attributes.merge(
{
story_id: story_info['id'],
story_sender: inbox.channel.instagram_id,
story_url: story_info['url']
}
)
save!
end
private private
def ensure_content_type def ensure_content_type

View File

@@ -13,6 +13,7 @@ describe ::Messages::Instagram::MessageBuilder do
let!(:instagram_inbox) { create(:inbox, channel: instagram_channel, account: account, greeting_enabled: false) } let!(:instagram_inbox) { create(:inbox, channel: instagram_channel, account: account, greeting_enabled: false) }
let!(:dm_params) { build(:instagram_message_create_event).with_indifferent_access } let!(:dm_params) { build(:instagram_message_create_event).with_indifferent_access }
let!(:story_mention_params) { build(:instagram_story_mention_event).with_indifferent_access } let!(:story_mention_params) { build(:instagram_story_mention_event).with_indifferent_access }
let!(:instagram_story_reply_event) { build(:instagram_story_reply_event).with_indifferent_access }
let(:fb_object) { double } let(:fb_object) { double }
let(:contact) { create(:contact, id: 'Sender-id-1', name: 'Jane Dae') } let(:contact) { create(:contact, id: 'Sender-id-1', name: 'Jane Dae') }
let(:contact_inbox) { create(:contact_inbox, contact_id: contact.id, inbox_id: instagram_inbox.id, source_id: 'Sender-id-1') } let(:contact_inbox) { create(:contact_inbox, contact_id: contact.id, inbox_id: instagram_inbox.id, source_id: 'Sender-id-1') }
@@ -44,6 +45,29 @@ describe ::Messages::Instagram::MessageBuilder do
expect(message.content).to eq('This is the first message from the customer') expect(message.content).to eq('This is the first message from the customer')
end end
it 'creates message with for reply with story id' do
allow(Koala::Facebook::API).to receive(:new).and_return(fb_object)
allow(fb_object).to receive(:get_object).and_return(
{
name: 'Jane',
id: 'Sender-id-1',
account_id: instagram_inbox.account_id,
profile_pic: 'https://chatwoot-assets.local/sample.png'
}.with_indifferent_access
)
messaging = instagram_story_reply_event[:entry][0]['messaging'][0]
contact_inbox
described_class.new(messaging, instagram_inbox).perform
message = instagram_channel.inbox.messages.first
expect(message.content).to eq('This is the story reply')
expect(message.content_attributes[:story_sender]).to eq(instagram_inbox.channel.instagram_id)
expect(message.content_attributes[:story_id]).to eq('chatwoot-app-user-id-1')
expect(message.content_attributes[:story_url]).to eq('https://chatwoot-assets.local/sample.png')
end
it 'raises exception on deleted story' do it 'raises exception on deleted story' do
allow(Koala::Facebook::API).to receive(:new).and_return(fb_object) allow(Koala::Facebook::API).to receive(:new).and_return(fb_object)
allow(fb_object).to receive(:get_object).and_raise(Koala::Facebook::ClientError.new( allow(fb_object).to receive(:get_object).and_raise(Koala::Facebook::ClientError.new(

View File

@@ -26,6 +26,39 @@ FactoryBot.define do
initialize_with { attributes } initialize_with { attributes }
end end
factory :instagram_story_reply_event, class: Hash do
entry do
[
{
'id': 'instagram-message-id-123',
'time': '2021-09-08T06:34:04+0000',
'messaging': [
{
'sender': {
'id': 'Sender-id-1'
},
'recipient': {
'id': 'chatwoot-app-user-id-1'
},
'timestamp': '2021-09-08T06:34:04+0000',
'message': {
'mid': 'message-id-1',
'text': 'This is the story reply',
'reply_to': {
'story': {
'id': 'chatwoot-app-user-id-1',
'url': 'https://chatwoot-assets.local/sample.png'
}
}
}
}
]
}
]
end
initialize_with { attributes }
end
factory :instagram_test_text_event, class: Hash do factory :instagram_test_text_event, class: Hash do
entry do entry do
[ [