fix: Populate extension and include content_type in attachment webhook payload (#13945)

Attachment webhook event payloads (`message_created`) were missing the
file extension and content type. The `extension` column existed but was
never populated, and `content_type` was not included in the payload at
all.

## What changed

- Added `before_save :set_extension` callback to extract file extension
from the filename when saving an attachment.
- Added `content_type` (from ActiveStorage) to the `file_metadata` used
in `push_event_data`.

### Before
```json
{
  "extension": null,
  "data_url": "...",
  "file_size": 11960
}
```

### After
```json
{
  "extension": "pdf",
  "content_type": "application/pdf",
  "data_url": "...",
  "file_size": 11960
}
```

## How to reproduce
1. Send a message with a file attachment (e.g., PDF) via any channel
2. Inspect the `message_created` webhook payload
3. Observe `extension` is `null` and `content_type` is missing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Muhsin Keloth
2026-04-02 11:13:11 +04:00
committed by GitHub
parent 8daf6cf6cb
commit d83beb2148
2 changed files with 47 additions and 0 deletions

View File

@@ -187,6 +187,44 @@ RSpec.describe Attachment do
end
end
describe 'set_extension' do
it 'sets extension from filename on save' do
attachment = message.attachments.new(account_id: message.account_id, file_type: :file)
attachment.file.attach(io: StringIO.new('fake pdf'), filename: 'test.pdf', content_type: 'application/pdf')
attachment.save!
expect(attachment.extension).to eq('pdf')
end
it 'does not overwrite extension if already set' do
attachment = message.attachments.new(account_id: message.account_id, file_type: :file, extension: 'doc')
attachment.file.attach(io: StringIO.new('fake pdf'), filename: 'test.pdf', content_type: 'application/pdf')
attachment.save!
expect(attachment.extension).to eq('doc')
end
it 'handles filenames without extension' do
attachment = message.attachments.new(account_id: message.account_id, file_type: :file)
attachment.file.attach(io: StringIO.new('fake data'), filename: 'README', content_type: 'text/plain')
attachment.save!
expect(attachment.extension).to be_nil
end
end
describe 'push_event_data includes extension and content_type' do
it 'returns extension and content_type for file attachments' do
attachment = message.attachments.new(account_id: message.account_id, file_type: :file)
attachment.file.attach(io: StringIO.new('fake pdf'), filename: 'test.pdf', content_type: 'application/pdf')
attachment.save!
event_data = attachment.push_event_data
expect(event_data[:extension]).to eq('pdf')
expect(event_data[:content_type]).to eq('application/pdf')
end
end
describe 'file size validation' do
let(:attachment) { message.attachments.new(account_id: message.account_id, file_type: :image) }