From b5deecc9f9d130139224c696c12b65f75d479c2d Mon Sep 17 00:00:00 2001 From: mix5003 Date: Mon, 22 Sep 2025 16:36:28 +0700 Subject: [PATCH] feat: Accept file attachment in line channel (#12321) # Pull Request Template ## Description This pull request allow LINE to receive files. ## Type of change Please delete options that are not relevant. - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality not to work as expected) - [ ] This change requires a documentation update ## How Has This Been Tested? add testcase. and test manually by myself. in case you want to test in android, use native share method to share files to LINE. you can share more file types to LINE (native line share only send image,video and audio). ## Checklist: - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [ ] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules --------- Co-authored-by: mix5003 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Muhsin Keloth --- app/services/line/incoming_message_service.rb | 18 +++++- .../line/incoming_message_service_spec.rb | 64 +++++++++++++++++++ 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/app/services/line/incoming_message_service.rb b/app/services/line/incoming_message_service.rb index 4761292d0..0d2f78c7a 100644 --- a/app/services/line/incoming_message_service.rb +++ b/app/services/line/incoming_message_service.rb @@ -76,7 +76,8 @@ class Line::IncomingMessageService response = inbox.channel.client.get_message_content(message['id']) - file_name = "media-#{message['id']}.#{response.content_type.split('/')[1]}" + extension = get_file_extension(response) + file_name = message['fileName'] || "media-#{message['id']}.#{extension}" temp_file = Tempfile.new(file_name) temp_file.binmode temp_file << response.body @@ -93,12 +94,25 @@ class Line::IncomingMessageService ) end + def get_file_extension(response) + if response.content_type&.include?('/') + response.content_type.split('/')[1] + else + 'bin' + end + end + def event_type_message?(event) event['type'] == 'message' || event['type'] == 'sticker' end def message_type_non_text?(type) - [Line::Bot::Event::MessageType::Video, Line::Bot::Event::MessageType::Audio, Line::Bot::Event::MessageType::Image].include?(type) + [ + Line::Bot::Event::MessageType::Video, + Line::Bot::Event::MessageType::Audio, + Line::Bot::Event::MessageType::Image, + Line::Bot::Event::MessageType::File + ].include?(type) end def account diff --git a/spec/services/line/incoming_message_service_spec.rb b/spec/services/line/incoming_message_service_spec.rb index 3bcdf8b04..9160efff2 100644 --- a/spec/services/line/incoming_message_service_spec.rb +++ b/spec/services/line/incoming_message_service_spec.rb @@ -105,6 +105,40 @@ describe Line::IncomingMessageService do }.with_indifferent_access end + let(:file_params) do + { + 'destination': '2342234234', + 'events': [ + { + 'replyToken': '0f3779fba3b349968c5d07db31eab56f', + 'type': 'message', + 'mode': 'active', + 'timestamp': 1_462_629_479_859, + 'source': { + 'type': 'user', + 'userId': 'U4af4980629' + }, + 'message': { + 'type': 'file', + 'id': '354718', + 'fileName': 'contacts.csv', + 'fileSize': 2978 + } + }, + { + 'replyToken': '8cf9239d56244f4197887e939187e19e', + 'type': 'follow', + 'mode': 'active', + 'timestamp': 1_462_629_479_859, + 'source': { + 'type': 'user', + 'userId': 'U4af4980629' + } + } + ] + }.with_indifferent_access + end + let(:sticker_params) do { 'destination': '2342234234', @@ -241,5 +275,35 @@ describe Line::IncomingMessageService do expect(line_channel.inbox.messages.first.attachments.first.file.blob.filename.to_s).to eq('media-354718.mp4') end end + + context 'when valid file message params' do + it 'creates appropriate conversations, message and contacts' do + line_bot = double + line_user_profile = double + allow(Line::Bot::Client).to receive(:new).and_return(line_bot) + allow(line_bot).to receive(:get_profile).and_return(line_user_profile) + file = fixture_file_upload(Rails.root.join('spec/assets/contacts.csv'), 'text/csv') + allow(line_bot).to receive(:get_message_content).and_return( + OpenStruct.new({ + body: Base64.encode64(file.read), + content_type: 'text/csv' + }) + ) + allow(line_user_profile).to receive(:body).and_return( + { + 'displayName': 'LINE Test', + 'userId': 'U4af4980629', + 'pictureUrl': 'https://test.com' + }.to_json + ) + described_class.new(inbox: line_channel.inbox, params: file_params).perform + expect(line_channel.inbox.conversations).not_to eq(0) + expect(Contact.all.first.name).to eq('LINE Test') + expect(Contact.all.first.additional_attributes['social_line_user_id']).to eq('U4af4980629') + expect(line_channel.inbox.messages.first.content).to be_nil + expect(line_channel.inbox.messages.first.attachments.first.file_type).to eq('file') + expect(line_channel.inbox.messages.first.attachments.first.file.blob.filename.to_s).to eq('contacts.csv') + end + end end end