fix(line): Use non-expiring URLs for image and video messages (#13949)
Images and videos sent from Chatwoot to LINE inboxes fail to display on the LINE mobile app — users see expired markers, broken thumbnails, or missing images. This happens because LINE mobile lazy-loads images rather than downloading them immediately, and the ActiveStorage signed URLs expire after 5 minutes. Closes https://linear.app/chatwoot/issue/CW-6696/line-messaging-with-image-or-video-may-not-show-when-client-inactive ## How to reproduce 1. Create a LINE inbox and start a chat from the LINE mobile app 2. Close the LINE mobile app 3. Send an image from Chatwoot to that chat 4. Wait 7-8 minutes (past the 5-minute URL expiration) 5. Open the LINE mobile app — the image is broken/expired ## What changed - **`originalContentUrl`**: switched from `download_url` (signed, 5-min expiry) to `file_url` (permanent redirect-based URL) - **`previewImageUrl`**: switched to `thumb_url` (250px resized thumbnail meeting LINE's 1MB/240x240 recommendation), with fallback to `file_url` for non-image attachments like video 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Sojan Jose <sojan@pepalo.com>
This commit is contained in:
@@ -44,10 +44,15 @@ class Line::SendOnLineService < Base::SendOnChannelService
|
||||
# Support only image and video for now, https://developers.line.biz/en/reference/messaging-api/#image-message
|
||||
next unless attachment.file_type == 'image' || attachment.file_type == 'video'
|
||||
|
||||
# Use file_url (permanent redirect-based URL) instead of download_url (signed URL that expires in 5 minutes).
|
||||
# LINE mobile app lazy-loads images and may fetch them well after the message is sent.
|
||||
original_url = attachment.file_url
|
||||
preview_url = attachment.thumb_url.presence || original_url
|
||||
|
||||
{
|
||||
type: attachment.file_type,
|
||||
originalContentUrl: attachment.download_url,
|
||||
previewImageUrl: attachment.download_url
|
||||
originalContentUrl: original_url,
|
||||
previewImageUrl: preview_url
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -161,7 +161,9 @@ describe Line::SendOnLineService do
|
||||
it 'sends the message with text and attachments' do
|
||||
attachment = message.attachments.new(account_id: message.account_id, file_type: :image)
|
||||
attachment.file.attach(io: Rails.root.join('spec/assets/avatar.png').open, filename: 'avatar.png', content_type: 'image/png')
|
||||
expected_url_regex = %r{rails/active_storage/disk/[a-zA-Z0-9=_\-+]+/avatar\.png}
|
||||
attachment.save!
|
||||
expected_original_url_regex = %r{rails/active_storage/blobs/redirect/[a-zA-Z0-9=_\-+]+/avatar\.png}
|
||||
expected_preview_url_regex = %r{rails/active_storage/representations/redirect/[a-zA-Z0-9=_\-+]+/[a-zA-Z0-9=_\-+]+/avatar\.png}
|
||||
|
||||
expect(line_client).to receive(:push_message).with(
|
||||
message.conversation.contact_inbox.source_id,
|
||||
@@ -169,8 +171,8 @@ describe Line::SendOnLineService do
|
||||
{ type: 'text', text: message.content },
|
||||
{
|
||||
type: 'image',
|
||||
originalContentUrl: match(expected_url_regex),
|
||||
previewImageUrl: match(expected_url_regex)
|
||||
originalContentUrl: match(expected_original_url_regex),
|
||||
previewImageUrl: match(expected_preview_url_regex)
|
||||
}
|
||||
]
|
||||
)
|
||||
@@ -181,16 +183,18 @@ describe Line::SendOnLineService do
|
||||
it 'sends the message with attachments only' do
|
||||
attachment = message.attachments.new(account_id: message.account_id, file_type: :image)
|
||||
attachment.file.attach(io: Rails.root.join('spec/assets/avatar.png').open, filename: 'avatar.png', content_type: 'image/png')
|
||||
attachment.save!
|
||||
message.update!(content: nil)
|
||||
expected_url_regex = %r{rails/active_storage/disk/[a-zA-Z0-9=_\-+]+/avatar\.png}
|
||||
expected_original_url_regex = %r{rails/active_storage/blobs/redirect/[a-zA-Z0-9=_\-+]+/avatar\.png}
|
||||
expected_preview_url_regex = %r{rails/active_storage/representations/redirect/[a-zA-Z0-9=_\-+]+/[a-zA-Z0-9=_\-+]+/avatar\.png}
|
||||
|
||||
expect(line_client).to receive(:push_message).with(
|
||||
message.conversation.contact_inbox.source_id,
|
||||
[
|
||||
{
|
||||
type: 'image',
|
||||
originalContentUrl: match(expected_url_regex),
|
||||
previewImageUrl: match(expected_url_regex)
|
||||
originalContentUrl: match(expected_original_url_regex),
|
||||
previewImageUrl: match(expected_preview_url_regex)
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user