diff --git a/app/helpers/file_type_helper.rb b/app/helpers/file_type_helper.rb index 503c7f25b..9e822b6c4 100644 --- a/app/helpers/file_type_helper.rb +++ b/app/helpers/file_type_helper.rb @@ -3,7 +3,7 @@ module FileTypeHelper def file_type(content_type) return :image if image_file?(content_type) return :video if video_file?(content_type) - return :audio if content_type.include?('audio/') + return :audio if content_type&.include?('audio/') :file end diff --git a/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue b/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue index 7441d9a73..d521a1cde 100644 --- a/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue +++ b/app/javascript/dashboard/components/widgets/conversation/ReplyBox.vue @@ -293,7 +293,7 @@ export default { if (this.isAWhatsappChannel) { return MESSAGE_MAX_LENGTH.TWILIO_WHATSAPP; } - if (this.isATwilioSMSChannel) { + if (this.isASmsInbox) { return MESSAGE_MAX_LENGTH.TWILIO_SMS; } if (this.isATwitterInbox) { @@ -310,7 +310,7 @@ export default { this.isAWhatsappChannel || this.isAPIInbox || this.isAnEmailChannel || - this.isATwilioSMSChannel || + this.isASmsInbox || this.isATelegramChannel ); }, diff --git a/app/javascript/shared/mixins/inboxMixin.js b/app/javascript/shared/mixins/inboxMixin.js index aebbeebc1..f0417ae93 100644 --- a/app/javascript/shared/mixins/inboxMixin.js +++ b/app/javascript/shared/mixins/inboxMixin.js @@ -44,6 +44,9 @@ export default { const { medium: medium = '' } = this.inbox; return this.isATwilioChannel && medium === 'sms'; }, + isASmsInbox() { + return this.channelType === INBOX_TYPES.SMS || this.isATwilioSMSChannel; + }, isATwilioWhatsappChannel() { const { medium: medium = '' } = this.inbox; return this.isATwilioChannel && medium === 'whatsapp'; diff --git a/app/javascript/shared/mixins/specs/inboxMixin.spec.js b/app/javascript/shared/mixins/specs/inboxMixin.spec.js index f128a44d8..dc7cc38cc 100644 --- a/app/javascript/shared/mixins/specs/inboxMixin.spec.js +++ b/app/javascript/shared/mixins/specs/inboxMixin.spec.js @@ -62,6 +62,18 @@ describe('inboxMixin', () => { expect(wrapper.vm.isAWebWidgetInbox).toBe(true); }); + it('isASmsInbox returns true if channel type is sms', () => { + const Component = { + render() {}, + mixins: [inboxMixin], + data() { + return { inbox: { channel_type: 'Channel::Sms' } }; + }, + }; + const wrapper = shallowMount(Component); + expect(wrapper.vm.isASmsInbox).toBe(true); + }); + it('isATwilioChannel returns true if channel type is Twilio', () => { const Component = { render() {}, @@ -94,6 +106,7 @@ describe('inboxMixin', () => { const wrapper = shallowMount(Component); expect(wrapper.vm.isATwilioChannel).toBe(true); expect(wrapper.vm.isATwilioSMSChannel).toBe(true); + expect(wrapper.vm.isASmsInbox).toBe(true); }); it('isATwilioWhatsappChannel returns true if channel type is Twilio and medium is whatsapp', () => { diff --git a/app/models/attachment.rb b/app/models/attachment.rb index cea0721b8..6def5bbdb 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -48,6 +48,10 @@ class Attachment < ApplicationRecord file.attached? ? url_for(file) : '' end + def download_url + file.attached? ? rails_storage_proxy_url(file) : '' + end + def thumb_url if file.attached? && file.representable? url_for(file.representation(resize: '250x250')) diff --git a/app/models/channel/sms.rb b/app/models/channel/sms.rb index ff7dd2433..e6f993e59 100644 --- a/app/models/channel/sms.rb +++ b/app/models/channel/sms.rb @@ -33,35 +33,38 @@ class Channel::Sms < ApplicationRecord 'https://messaging.bandwidth.com/api/v2' end - # Extract later into provider Service - def send_message(phone_number, message) - if message.attachments.present? - send_attachment_message(phone_number, message) - else - send_text_message(phone_number, message.content) - end + def send_message(contact_number, message) + body = message_body(contact_number, message.content) + body['media'] = message.attachments.map(&:download_url) if message.attachments.present? + + send_to_bandwidth(body) end - def send_text_message(contact_number, message) - response = HTTParty.post( - "#{api_base_path}/users/#{provider_config['account_id']}/messages", - basic_auth: bandwidth_auth, - headers: { 'Content-Type' => 'application/json' }, - body: { - 'to' => contact_number, - 'from' => phone_number, - 'text' => message, - 'applicationId' => provider_config['application_id'] - }.to_json - ) - - response.success? ? response.parsed_response['id'] : nil + def send_text_message(contact_number, message_content) + body = message_body(contact_number, message_content) + send_to_bandwidth(body) end private - def send_attachment_message(phone_number, message) - # fix me + def message_body(contact_number, message_content) + { + 'to' => contact_number, + 'from' => phone_number, + 'text' => message_content, + 'applicationId' => provider_config['application_id'] + } + end + + def send_to_bandwidth(body) + response = HTTParty.post( + "#{api_base_path}/users/#{provider_config['account_id']}/messages", + basic_auth: bandwidth_auth, + headers: { 'Content-Type' => 'application/json' }, + body: body.to_json + ) + + response.success? ? response.parsed_response['id'] : nil end def bandwidth_auth diff --git a/app/services/sms/incoming_message_service.rb b/app/services/sms/incoming_message_service.rb index 62fda96ac..537f3baf8 100644 --- a/app/services/sms/incoming_message_service.rb +++ b/app/services/sms/incoming_message_service.rb @@ -14,6 +14,8 @@ class Sms::IncomingMessageService sender: @contact, source_id: params[:id] ) + attach_files + @message.save! end private @@ -22,6 +24,10 @@ class Sms::IncomingMessageService @account ||= @inbox.account end + def channel + @channel ||= @inbox.channel + end + def phone_number params[:from] end @@ -63,4 +69,28 @@ class Sms::IncomingMessageService phone_number: phone_number } end + + def attach_files + return if params[:media].blank? + + params[:media].each do |media_url| + # we don't need to process this files since chatwoot doesn't support it + next if media_url.end_with? '.smil' + + attachment_file = Down.download( + media_url, + http_basic_authentication: [channel.provider_config['api_key'], channel.provider_config['api_secret']] + ) + + @message.attachments.new( + account_id: @message.account_id, + file_type: file_type(attachment_file.content_type), + file: { + io: attachment_file, + filename: attachment_file, + content_type: attachment_file.content_type + } + ) + end + end end diff --git a/spec/services/sms/incoming_message_service_spec.rb b/spec/services/sms/incoming_message_service_spec.rb index 1e86d8015..c5f576b4a 100644 --- a/spec/services/sms/incoming_message_service_spec.rb +++ b/spec/services/sms/incoming_message_service_spec.rb @@ -26,6 +26,37 @@ describe Sms::IncomingMessageService do expect(Contact.all.first.name).to eq('+1 423-423-4234') expect(sms_channel.inbox.messages.first.content).to eq('test message') end + + it 'creates attachment messages and ignores .smil files' do + stub_request(:get, 'http://test.com/test.png').to_return(status: 200, body: File.read('spec/assets/sample.png'), headers: {}) + stub_request(:get, 'http://test.com/test2.png').to_return(status: 200, body: File.read('spec/assets/sample.png'), headers: {}) + + params = { + + 'id': '3232420-2323-234324', + 'owner': sms_channel.phone_number, + 'applicationId': '2342349-324234d-32432432', + 'time': '2022-02-02T23:14:05.262Z', + 'segmentCount': 1, + 'direction': 'in', + 'to': [ + sms_channel.phone_number + ], + 'media': [ + 'http://test.com/test.smil', + 'http://test.com/test.png', + 'http://test.com/test2.png' + ], + 'from': '+14234234234', + 'text': 'test message' + + }.with_indifferent_access + described_class.new(inbox: sms_channel.inbox, params: params).perform + expect(sms_channel.inbox.conversations.count).not_to eq(0) + expect(Contact.all.first.name).to eq('+1 423-423-4234') + expect(sms_channel.inbox.messages.first.content).to eq('test message') + expect(sms_channel.inbox.messages.first.attachments.present?).to eq true + end end end end diff --git a/spec/services/sms/send_on_sms_service_spec.rb b/spec/services/sms/send_on_sms_service_spec.rb index 7304fad88..21f9a7855 100644 --- a/spec/services/sms/send_on_sms_service_spec.rb +++ b/spec/services/sms/send_on_sms_service_spec.rb @@ -23,6 +23,29 @@ describe Sms::SendOnSmsService do described_class.new(message: message).perform expect(message.reload.source_id).to eq('123456789') end + + it 'calls channel.send_message with attachments' do + message = build(:message, message_type: :outgoing, content: 'test', + conversation: conversation) + attachment = message.attachments.new(account_id: message.account_id, file_type: :image) + attachment.file.attach(io: File.open(Rails.root.join('spec/assets/avatar.png')), filename: 'avatar.png', content_type: 'image/png') + attachment2 = message.attachments.new(account_id: message.account_id, file_type: :image) + attachment2.file.attach(io: File.open(Rails.root.join('spec/assets/avatar.png')), filename: 'avatar.png', content_type: 'image/png') + message.save! + + allow(HTTParty).to receive(:post).and_return(sms_request) + allow(sms_request).to receive(:success?).and_return(true) + allow(sms_request).to receive(:parsed_response).and_return({ 'id' => '123456789' }) + expect(HTTParty).to receive(:post).with( + 'https://messaging.bandwidth.com/api/v2/users/1/messages', + basic_auth: { username: '1', password: '1' }, + headers: { 'Content-Type' => 'application/json' }, + body: { 'to' => '+123456789', 'from' => sms_channel.phone_number, 'text' => 'test', 'applicationId' => '1', + 'media' => [attachment.download_url, attachment2.download_url] }.to_json + ) + described_class.new(message: message).perform + expect(message.reload.source_id).to eq('123456789') + end end end end