feat: Add support for shared post and story attachment types in Instagram messages (#12997)

When users share Instagram posts or stories via DM, Instagram sends
webhooks with type `ig_post` and `ig_story` attachments. The system was
failing on these types because they weren't defined in the file_types.
This PR fixes the issue by handling all shared types and rendering them
on the front end.

**Shared post**

<img width="2154" height="1828" alt="CleanShot 2025-12-03 at 16 29
14@2x"
src="https://github.com/user-attachments/assets/7e731171-4904-43a6-abeb-b1db2c262742"
/>

**Shared status**
<img width="1702" height="1676" alt="CleanShot 2025-12-03 at 16 10
25@2x"
src="https://github.com/user-attachments/assets/6a151233-ce47-429d-b7c2-061514b20e05"
/>


Fixes
https://linear.app/chatwoot/issue/CW-5441/argumenterror-ig-story-is-not-a-valid-file-type-argumenterror
This commit is contained in:
Muhsin Keloth
2025-12-04 05:20:47 +05:30
committed by GitHub
parent e6a7e836a0
commit 5c3b85334b
7 changed files with 201 additions and 6 deletions

View File

@@ -9,6 +9,8 @@ class Messages::Messenger::MessageBuilder
attachment_obj.save!
attach_file(attachment_obj, attachment_params(attachment)[:remote_file_url]) if attachment_params(attachment)[:remote_file_url]
fetch_story_link(attachment_obj) if attachment_obj.file_type == 'story_mention'
fetch_ig_story_link(attachment_obj) if attachment_obj.file_type == 'ig_story'
fetch_ig_post_link(attachment_obj) if attachment_obj.file_type == 'ig_post'
update_attachment_file_type(attachment_obj)
end
@@ -27,7 +29,7 @@ class Messages::Messenger::MessageBuilder
file_type = attachment['type'].to_sym
params = { file_type: file_type, account_id: @message.account_id }
if [:image, :file, :audio, :video, :share, :story_mention, :ig_reel, :ig_post].include? file_type
if [:image, :file, :audio, :video, :share, :story_mention, :ig_reel, :ig_post, :ig_story].include? file_type
params.merge!(file_type_params(attachment))
elsif file_type == :location
params.merge!(location_params(attachment))
@@ -39,9 +41,17 @@ class Messages::Messenger::MessageBuilder
end
def file_type_params(attachment)
# Handle different URL field names for different attachment types
url = case attachment['type'].to_sym
when :ig_story
attachment['payload']['story_media_url']
else
attachment['payload']['url']
end
{
external_url: attachment['payload']['url'],
remote_file_url: attachment['payload']['url']
external_url: url,
remote_file_url: url
}
end
@@ -68,6 +78,21 @@ class Messages::Messenger::MessageBuilder
message.save!
end
def fetch_ig_story_link(attachment)
message = attachment.message
# For ig_story, we don't have the same API call as story_mention, so we'll set it up similarly but with generic content
message.content_attributes[:image_type] = 'ig_story'
message.content = I18n.t('conversations.messages.instagram_shared_story_content')
message.save!
end
def fetch_ig_post_link(attachment)
message = attachment.message
message.content_attributes[:image_type] = 'ig_post'
message.content = I18n.t('conversations.messages.instagram_shared_post_content')
message.save!
end
# This is a placeholder method to be overridden by child classes
def get_story_object_from_source_id(_source_id)
{}

View File

@@ -299,7 +299,12 @@ const componentToRender = computed(() => {
return DyteBubble;
}
if (props.contentAttributes.imageType === 'story_mention') {
const instagramSharedTypes = [
ATTACHMENT_TYPES.STORY_MENTION,
ATTACHMENT_TYPES.IG_STORY,
ATTACHMENT_TYPES.IG_POST,
];
if (instagramSharedTypes.includes(props.contentAttributes.imageType)) {
return InstagramStoryBubble;
}
@@ -476,7 +481,7 @@ provideMessageContext({
<div
v-if="shouldRenderMessage"
:id="`message${props.id}`"
class="flex w-full message-bubble-container mb-2"
class="flex mb-2 w-full message-bubble-container"
:data-message-id="props.id"
:class="[
flexOrientationClass,

View File

@@ -49,6 +49,8 @@ export const ATTACHMENT_TYPES = {
STORY_MENTION: 'story_mention',
CONTACT: 'contact',
IG_REEL: 'ig_reel',
IG_POST: 'ig_post',
IG_STORY: 'ig_story',
};
export const CONTENT_TYPES = {

View File

@@ -40,7 +40,7 @@ class Attachment < ApplicationRecord
validate :acceptable_file
validates :external_url, length: { maximum: Limits::URL_LENGTH_LIMIT }
enum file_type: { :image => 0, :audio => 1, :video => 2, :file => 3, :location => 4, :fallback => 5, :share => 6, :story_mention => 7,
:contact => 8, :ig_reel => 9, :ig_post => 10 }
:contact => 8, :ig_reel => 9, :ig_post => 10, :ig_story => 11 }
def push_event_data
return unless file_type