fix: preserve original filenames for Telegram inbound attachments (#15071)

## Description

Telegram inbound attachments were stored under a generic, renamed
filename (e.g. `file_5.pdf`) instead of the name the sender actually
uploaded (e.g. `Quarterly-Report-2025.pdf`).

**Root cause:** In `Telegram::IncomingMessageService#attach_files`, the
attachment filename was taken from the `Down`-downloaded file's
`original_filename`, which `Down` derives from the Telegram file-server
download URL. That URL is built from Telegram's `getFile` response,
whose `file_path` is Telegram's *internal* storage path — not the
sender's chosen name. The real name is present in the webhook payload as
`file_name` on the `document` / `audio` / `video` object, but it was
never read.

Because `Attachment#set_extension` derives the stored `extension` from
the filename, this also corrupted the recorded extension for documents
whose Telegram path lacked a proper one.

**Fix:** Prefer the payload's `file_name`, falling back to the
downloaded name when it's absent (photos, stickers, voice notes — which
Telegram sends without a `file_name`). This mirrors how the Line channel
(`message['fileName']`) and WhatsApp Cloud channel already handle
inbound attachment filenames.

```ruby
filename: file[:file_name].presence || attachment_file.original_filename,
```

Fixes #15070

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## How Has This Been Tested?

Added/updated specs in
`spec/services/telegram/incoming_message_service_spec.rb`:

- Extended the existing document-message example to assert the stored
attachment retains the original payload filename (`Screenshot 2021-09-27
at 2.01.14 PM.png`) rather than Telegram's internal download name.
- Added a fallback example (a `photo` payload, which carries no
`file_name`) asserting the attachment is still created and the filename
falls back to the downloaded name — guarding the `.presence || …` branch
and confirming no regression for media types without a `file_name`.

> Note: my local machine does not have the Ruby/Redis toolchain to run
the suite, so I have not run RSpec/RuboCop locally — I'm relying on CI
to validate. Suggested command for reviewers: `bundle exec rspec
spec/services/telegram/incoming_message_service_spec.rb`.

## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [x] I have added tests that prove my fix is effective
- [ ] New and existing unit tests pass locally with my changes (unable
to run locally — see note above; relying on CI)
This commit is contained in:
Afiq
2026-08-04 10:29:43 +08:00
committed by GitHub
parent 3633dd44fb
commit e3ce2772fe
2 changed files with 27 additions and 5 deletions

View File

@@ -299,7 +299,29 @@ describe Telegram::IncomingMessageService do
described_class.new(inbox: telegram_channel.inbox, params: params).perform
expect(telegram_channel.inbox.conversations.count).not_to eq(0)
expect(Contact.all.first.name).to eq('Sojan Jose')
expect(telegram_channel.inbox.messages.first.attachments.first.file_type).to eq('file')
attachment = telegram_channel.inbox.messages.first.attachments.first
expect(attachment.file_type).to eq('file')
# Retain the original filename from the payload instead of Telegram's internal download name
expect(attachment.file.filename.to_s).to eq('Screenshot 2021-09-27 at 2.01.14 PM.png')
end
end
context 'when attachment params have no file_name' do
it 'falls back to the downloaded file name' do
allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-assets.local/sample.png')
params = {
'update_id' => 2_342_342_343_242,
'message' => {
'photo' => [{
'file_id' => 'AgACAgUAAxkBAAODYV3aGZlD6vhzKsE2WNmblsr6zKwAAi-tMRvCoeBWNQ1ENVBzJdwBAAMCAANzAAMhBA',
'file_unique_id' => 'AQADL60xG8Kh4FZ4', 'file_size' => 1883, 'width' => 90, 'height' => 67
}]
}.merge(message_params)
}.with_indifferent_access
described_class.new(inbox: telegram_channel.inbox, params: params).perform
attachment = telegram_channel.inbox.messages.first.attachments.first
expect(attachment.file_type).to eq('image')
expect(attachment.file.filename.to_s).to eq('sample.png')
end
end