diff --git a/app/services/line/incoming_message_service.rb b/app/services/line/incoming_message_service.rb index 80e10c2e1..e3c85ef99 100644 --- a/app/services/line/incoming_message_service.rb +++ b/app/services/line/incoming_message_service.rb @@ -14,20 +14,63 @@ class Line::IncomingMessageService set_contact set_conversation - # TODO: iterate over the events and handle the attachments in future - # https://github.com/line/line-bot-sdk-ruby#synopsis + parse_events + end + + private + + def parse_events + params[:events].each do |event| + next unless message_created? event + + attach_files event['message'] + end + end + + def message_created?(event) + return unless event_type_message?(event) + @message = @conversation.messages.create( - content: params[:events].first['message']['text'], + content: event['message']['text'], account_id: @inbox.account_id, inbox_id: @inbox.id, message_type: :incoming, sender: @contact, - source_id: (params[:events].first['message']['id']).to_s + source_id: event['message']['id'].to_s + ) + @message + end + + def attach_files(message) + return unless message_type_non_text?(message['type']) + + response = inbox.channel.client.get_message_content(message['id']) + + file_name = "media-#{message['id']}.#{response.content_type.split('/')[1]}" + temp_file = Tempfile.new(file_name) + temp_file.binmode + temp_file << response.body + temp_file.rewind + + @message.attachments.new( + account_id: @message.account_id, + file_type: file_content_type(response), + file: { + io: temp_file, + filename: file_name, + content_type: response.content_type + } ) @message.save! end - private + def event_type_message?(event) + event['type'] == 'message' + end + + def message_type_non_text?(type) + [Line::Bot::Event::MessageType::Video, Line::Bot::Event::MessageType::Audio, Line::Bot::Event::MessageType::Image].include?(type) + end def account @account ||= inbox.account @@ -70,4 +113,8 @@ class Line::IncomingMessageService avatar_url: line_contact_info['pictureUrl'] } end + + def file_content_type(file_content) + file_type(file_content.content_type) + end end diff --git a/spec/assets/sample.mp4 b/spec/assets/sample.mp4 new file mode 100644 index 000000000..a203d0cdf Binary files /dev/null and b/spec/assets/sample.mp4 differ diff --git a/spec/services/line/incoming_message_service_spec.rb b/spec/services/line/incoming_message_service_spec.rb index 06ff3ade3..4b03fc8f2 100644 --- a/spec/services/line/incoming_message_service_spec.rb +++ b/spec/services/line/incoming_message_service_spec.rb @@ -35,6 +35,76 @@ describe Line::IncomingMessageService do }.with_indifferent_access end + let(:image_params) do + { + 'destination': '2342234234', + 'events': [ + { + 'replyToken': '0f3779fba3b349968c5d07db31eab56f', + 'type': 'message', + 'mode': 'active', + 'timestamp': 1_462_629_479_859, + 'source': { + 'type': 'user', + 'userId': 'U4af4980629' + }, + 'message': { + 'type': 'image', + 'id': '354718', + 'contentProvider': { + 'type': 'line' + } + } + }, + { + 'replyToken': '8cf9239d56244f4197887e939187e19e', + 'type': 'follow', + 'mode': 'active', + 'timestamp': 1_462_629_479_859, + 'source': { + 'type': 'user', + 'userId': 'U4af4980629' + } + } + ] + }.with_indifferent_access + end + + let(:video_params) do + { + 'destination': '2342234234', + 'events': [ + { + 'replyToken': '0f3779fba3b349968c5d07db31eab56f', + 'type': 'message', + 'mode': 'active', + 'timestamp': 1_462_629_479_859, + 'source': { + 'type': 'user', + 'userId': 'U4af4980629' + }, + 'message': { + 'type': 'video', + 'id': '354718', + 'contentProvider': { + 'type': 'line' + } + } + }, + { + 'replyToken': '8cf9239d56244f4197887e939187e19e', + 'type': 'follow', + 'mode': 'active', + 'timestamp': 1_462_629_479_859, + 'source': { + 'type': 'user', + 'userId': 'U4af4980629' + } + } + ] + }.with_indifferent_access + end + describe '#perform' do context 'when valid text message params' do it 'creates appropriate conversations, message and contacts' do @@ -55,5 +125,63 @@ describe Line::IncomingMessageService do expect(line_channel.inbox.messages.first.content).to eq('Hello, world') end end + + context 'when valid image 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/avatar.png'), 'image/png') + allow(line_bot).to receive(:get_message_content).and_return( + OpenStruct.new({ + body: Base64.encode64(file.read), + content_type: 'image/png' + }) + ) + 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: image_params).perform + expect(line_channel.inbox.conversations).not_to eq(0) + expect(Contact.all.first.name).to eq('LINE Test') + expect(line_channel.inbox.messages.first.content).to eq(nil) + expect(line_channel.inbox.messages.first.attachments.first.file_type).to eq('image') + expect(line_channel.inbox.messages.first.attachments.first.file.blob.filename.to_s).to eq('media-354718.png') + end + end + + context 'when valid video 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/sample.mp4'), 'video/mp4') + allow(line_bot).to receive(:get_message_content).and_return( + OpenStruct.new({ + body: Base64.encode64(file.read), + content_type: 'video/mp4' + }) + ) + 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: video_params).perform + expect(line_channel.inbox.conversations).not_to eq(0) + expect(Contact.all.first.name).to eq('LINE Test') + expect(line_channel.inbox.messages.first.content).to eq(nil) + expect(line_channel.inbox.messages.first.attachments.first.file_type).to eq('video') + expect(line_channel.inbox.messages.first.attachments.first.file.blob.filename.to_s).to eq('media-354718.mp4') + end + end end end