fix: scope external_url override to Instagram DM conversations only (#13982)

Previously, all incoming messages from Facebook channel with
instagram_id had their attachment data_url and thumb_url overridden with
external_url. This caused issues for non-Instagram conversations
originating from Facebook Message where the file URL should be used
instead.

Narrows the override to only apply when the conversation type is
instagram_direct_message, which is the only case where Instagram's CDN
URLs need to be used directly.

Fixes
https://linear.app/chatwoot/issue/CW-6722/videos-are-missing-in-facebook-conversation

---------

Co-authored-by: Muhsin <12408980+muhsin-k@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Pranav
2026-04-02 07:26:23 -07:00
committed by GitHub
parent b9b5a18767
commit 441fe4db11
2 changed files with 86 additions and 6 deletions

View File

@@ -120,7 +120,7 @@ class Attachment < ApplicationRecord
height: file.metadata[:height]
}
metadata[:data_url] = metadata[:thumb_url] = external_url if message.inbox.instagram? && message.incoming?
metadata[:data_url] = metadata[:thumb_url] = external_url if instagram_incoming_message?
metadata
end
@@ -156,6 +156,14 @@ class Attachment < ApplicationRecord
}
end
def instagram_incoming_message?
return false unless message.incoming?
return true if message.inbox.instagram_direct?
message.inbox.instagram? && message.conversation&.additional_attributes&.dig('type') == 'instagram_direct_message'
end
def set_extension
return unless file.attached?
return if extension.present?

View File

@@ -57,11 +57,6 @@ RSpec.describe Attachment do
}.to_json, headers: {})
end
it 'returns external url as data and thumb urls when message is incoming' do
external_url = instagram_message.attachments.first.external_url
expect(instagram_message.attachments.first.push_event_data[:data_url]).to eq external_url
end
it 'returns original attachment url as data url if the message is outgoing' do
message = create(:message, :instagram_story_mention, message_type: :outgoing)
expect(message.attachments.first.push_event_data[:data_url]).not_to eq message.attachments.first.external_url
@@ -155,6 +150,83 @@ RSpec.describe Attachment do
end
end
describe 'push_event_data for instagram direct message attachments' do
let(:account) { create(:account) }
let(:instagram_inbox) do
create(:inbox, account: account,
channel: create(:channel_instagram_fb_page, account: account, instagram_id: 'instagram-dm-test'))
end
context 'when conversation type is instagram_direct_message' do
let(:conversation) do
create(:conversation, account: account, inbox: instagram_inbox,
additional_attributes: { 'type' => 'instagram_direct_message' })
end
let(:instagram_message) { create(:message, account: account, inbox: instagram_inbox, conversation: conversation, message_type: :incoming) }
it 'uses external_url for data_url and thumb_url' do
attachment = instagram_message.attachments.new(account_id: account.id, file_type: :image, external_url: 'https://instagram.com/image.jpg')
attachment.file.attach(io: Rails.root.join('spec/assets/avatar.png').open, filename: 'avatar.png', content_type: 'image/png')
attachment.save!
event_data = attachment.push_event_data
expect(event_data[:data_url]).to eq('https://instagram.com/image.jpg')
expect(event_data[:thumb_url]).to eq('https://instagram.com/image.jpg')
end
end
context 'when conversation type is not instagram_direct_message' do
let(:conversation) do
create(:conversation, account: account, inbox: instagram_inbox,
additional_attributes: { 'type' => 'other_type' })
end
let(:instagram_message) { create(:message, account: account, inbox: instagram_inbox, conversation: conversation, message_type: :incoming) }
it 'uses file_url for data_url instead of external_url' do
attachment = instagram_message.attachments.new(account_id: account.id, file_type: :image, external_url: 'https://instagram.com/image.jpg')
attachment.file.attach(io: Rails.root.join('spec/assets/avatar.png').open, filename: 'avatar.png', content_type: 'image/png')
attachment.save!
event_data = attachment.push_event_data
expect(event_data[:data_url]).not_to eq('https://instagram.com/image.jpg')
end
end
context 'when message is outgoing on instagram DM conversation' do
let(:conversation) do
create(:conversation, account: account, inbox: instagram_inbox,
additional_attributes: { 'type' => 'instagram_direct_message' })
end
let(:outgoing_message) { create(:message, account: account, inbox: instagram_inbox, conversation: conversation, message_type: :outgoing) }
it 'does not override data_url with external_url' do
attachment = outgoing_message.attachments.new(account_id: account.id, file_type: :image, external_url: 'https://instagram.com/image.jpg')
attachment.file.attach(io: Rails.root.join('spec/assets/avatar.png').open, filename: 'avatar.png', content_type: 'image/png')
attachment.save!
event_data = attachment.push_event_data
expect(event_data[:data_url]).not_to eq('https://instagram.com/image.jpg')
end
end
context 'when inbox is Channel::Instagram (direct login)' do
let(:instagram_channel) { create(:channel_instagram, account: account) }
let(:direct_inbox) { instagram_channel.inbox }
let(:conversation) { create(:conversation, account: account, inbox: direct_inbox) }
let(:incoming_message) { create(:message, account: account, inbox: direct_inbox, conversation: conversation, message_type: :incoming) }
it 'uses external_url for data_url and thumb_url' do
attachment = incoming_message.attachments.new(account_id: account.id, file_type: :image, external_url: 'https://instagram.com/image.jpg')
attachment.file.attach(io: Rails.root.join('spec/assets/avatar.png').open, filename: 'avatar.png', content_type: 'image/png')
attachment.save!
event_data = attachment.push_event_data
expect(event_data[:data_url]).to eq('https://instagram.com/image.jpg')
expect(event_data[:thumb_url]).to eq('https://instagram.com/image.jpg')
end
end
end
describe 'push_event_data for ig_reel attachments' do
it 'returns external_url as data_url when no file is attached' do
attachment = message.attachments.create!(