mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-10-30 18:47:51 +00:00 
			
		
		
		
	chore: Handle attachments in Whatsapp Channel (#3299)
send and receive attachments in 360Dialog WhatsApp channels
This commit is contained in:
		
							
								
								
									
										3
									
								
								Gemfile
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								Gemfile
									
									
									
									
									
								
							| @@ -144,6 +144,8 @@ group :test do | |||||||
|   gem 'cypress-on-rails', '~> 1.0' |   gem 'cypress-on-rails', '~> 1.0' | ||||||
|   # fast cleaning of database |   # fast cleaning of database | ||||||
|   gem 'database_cleaner' |   gem 'database_cleaner' | ||||||
|  |   # mock http calls | ||||||
|  |   gem 'webmock' | ||||||
| end | end | ||||||
|  |  | ||||||
| group :development, :test do | group :development, :test do | ||||||
| @@ -171,5 +173,4 @@ group :development, :test do | |||||||
|   gem 'simplecov', '0.17.1', require: false |   gem 'simplecov', '0.17.1', require: false | ||||||
|   gem 'spring' |   gem 'spring' | ||||||
|   gem 'spring-watcher-listen' |   gem 'spring-watcher-listen' | ||||||
|   gem 'webmock' |  | ||||||
| end | end | ||||||
|   | |||||||
| @@ -228,7 +228,7 @@ export default { | |||||||
|       return ( |       return ( | ||||||
|         this.isAWebWidgetInbox || |         this.isAWebWidgetInbox || | ||||||
|         this.isAFacebookInbox || |         this.isAFacebookInbox || | ||||||
|         this.isATwilioWhatsappChannel || |         this.isAWhatsappChannel || | ||||||
|         this.isAPIInbox || |         this.isAPIInbox || | ||||||
|         this.isAnEmailChannel || |         this.isAnEmailChannel || | ||||||
|         this.isATwilioSMSChannel || |         this.isATwilioSMSChannel || | ||||||
|   | |||||||
| @@ -2,7 +2,12 @@ | |||||||
|   <div class="wizard-body small-12 medium-9 columns height-auto"> |   <div class="wizard-body small-12 medium-9 columns height-auto"> | ||||||
|     <page-header |     <page-header | ||||||
|       :header-title="$t('INBOX_MGMT.ADD.AUTH.TITLE')" |       :header-title="$t('INBOX_MGMT.ADD.AUTH.TITLE')" | ||||||
|       :header-content="$t('INBOX_MGMT.ADD.AUTH.DESC')" |       :header-content=" | ||||||
|  |         useInstallationName( | ||||||
|  |           $t('INBOX_MGMT.ADD.AUTH.DESC'), | ||||||
|  |           globalConfig.installationName | ||||||
|  |         ) | ||||||
|  |       " | ||||||
|     /> |     /> | ||||||
|     <div class="row channels"> |     <div class="row channels"> | ||||||
|       <channel-item |       <channel-item | ||||||
| @@ -21,12 +26,14 @@ import ChannelItem from 'dashboard/components/widgets/ChannelItem'; | |||||||
| import router from '../../../index'; | import router from '../../../index'; | ||||||
| import PageHeader from '../SettingsSubPageHeader'; | import PageHeader from '../SettingsSubPageHeader'; | ||||||
| import { mapGetters } from 'vuex'; | import { mapGetters } from 'vuex'; | ||||||
|  | import globalConfigMixin from 'shared/mixins/globalConfigMixin'; | ||||||
|  |  | ||||||
| export default { | export default { | ||||||
|   components: { |   components: { | ||||||
|     ChannelItem, |     ChannelItem, | ||||||
|     PageHeader, |     PageHeader, | ||||||
|   }, |   }, | ||||||
|  |   mixins: [globalConfigMixin], | ||||||
|   data() { |   data() { | ||||||
|     return { |     return { | ||||||
|       enabledFeatures: {}, |       enabledFeatures: {}, | ||||||
|   | |||||||
| @@ -43,7 +43,7 @@ class Channel::Telegram < ApplicationRecord | |||||||
|     response = HTTParty.get("#{telegram_api_url}/getUserProfilePhotos", query: { user_id: user_id }) |     response = HTTParty.get("#{telegram_api_url}/getUserProfilePhotos", query: { user_id: user_id }) | ||||||
|     return nil unless response.success? |     return nil unless response.success? | ||||||
|  |  | ||||||
|     photos = response.parsed_response['result']['photos'] |     photos = response.parsed_response.dig('result', 'photos') | ||||||
|     return if photos.blank? |     return if photos.blank? | ||||||
|  |  | ||||||
|     get_telegram_file_path(photos.first.last['file_id']) |     get_telegram_file_path(photos.first.last['file_id']) | ||||||
|   | |||||||
| @@ -36,15 +36,19 @@ class Channel::Whatsapp < ApplicationRecord | |||||||
|  |  | ||||||
|   # Extract later into provider Service |   # Extract later into provider Service | ||||||
|   def send_message(phone_number, message) |   def send_message(phone_number, message) | ||||||
|     HTTParty.post( |     if message.attachments.present? | ||||||
|       "#{api_base_path}/messages", |       send_attachment_message(phone_number, message) | ||||||
|       headers: { 'D360-API-KEY': provider_config['api_key'], 'Content-Type': 'application/json' }, |     else | ||||||
|       body: { |       send_text_message(phone_number, message) | ||||||
|         to: phone_number, |     end | ||||||
|         text: { body: message }, |   end | ||||||
|         type: 'text' |  | ||||||
|       }.to_json |   def media_url(media_id) | ||||||
|     ) |     "#{api_base_path}/media/#{media_id}" | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   def api_headers | ||||||
|  |     { 'D360-API-KEY' => provider_config['api_key'], 'Content-Type' => 'application/json' } | ||||||
|   end |   end | ||||||
|  |  | ||||||
|   def has_24_hour_messaging_window? |   def has_24_hour_messaging_window? | ||||||
| @@ -53,6 +57,36 @@ class Channel::Whatsapp < ApplicationRecord | |||||||
|  |  | ||||||
|   private |   private | ||||||
|  |  | ||||||
|  |   def send_text_message(phone_number, message) | ||||||
|  |     HTTParty.post( | ||||||
|  |       "#{api_base_path}/messages", | ||||||
|  |       headers: { 'D360-API-KEY': provider_config['api_key'], 'Content-Type': 'application/json' }, | ||||||
|  |       body: { | ||||||
|  |         to: phone_number, | ||||||
|  |         text: { body: message.content }, | ||||||
|  |         type: 'text' | ||||||
|  |       }.to_json | ||||||
|  |     ) | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   def send_attachment_message(phone_number, message) | ||||||
|  |     attachment = message.attachments.first | ||||||
|  |     type = %w[image audio video].include?(attachment.file_type) ? attachment.file_type : 'document' | ||||||
|  |     attachment_url = attachment.file_url | ||||||
|  |     HTTParty.post( | ||||||
|  |       "#{api_base_path}/messages", | ||||||
|  |       headers: { 'D360-API-KEY': provider_config['api_key'], 'Content-Type': 'application/json' }, | ||||||
|  |       body: { | ||||||
|  |         'to' => phone_number, | ||||||
|  |         'type' => type, | ||||||
|  |         type.to_s => { | ||||||
|  |           'link': attachment_url, | ||||||
|  |           'caption': message.content | ||||||
|  |         } | ||||||
|  |       }.to_json | ||||||
|  |     ) | ||||||
|  |   end | ||||||
|  |  | ||||||
|   # Extract later into provider Service |   # Extract later into provider Service | ||||||
|   def validate_provider_config |   def validate_provider_config | ||||||
|     response = HTTParty.post( |     response = HTTParty.post( | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| # Find the various telegram payload samples here: https://core.telegram.org/bots/webhooks#testing-your-bot-with-updates | # https://docs.360dialog.com/whatsapp-api/whatsapp-api/media | ||||||
| # https://core.telegram.org/bots/api#available-types | # https://developers.facebook.com/docs/whatsapp/api/media/ | ||||||
|  |  | ||||||
| class Whatsapp::IncomingMessageService | class Whatsapp::IncomingMessageService | ||||||
|   pattr_initialize [:inbox!, :params!] |   pattr_initialize [:inbox!, :params!] | ||||||
| @@ -12,7 +12,7 @@ class Whatsapp::IncomingMessageService | |||||||
|  |  | ||||||
|     return if params[:messages].blank? |     return if params[:messages].blank? | ||||||
|  |  | ||||||
|     @message = @conversation.messages.create( |     @message = @conversation.messages.build( | ||||||
|       content: params[:messages].first.dig(:text, :body), |       content: params[:messages].first.dig(:text, :body), | ||||||
|       account_id: @inbox.account_id, |       account_id: @inbox.account_id, | ||||||
|       inbox_id: @inbox.id, |       inbox_id: @inbox.id, | ||||||
| @@ -20,6 +20,7 @@ class Whatsapp::IncomingMessageService | |||||||
|       sender: @contact, |       sender: @contact, | ||||||
|       source_id: params[:messages].first[:id].to_s |       source_id: params[:messages].first[:id].to_s | ||||||
|     ) |     ) | ||||||
|  |     attach_files | ||||||
|     @message.save! |     @message.save! | ||||||
|   end |   end | ||||||
|  |  | ||||||
| @@ -58,4 +59,31 @@ class Whatsapp::IncomingMessageService | |||||||
|  |  | ||||||
|     @conversation = ::Conversation.create!(conversation_params) |     @conversation = ::Conversation.create!(conversation_params) | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  |   def file_content_type(file_type) | ||||||
|  |     return :image if %w[image sticker].include?(file_type) | ||||||
|  |     return :audio if %w[audio voice].include?(file_type) | ||||||
|  |     return :video if ['video'].include?(file_type) | ||||||
|  |  | ||||||
|  |     'document' | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   def attach_files | ||||||
|  |     message_type = params[:messages].first[:type] | ||||||
|  |     return if message_type == 'text' | ||||||
|  |  | ||||||
|  |     attachment_payload = params[:messages].first[message_type.to_sym] | ||||||
|  |     attachment_file = Down.download(inbox.channel.media_url(attachment_payload[:id]), headers: inbox.channel.api_headers) | ||||||
|  |  | ||||||
|  |     @message.content ||= attachment_payload[:caption] | ||||||
|  |     @message.attachments.new( | ||||||
|  |       account_id: @message.account_id, | ||||||
|  |       file_type: file_content_type(message_type), | ||||||
|  |       file: { | ||||||
|  |         io: attachment_file, | ||||||
|  |         filename: attachment_file, | ||||||
|  |         content_type: attachment_file.content_type | ||||||
|  |       } | ||||||
|  |     ) | ||||||
|  |   end | ||||||
| end | end | ||||||
|   | |||||||
| @@ -6,6 +6,6 @@ class Whatsapp::SendOnWhatsappService < Base::SendOnChannelService | |||||||
|   end |   end | ||||||
|  |  | ||||||
|   def perform_reply |   def perform_reply | ||||||
|     channel.send_message(message.conversation.contact_inbox.source_id, message.content) |     channel.send_message(message.conversation.contact_inbox.source_id, message) | ||||||
|   end |   end | ||||||
| end | end | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ describe ::ContactIdentifyAction do | |||||||
|     end |     end | ||||||
|  |  | ||||||
|     it 'enques avatar job when avatar url parameter is passed' do |     it 'enques avatar job when avatar url parameter is passed' do | ||||||
|       params = { name: 'test', avatar_url: 'https://via.placeholder.com/250x250.png' } |       params = { name: 'test', avatar_url: 'https://chatwoot-assets.local/sample.png' } | ||||||
|       expect(ContactAvatarJob).to receive(:perform_later).with(contact, params[:avatar_url]).once |       expect(ContactAvatarJob).to receive(:perform_later).with(contact, params[:avatar_url]).once | ||||||
|       described_class.new(contact: contact, params: params).perform |       described_class.new(contact: contact, params: params).perform | ||||||
|     end |     end | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								spec/assets/sample.mov
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								spec/assets/sample.mov
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								spec/assets/sample.mp3
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								spec/assets/sample.mp3
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								spec/assets/sample.ogg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								spec/assets/sample.ogg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										198
									
								
								spec/assets/sample.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								spec/assets/sample.pdf
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,198 @@ | |||||||
|  | %PDF-1.3 | ||||||
|  | %<25><><EFBFBD><EFBFBD> | ||||||
|  |  | ||||||
|  | 1 0 obj | ||||||
|  | << | ||||||
|  | /Type /Catalog | ||||||
|  | /Outlines 2 0 R | ||||||
|  | /Pages 3 0 R | ||||||
|  | >> | ||||||
|  | endobj | ||||||
|  |  | ||||||
|  | 2 0 obj | ||||||
|  | << | ||||||
|  | /Type /Outlines | ||||||
|  | /Count 0 | ||||||
|  | >> | ||||||
|  | endobj | ||||||
|  |  | ||||||
|  | 3 0 obj | ||||||
|  | << | ||||||
|  | /Type /Pages | ||||||
|  | /Count 2 | ||||||
|  | /Kids [ 4 0 R 6 0 R ]  | ||||||
|  | >> | ||||||
|  | endobj | ||||||
|  |  | ||||||
|  | 4 0 obj | ||||||
|  | << | ||||||
|  | /Type /Page | ||||||
|  | /Parent 3 0 R | ||||||
|  | /Resources << | ||||||
|  | /Font << | ||||||
|  | /F1 9 0 R  | ||||||
|  | >> | ||||||
|  | /ProcSet 8 0 R | ||||||
|  | >> | ||||||
|  | /MediaBox [0 0 612.0000 792.0000] | ||||||
|  | /Contents 5 0 R | ||||||
|  | >> | ||||||
|  | endobj | ||||||
|  |  | ||||||
|  | 5 0 obj | ||||||
|  | << /Length 1074 >> | ||||||
|  | stream | ||||||
|  | 2 J | ||||||
|  | BT | ||||||
|  | 0 0 0 rg | ||||||
|  | /F1 0027 Tf | ||||||
|  | 57.3750 722.2800 Td | ||||||
|  | ( A Simple PDF File ) Tj | ||||||
|  | ET | ||||||
|  | BT | ||||||
|  | /F1 0010 Tf | ||||||
|  | 69.2500 688.6080 Td | ||||||
|  | ( This is a small demonstration .pdf file - ) Tj | ||||||
|  | ET | ||||||
|  | BT | ||||||
|  | /F1 0010 Tf | ||||||
|  | 69.2500 664.7040 Td | ||||||
|  | ( just for use in the Virtual Mechanics tutorials. More text. And more ) Tj | ||||||
|  | ET | ||||||
|  | BT | ||||||
|  | /F1 0010 Tf | ||||||
|  | 69.2500 652.7520 Td | ||||||
|  | ( text. And more text. And more text. And more text. ) Tj | ||||||
|  | ET | ||||||
|  | BT | ||||||
|  | /F1 0010 Tf | ||||||
|  | 69.2500 628.8480 Td | ||||||
|  | ( And more text. And more text. And more text. And more text. And more ) Tj | ||||||
|  | ET | ||||||
|  | BT | ||||||
|  | /F1 0010 Tf | ||||||
|  | 69.2500 616.8960 Td | ||||||
|  | ( text. And more text. Boring, zzzzz. And more text. And more text. And ) Tj | ||||||
|  | ET | ||||||
|  | BT | ||||||
|  | /F1 0010 Tf | ||||||
|  | 69.2500 604.9440 Td | ||||||
|  | ( more text. And more text. And more text. And more text. And more text. ) Tj | ||||||
|  | ET | ||||||
|  | BT | ||||||
|  | /F1 0010 Tf | ||||||
|  | 69.2500 592.9920 Td | ||||||
|  | ( And more text. And more text. ) Tj | ||||||
|  | ET | ||||||
|  | BT | ||||||
|  | /F1 0010 Tf | ||||||
|  | 69.2500 569.0880 Td | ||||||
|  | ( And more text. And more text. And more text. And more text. And more ) Tj | ||||||
|  | ET | ||||||
|  | BT | ||||||
|  | /F1 0010 Tf | ||||||
|  | 69.2500 557.1360 Td | ||||||
|  | ( text. And more text. And more text. Even more. Continued on page 2 ...) Tj | ||||||
|  | ET | ||||||
|  | endstream | ||||||
|  | endobj | ||||||
|  |  | ||||||
|  | 6 0 obj | ||||||
|  | << | ||||||
|  | /Type /Page | ||||||
|  | /Parent 3 0 R | ||||||
|  | /Resources << | ||||||
|  | /Font << | ||||||
|  | /F1 9 0 R  | ||||||
|  | >> | ||||||
|  | /ProcSet 8 0 R | ||||||
|  | >> | ||||||
|  | /MediaBox [0 0 612.0000 792.0000] | ||||||
|  | /Contents 7 0 R | ||||||
|  | >> | ||||||
|  | endobj | ||||||
|  |  | ||||||
|  | 7 0 obj | ||||||
|  | << /Length 676 >> | ||||||
|  | stream | ||||||
|  | 2 J | ||||||
|  | BT | ||||||
|  | 0 0 0 rg | ||||||
|  | /F1 0027 Tf | ||||||
|  | 57.3750 722.2800 Td | ||||||
|  | ( Simple PDF File 2 ) Tj | ||||||
|  | ET | ||||||
|  | BT | ||||||
|  | /F1 0010 Tf | ||||||
|  | 69.2500 688.6080 Td | ||||||
|  | ( ...continued from page 1. Yet more text. And more text. And more text. ) Tj | ||||||
|  | ET | ||||||
|  | BT | ||||||
|  | /F1 0010 Tf | ||||||
|  | 69.2500 676.6560 Td | ||||||
|  | ( And more text. And more text. And more text. And more text. And more ) Tj | ||||||
|  | ET | ||||||
|  | BT | ||||||
|  | /F1 0010 Tf | ||||||
|  | 69.2500 664.7040 Td | ||||||
|  | ( text. Oh, how boring typing this stuff. But not as boring as watching ) Tj | ||||||
|  | ET | ||||||
|  | BT | ||||||
|  | /F1 0010 Tf | ||||||
|  | 69.2500 652.7520 Td | ||||||
|  | ( paint dry. And more text. And more text. And more text. And more text. ) Tj | ||||||
|  | ET | ||||||
|  | BT | ||||||
|  | /F1 0010 Tf | ||||||
|  | 69.2500 640.8000 Td | ||||||
|  | ( Boring.  More, a little more text. The end, and just as well. ) Tj | ||||||
|  | ET | ||||||
|  | endstream | ||||||
|  | endobj | ||||||
|  |  | ||||||
|  | 8 0 obj | ||||||
|  | [/PDF /Text] | ||||||
|  | endobj | ||||||
|  |  | ||||||
|  | 9 0 obj | ||||||
|  | << | ||||||
|  | /Type /Font | ||||||
|  | /Subtype /Type1 | ||||||
|  | /Name /F1 | ||||||
|  | /BaseFont /Helvetica | ||||||
|  | /Encoding /WinAnsiEncoding | ||||||
|  | >> | ||||||
|  | endobj | ||||||
|  |  | ||||||
|  | 10 0 obj | ||||||
|  | << | ||||||
|  | /Creator (Rave \(http://www.nevrona.com/rave\)) | ||||||
|  | /Producer (Nevrona Designs) | ||||||
|  | /CreationDate (D:20060301072826) | ||||||
|  | >> | ||||||
|  | endobj | ||||||
|  |  | ||||||
|  | xref | ||||||
|  | 0 11 | ||||||
|  | 0000000000 65535 f | ||||||
|  | 0000000019 00000 n | ||||||
|  | 0000000093 00000 n | ||||||
|  | 0000000147 00000 n | ||||||
|  | 0000000222 00000 n | ||||||
|  | 0000000390 00000 n | ||||||
|  | 0000001522 00000 n | ||||||
|  | 0000001690 00000 n | ||||||
|  | 0000002423 00000 n | ||||||
|  | 0000002456 00000 n | ||||||
|  | 0000002574 00000 n | ||||||
|  |  | ||||||
|  | trailer | ||||||
|  | << | ||||||
|  | /Size 11 | ||||||
|  | /Root 1 0 R | ||||||
|  | /Info 10 0 R | ||||||
|  | >> | ||||||
|  |  | ||||||
|  | startxref | ||||||
|  | 2714 | ||||||
|  | %%EOF | ||||||
							
								
								
									
										
											BIN
										
									
								
								spec/assets/sample.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								spec/assets/sample.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 522 KiB | 
| @@ -199,6 +199,10 @@ describe ::ContactInboxBuilder do | |||||||
|     end |     end | ||||||
|  |  | ||||||
|     describe 'facebook inbox' do |     describe 'facebook inbox' do | ||||||
|  |       before do | ||||||
|  |         stub_request(:post, /graph.facebook.com/) | ||||||
|  |       end | ||||||
|  |  | ||||||
|       let!(:facebook_channel) { create(:channel_facebook_page, account: account) } |       let!(:facebook_channel) { create(:channel_facebook_page, account: account) } | ||||||
|       let!(:facebook_inbox) { create(:inbox, channel: facebook_channel, account: account) } |       let!(:facebook_inbox) { create(:inbox, channel: facebook_channel, account: account) } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,6 +3,10 @@ require 'rails_helper' | |||||||
| describe  ::Messages::Facebook::MessageBuilder do | describe  ::Messages::Facebook::MessageBuilder do | ||||||
|   subject(:message_builder) { described_class.new(incoming_fb_text_message, facebook_channel.inbox).perform } |   subject(:message_builder) { described_class.new(incoming_fb_text_message, facebook_channel.inbox).perform } | ||||||
|  |  | ||||||
|  |   before do | ||||||
|  |     stub_request(:post, /graph.facebook.com/) | ||||||
|  |   end | ||||||
|  |  | ||||||
|   let!(:facebook_channel) { create(:channel_facebook_page) } |   let!(:facebook_channel) { create(:channel_facebook_page) } | ||||||
|   let!(:message_object) { build(:incoming_fb_text_message).to_json } |   let!(:message_object) { build(:incoming_fb_text_message).to_json } | ||||||
|   let!(:incoming_fb_text_message) { Integrations::Facebook::MessageParser.new(message_object) } |   let!(:incoming_fb_text_message) { Integrations::Facebook::MessageParser.new(message_object) } | ||||||
| @@ -16,7 +20,7 @@ describe  ::Messages::Facebook::MessageBuilder do | |||||||
|           first_name: 'Jane', |           first_name: 'Jane', | ||||||
|           last_name: 'Dae', |           last_name: 'Dae', | ||||||
|           account_id: facebook_channel.inbox.account_id, |           account_id: facebook_channel.inbox.account_id, | ||||||
|           profile_pic: 'https://via.placeholder.com/250x250.png' |           profile_pic: 'https://chatwoot-assets.local/sample.png' | ||||||
|         }.with_indifferent_access |         }.with_indifferent_access | ||||||
|       ) |       ) | ||||||
|       message_builder |       message_builder | ||||||
|   | |||||||
| @@ -3,6 +3,10 @@ require 'rails_helper' | |||||||
| describe  ::Messages::Instagram::MessageBuilder do | describe  ::Messages::Instagram::MessageBuilder do | ||||||
|   subject(:instagram_message_builder) { described_class } |   subject(:instagram_message_builder) { described_class } | ||||||
|  |  | ||||||
|  |   before do | ||||||
|  |     stub_request(:post, /graph.facebook.com/) | ||||||
|  |   end | ||||||
|  |  | ||||||
|   let!(:account) { create(:account) } |   let!(:account) { create(:account) } | ||||||
|   let!(:instagram_channel) { create(:channel_instagram_fb_page, account: account, instagram_id: 'chatwoot-app-user-id-1') } |   let!(:instagram_channel) { create(:channel_instagram_fb_page, account: account, instagram_id: 'chatwoot-app-user-id-1') } | ||||||
|   let!(:instagram_inbox) { create(:inbox, channel: instagram_channel, account: account, greeting_enabled: false) } |   let!(:instagram_inbox) { create(:inbox, channel: instagram_channel, account: account, greeting_enabled: false) } | ||||||
| @@ -19,7 +23,7 @@ describe  ::Messages::Instagram::MessageBuilder do | |||||||
|           name: 'Jane', |           name: 'Jane', | ||||||
|           id: 'Sender-id-1', |           id: 'Sender-id-1', | ||||||
|           account_id: instagram_inbox.account_id, |           account_id: instagram_inbox.account_id, | ||||||
|           profile_pic: 'https://via.placeholder.com/250x250.png' |           profile_pic: 'https://chatwoot-assets.local/sample.png' | ||||||
|         }.with_indifferent_access |         }.with_indifferent_access | ||||||
|       ) |       ) | ||||||
|       messaging = dm_params[:entry][0]['messaging'][0] |       messaging = dm_params[:entry][0]['messaging'][0] | ||||||
|   | |||||||
| @@ -1,16 +1,8 @@ | |||||||
| require 'rails_helper' | require 'rails_helper' | ||||||
|  |  | ||||||
| RSpec.describe 'Callbacks API', type: :request do | RSpec.describe 'Callbacks API', type: :request do | ||||||
|   let(:account) { create(:account) } |  | ||||||
|   let(:valid_params) { attributes_for(:channel_facebook_page).merge(inbox_name: 'Test Inbox') } |  | ||||||
|   let(:inbox) { create(:inbox, account: account) } |  | ||||||
|   let!(:facebook_page) { create(:channel_facebook_page, inbox: inbox, account: account) } |  | ||||||
|  |  | ||||||
|   # Doubles |  | ||||||
|   let(:koala_api) { instance_double(Koala::Facebook::API) } |  | ||||||
|   let(:koala_oauth) { instance_double(Koala::Facebook::OAuth) } |  | ||||||
|  |  | ||||||
|   before do |   before do | ||||||
|  |     stub_request(:any, /graph.facebook.com/) | ||||||
|     # Mock new and return instance doubles defined above |     # Mock new and return instance doubles defined above | ||||||
|     allow(Koala::Facebook::OAuth).to receive(:new).and_return(koala_oauth) |     allow(Koala::Facebook::OAuth).to receive(:new).and_return(koala_oauth) | ||||||
|     allow(Koala::Facebook::API).to receive(:new).and_return(koala_api) |     allow(Koala::Facebook::API).to receive(:new).and_return(koala_api) | ||||||
| @@ -22,6 +14,15 @@ RSpec.describe 'Callbacks API', type: :request do | |||||||
|     allow(koala_oauth).to receive(:exchange_access_token_info).and_return('access_token' => SecureRandom.hex(10)) |     allow(koala_oauth).to receive(:exchange_access_token_info).and_return('access_token' => SecureRandom.hex(10)) | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  |   let(:account) { create(:account) } | ||||||
|  |   let!(:facebook_page) { create(:channel_facebook_page, inbox: inbox, account: account) } | ||||||
|  |   let(:valid_params) { attributes_for(:channel_facebook_page).merge(inbox_name: 'Test Inbox') } | ||||||
|  |   let(:inbox) { create(:inbox, account: account) } | ||||||
|  |  | ||||||
|  |   # Doubles | ||||||
|  |   let(:koala_api) { instance_double(Koala::Facebook::API) } | ||||||
|  |   let(:koala_oauth) { instance_double(Koala::Facebook::OAuth) } | ||||||
|  |  | ||||||
|   describe 'POST /api/v1/accounts/{account.id}/callbacks/register_facebook_page' do |   describe 'POST /api/v1/accounts/{account.id}/callbacks/register_facebook_page' do | ||||||
|     context 'when it is an unauthenticated user' do |     context 'when it is an unauthenticated user' do | ||||||
|       it 'returns unauthorized' do |       it 'returns unauthorized' do | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ FactoryBot.define do | |||||||
|   factory :bot_message_card, class: Hash do |   factory :bot_message_card, class: Hash do | ||||||
|     title { Faker::Book.name } |     title { Faker::Book.name } | ||||||
|     description { Faker::Movie.quote } |     description { Faker::Movie.quote } | ||||||
|     media_url { 'https://via.placeholder.com/250x250.png' } |     media_url { 'https://chatwoot-assets.local/sample.png' } | ||||||
|     actions do |     actions do | ||||||
|       [{ |       [{ | ||||||
|         text: 'Select', |         text: 'Select', | ||||||
|   | |||||||
| @@ -22,12 +22,12 @@ FactoryBot.define do | |||||||
|         '1' => { |         '1' => { | ||||||
|           id: '1', |           id: '1', | ||||||
|           name: 'person 1', |           name: 'person 1', | ||||||
|           profile_image_url: 'https://via.placeholder.com/250x250.png' |           profile_image_url: 'https://chatwoot-assets.local/sample.png' | ||||||
|         }, |         }, | ||||||
|         '2' => { |         '2' => { | ||||||
|           id: '1', |           id: '1', | ||||||
|           name: 'person 1', |           name: 'person 1', | ||||||
|           profile_image_url: 'https://via.placeholder.com/250x250.png' |           profile_image_url: 'https://chatwoot-assets.local/sample.png' | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     end |     end | ||||||
|   | |||||||
| @@ -19,6 +19,7 @@ RSpec.describe SendReplyJob, type: :job do | |||||||
|     end |     end | ||||||
|  |  | ||||||
|     it 'calls Facebook::SendOnFacebookService when its facebook message' do |     it 'calls Facebook::SendOnFacebookService when its facebook message' do | ||||||
|  |       stub_request(:post, /graph.facebook.com/) | ||||||
|       facebook_channel = create(:channel_facebook_page) |       facebook_channel = create(:channel_facebook_page) | ||||||
|       facebook_inbox = create(:inbox, channel: facebook_channel) |       facebook_inbox = create(:inbox, channel: facebook_channel) | ||||||
|       message = create(:message, conversation: create(:conversation, inbox: facebook_inbox)) |       message = create(:message, conversation: create(:conversation, inbox: facebook_inbox)) | ||||||
| @@ -66,6 +67,7 @@ RSpec.describe SendReplyJob, type: :job do | |||||||
|     end |     end | ||||||
|  |  | ||||||
|     it 'calls ::Whatsapp:SendOnWhatsappService when its line message' do |     it 'calls ::Whatsapp:SendOnWhatsappService when its line message' do | ||||||
|  |       stub_request(:post, 'https://waba.360dialog.io/v1/configs/webhook') | ||||||
|       whatsapp_channel = create(:channel_whatsapp) |       whatsapp_channel = create(:channel_whatsapp) | ||||||
|       message = create(:message, conversation: create(:conversation, inbox: whatsapp_channel.inbox)) |       message = create(:message, conversation: create(:conversation, inbox: whatsapp_channel.inbox)) | ||||||
|       allow(::Whatsapp::SendOnWhatsappService).to receive(:new).with(message: message).and_return(process_service) |       allow(::Whatsapp::SendOnWhatsappService).to receive(:new).with(message: message).and_return(process_service) | ||||||
|   | |||||||
| @@ -4,6 +4,10 @@ require 'webhooks/twitter' | |||||||
| describe Webhooks::InstagramEventsJob do | describe Webhooks::InstagramEventsJob do | ||||||
|   subject(:instagram_webhook) { described_class } |   subject(:instagram_webhook) { described_class } | ||||||
|  |  | ||||||
|  |   before do | ||||||
|  |     stub_request(:post, /graph.facebook.com/) | ||||||
|  |   end | ||||||
|  |  | ||||||
|   let!(:account) { create(:account) } |   let!(:account) { create(:account) } | ||||||
|   let!(:instagram_channel) { create(:channel_instagram_fb_page, account: account, instagram_id: 'chatwoot-app-user-id-1') } |   let!(:instagram_channel) { create(:channel_instagram_fb_page, account: account, instagram_id: 'chatwoot-app-user-id-1') } | ||||||
|   let!(:instagram_inbox) { create(:inbox, channel: instagram_channel, account: account, greeting_enabled: false) } |   let!(:instagram_inbox) { create(:inbox, channel: instagram_channel, account: account, greeting_enabled: false) } | ||||||
| @@ -20,7 +24,7 @@ describe Webhooks::InstagramEventsJob do | |||||||
|             name: 'Jane', |             name: 'Jane', | ||||||
|             id: 'Sender-id-1', |             id: 'Sender-id-1', | ||||||
|             account_id: instagram_inbox.account_id, |             account_id: instagram_inbox.account_id, | ||||||
|             profile_pic: 'https://via.placeholder.com/250x250.png' |             profile_pic: 'https://chatwoot-assets.local/sample.png' | ||||||
|           }.with_indifferent_access |           }.with_indifferent_access | ||||||
|         ) |         ) | ||||||
|         instagram_webhook.perform_now(dm_params[:entry]) |         instagram_webhook.perform_now(dm_params[:entry]) | ||||||
| @@ -39,7 +43,7 @@ describe Webhooks::InstagramEventsJob do | |||||||
|             name: 'Jane', |             name: 'Jane', | ||||||
|             id: 'Sender-id-1', |             id: 'Sender-id-1', | ||||||
|             account_id: instagram_inbox.account_id, |             account_id: instagram_inbox.account_id, | ||||||
|             profile_pic: 'https://via.placeholder.com/250x250.png' |             profile_pic: 'https://chatwoot-assets.local/sample.png' | ||||||
|           }.with_indifferent_access |           }.with_indifferent_access | ||||||
|         ) |         ) | ||||||
|         instagram_webhook.perform_now(test_params[:entry]) |         instagram_webhook.perform_now(test_params[:entry]) | ||||||
|   | |||||||
| @@ -10,6 +10,14 @@ describe Integrations::Slack::IncomingMessageBuilder do | |||||||
|   let!(:hook) { create(:integrations_hook, account: account, reference_id: message_params[:event][:channel]) } |   let!(:hook) { create(:integrations_hook, account: account, reference_id: message_params[:event][:channel]) } | ||||||
|   let!(:conversation) { create(:conversation, identifier: message_params[:event][:thread_ts]) } |   let!(:conversation) { create(:conversation, identifier: message_params[:event][:thread_ts]) } | ||||||
|  |  | ||||||
|  |   before do | ||||||
|  |     stub_request(:get, 'https://chatwoot-assets.local/sample.png').to_return( | ||||||
|  |       status: 200, | ||||||
|  |       body: File.read('spec/assets/sample.png'), | ||||||
|  |       headers: {} | ||||||
|  |     ) | ||||||
|  |   end | ||||||
|  |  | ||||||
|   describe '#perform' do |   describe '#perform' do | ||||||
|     context 'when url verification' do |     context 'when url verification' do | ||||||
|       it 'return challenge code as response' do |       it 'return challenge code as response' do | ||||||
|   | |||||||
| @@ -25,6 +25,10 @@ RSpec.describe AdministratorNotifications::ChannelNotificationsMailer, type: :ma | |||||||
|   end |   end | ||||||
|  |  | ||||||
|   describe 'facebook_disconnect' do |   describe 'facebook_disconnect' do | ||||||
|  |     before do | ||||||
|  |       stub_request(:post, /graph.facebook.com/) | ||||||
|  |     end | ||||||
|  |  | ||||||
|     let!(:facebook_channel) { create(:channel_facebook_page, account: account) } |     let!(:facebook_channel) { create(:channel_facebook_page, account: account) } | ||||||
|     let!(:facebook_inbox) { create(:inbox, channel: facebook_channel, account: account) } |     let!(:facebook_inbox) { create(:inbox, channel: facebook_channel, account: account) } | ||||||
|     let(:mail) { described_class.with(account: account).facebook_disconnect(facebook_inbox).deliver_now } |     let(:mail) { described_class.with(account: account).facebook_disconnect(facebook_inbox).deliver_now } | ||||||
|   | |||||||
| @@ -22,6 +22,10 @@ RSpec.describe Campaign, type: :model do | |||||||
|   end |   end | ||||||
|  |  | ||||||
|   context 'when Inbox other then Website or Twilio SMS' do |   context 'when Inbox other then Website or Twilio SMS' do | ||||||
|  |     before do | ||||||
|  |       stub_request(:post, /graph.facebook.com/) | ||||||
|  |     end | ||||||
|  |  | ||||||
|     let!(:facebook_channel) { create(:channel_facebook_page) } |     let!(:facebook_channel) { create(:channel_facebook_page) } | ||||||
|     let!(:facebook_inbox) { create(:inbox, channel: facebook_channel) } |     let!(:facebook_inbox) { create(:inbox, channel: facebook_channel) } | ||||||
|     let(:campaign) { build(:campaign, inbox: facebook_inbox) } |     let(:campaign) { build(:campaign, inbox: facebook_inbox) } | ||||||
|   | |||||||
| @@ -4,6 +4,10 @@ require 'rails_helper' | |||||||
| require Rails.root.join 'spec/models/concerns/reauthorizable_shared.rb' | require Rails.root.join 'spec/models/concerns/reauthorizable_shared.rb' | ||||||
|  |  | ||||||
| RSpec.describe Channel::FacebookPage do | RSpec.describe Channel::FacebookPage do | ||||||
|  |   before do | ||||||
|  |     stub_request(:post, /graph.facebook.com/) | ||||||
|  |   end | ||||||
|  |  | ||||||
|   let(:channel) { create(:channel_facebook_page) } |   let(:channel) { create(:channel_facebook_page) } | ||||||
|  |  | ||||||
|   it { is_expected.to validate_presence_of(:account_id) } |   it { is_expected.to validate_presence_of(:account_id) } | ||||||
|   | |||||||
| @@ -394,6 +394,10 @@ RSpec.describe Conversation, type: :model do | |||||||
|     end |     end | ||||||
|  |  | ||||||
|     describe 'on channels with 24 hour restriction' do |     describe 'on channels with 24 hour restriction' do | ||||||
|  |       before do | ||||||
|  |         stub_request(:post, /graph.facebook.com/) | ||||||
|  |       end | ||||||
|  |  | ||||||
|       let!(:facebook_channel) { create(:channel_facebook_page) } |       let!(:facebook_channel) { create(:channel_facebook_page) } | ||||||
|       let!(:facebook_inbox) { create(:inbox, channel: facebook_channel, account: facebook_channel.account) } |       let!(:facebook_inbox) { create(:inbox, channel: facebook_channel, account: facebook_channel.account) } | ||||||
|       let!(:conversation) { create(:conversation, inbox: facebook_inbox, account: facebook_channel.account) } |       let!(:conversation) { create(:conversation, inbox: facebook_inbox, account: facebook_channel.account) } | ||||||
|   | |||||||
| @@ -1,6 +1,10 @@ | |||||||
| require 'rails_helper' | require 'rails_helper' | ||||||
|  |  | ||||||
| describe Contacts::ContactableInboxesService do | describe Contacts::ContactableInboxesService do | ||||||
|  |   before do | ||||||
|  |     stub_request(:post, /graph.facebook.com/) | ||||||
|  |   end | ||||||
|  |  | ||||||
|   let(:account) { create(:account) } |   let(:account) { create(:account) } | ||||||
|   let(:contact) { create(:contact, account: account, email: 'contact@example.com', phone_number: '+2320000') } |   let(:contact) { create(:contact, account: account, email: 'contact@example.com', phone_number: '+2320000') } | ||||||
|   let!(:twilio_sms) { create(:channel_twilio_sms, account: account) } |   let!(:twilio_sms) { create(:channel_twilio_sms, account: account) } | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ describe Instagram::SendOnInstagramService do | |||||||
|   subject(:send_reply_service) { described_class.new(message: message) } |   subject(:send_reply_service) { described_class.new(message: message) } | ||||||
|  |  | ||||||
|   before do |   before do | ||||||
|  |     stub_request(:post, /graph.facebook.com/) | ||||||
|     create(:message, message_type: :incoming, inbox: instagram_inbox, account: account, conversation: conversation) |     create(:message, message_type: :incoming, inbox: instagram_inbox, account: account, conversation: conversation) | ||||||
|   end |   end | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,6 +1,35 @@ | |||||||
| require 'rails_helper' | require 'rails_helper' | ||||||
|  |  | ||||||
| describe Telegram::IncomingMessageService do | describe Telegram::IncomingMessageService do | ||||||
|  |   before do | ||||||
|  |     stub_request(:any, /api.telegram.org/).to_return(headers: { content_type: 'application/json' }, body: {}.to_json, status: 200) | ||||||
|  |     stub_request(:get, 'https://chatwoot-assets.local/sample.png').to_return( | ||||||
|  |       status: 200, | ||||||
|  |       body: File.read('spec/assets/sample.png'), | ||||||
|  |       headers: {} | ||||||
|  |     ) | ||||||
|  |     stub_request(:get, 'https://chatwoot-assets.local/sample.mov').to_return( | ||||||
|  |       status: 200, | ||||||
|  |       body: File.read('spec/assets/sample.mov'), | ||||||
|  |       headers: {} | ||||||
|  |     ) | ||||||
|  |     stub_request(:get, 'https://chatwoot-assets.local/sample.mp3').to_return( | ||||||
|  |       status: 200, | ||||||
|  |       body: File.read('spec/assets/sample.mp3'), | ||||||
|  |       headers: {} | ||||||
|  |     ) | ||||||
|  |     stub_request(:get, 'https://chatwoot-assets.local/sample.ogg').to_return( | ||||||
|  |       status: 200, | ||||||
|  |       body: File.read('spec/assets/sample.ogg'), | ||||||
|  |       headers: {} | ||||||
|  |     ) | ||||||
|  |     stub_request(:get, 'https://chatwoot-assets.local/sample.pdf').to_return( | ||||||
|  |       status: 200, | ||||||
|  |       body: File.read('spec/assets/sample.pdf'), | ||||||
|  |       headers: {} | ||||||
|  |     ) | ||||||
|  |   end | ||||||
|  |  | ||||||
|   let!(:telegram_channel) { create(:channel_telegram) } |   let!(:telegram_channel) { create(:channel_telegram) } | ||||||
|  |  | ||||||
|   describe '#perform' do |   describe '#perform' do | ||||||
| @@ -64,7 +93,7 @@ describe Telegram::IncomingMessageService do | |||||||
|  |  | ||||||
|     context 'when valid audio messages params' do |     context 'when valid audio messages params' do | ||||||
|       it 'creates appropriate conversations, message and contacts' do |       it 'creates appropriate conversations, message and contacts' do | ||||||
|         allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-public-assets.s3.amazonaws.com/test-files/rspec/sample.mp3') |         allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-assets.local/sample.mp3') | ||||||
|         params = { |         params = { | ||||||
|           'update_id' => 2_342_342_343_242, |           'update_id' => 2_342_342_343_242, | ||||||
|           'message' => { |           'message' => { | ||||||
| @@ -92,7 +121,7 @@ describe Telegram::IncomingMessageService do | |||||||
|  |  | ||||||
|     context 'when valid image attachment params' do |     context 'when valid image attachment params' do | ||||||
|       it 'creates appropriate conversations, message and contacts' do |       it 'creates appropriate conversations, message and contacts' do | ||||||
|         allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-public-assets.s3.amazonaws.com/test-files/rspec/sample.png') |         allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-assets.local/sample.png') | ||||||
|         params = { |         params = { | ||||||
|           'update_id' => 2_342_342_343_242, |           'update_id' => 2_342_342_343_242, | ||||||
|           'message' => { |           'message' => { | ||||||
| @@ -117,7 +146,7 @@ describe Telegram::IncomingMessageService do | |||||||
|  |  | ||||||
|     context 'when valid sticker attachment params' do |     context 'when valid sticker attachment params' do | ||||||
|       it 'creates appropriate conversations, message and contacts' do |       it 'creates appropriate conversations, message and contacts' do | ||||||
|         allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-public-assets.s3.amazonaws.com/test-files/rspec/sample.png') |         allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-assets.local/sample.png') | ||||||
|         params = { |         params = { | ||||||
|           'update_id' => 2_342_342_343_242, |           'update_id' => 2_342_342_343_242, | ||||||
|           'message' => { |           'message' => { | ||||||
| @@ -147,7 +176,7 @@ describe Telegram::IncomingMessageService do | |||||||
|  |  | ||||||
|     context 'when valid video messages params' do |     context 'when valid video messages params' do | ||||||
|       it 'creates appropriate conversations, message and contacts' do |       it 'creates appropriate conversations, message and contacts' do | ||||||
|         allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-public-assets.s3.amazonaws.com/test-files/rspec/sample.mov') |         allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-assets.local/sample.mov') | ||||||
|         params = { |         params = { | ||||||
|           'update_id' => 2_342_342_343_242, |           'update_id' => 2_342_342_343_242, | ||||||
|           'message' => { |           'message' => { | ||||||
| @@ -175,7 +204,7 @@ describe Telegram::IncomingMessageService do | |||||||
|  |  | ||||||
|     context 'when valid voice attachment params' do |     context 'when valid voice attachment params' do | ||||||
|       it 'creates appropriate conversations, message and contacts' do |       it 'creates appropriate conversations, message and contacts' do | ||||||
|         allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-public-assets.s3.amazonaws.com/test-files/rspec/sample.oga') |         allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-assets.local/sample.ogg') | ||||||
|         params = { |         params = { | ||||||
|           'update_id' => 2_342_342_343_242, |           'update_id' => 2_342_342_343_242, | ||||||
|           'message' => { |           'message' => { | ||||||
| @@ -200,7 +229,7 @@ describe Telegram::IncomingMessageService do | |||||||
|  |  | ||||||
|     context 'when valid document message params' do |     context 'when valid document message params' do | ||||||
|       it 'creates appropriate conversations, message and contacts' do |       it 'creates appropriate conversations, message and contacts' do | ||||||
|         allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-public-assets.s3.amazonaws.com/test-files/rspec/sample.pdf') |         allow(telegram_channel.inbox.channel).to receive(:get_telegram_file_path).and_return('https://chatwoot-assets.local/sample.pdf') | ||||||
|         params = { |         params = { | ||||||
|           'update_id' => 2_342_342_343_242, |           'update_id' => 2_342_342_343_242, | ||||||
|           'message' => { |           'message' => { | ||||||
|   | |||||||
| @@ -1,9 +1,13 @@ | |||||||
| require 'rails_helper' | require 'rails_helper' | ||||||
|  |  | ||||||
| describe Whatsapp::IncomingMessageService do | describe Whatsapp::IncomingMessageService do | ||||||
|  |   describe '#perform' do | ||||||
|  |     before do | ||||||
|  |       stub_request(:post, 'https://waba.360dialog.io/v1/configs/webhook') | ||||||
|  |     end | ||||||
|  |  | ||||||
|     let!(:whatsapp_channel) { create(:channel_whatsapp) } |     let!(:whatsapp_channel) { create(:channel_whatsapp) } | ||||||
|  |  | ||||||
|   describe '#perform' do |  | ||||||
|     context 'when valid text message params' do |     context 'when valid text message params' do | ||||||
|       it 'creates appropriate conversations, message and contacts' do |       it 'creates appropriate conversations, message and contacts' do | ||||||
|         params = { |         params = { | ||||||
| @@ -17,5 +21,29 @@ describe Whatsapp::IncomingMessageService do | |||||||
|         expect(whatsapp_channel.inbox.messages.first.content).to eq('Test') |         expect(whatsapp_channel.inbox.messages.first.content).to eq('Test') | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  |     context 'when valid attachment message params' do | ||||||
|  |       it 'creates appropriate conversations, message and contacts' do | ||||||
|  |         stub_request(:get, whatsapp_channel.media_url('b1c68f38-8734-4ad3-b4a1-ef0c10d683')).to_return( | ||||||
|  |           status: 200, | ||||||
|  |           body: File.read('spec/assets/sample.png'), | ||||||
|  |           headers: {} | ||||||
|  |         ) | ||||||
|  |         params = { | ||||||
|  |           'contacts' => [{ 'profile' => { 'name' => 'Sojan Jose' }, 'wa_id' => '2423423243' }], | ||||||
|  |           'messages' => [{ 'from' => '2423423243', 'id' => 'SDFADSf23sfasdafasdfa', | ||||||
|  |                            'image' => { 'id' => 'b1c68f38-8734-4ad3-b4a1-ef0c10d683', | ||||||
|  |                                         'mime_type' => 'image/jpeg', | ||||||
|  |                                         'sha256' => '29ed500fa64eb55fc19dc4124acb300e5dcca0f822a301ae99944db', | ||||||
|  |                                         'caption' => 'Check out my product!' }, | ||||||
|  |                            'timestamp' => '1633034394', 'type' => 'image' }] | ||||||
|  |         }.with_indifferent_access | ||||||
|  |         described_class.new(inbox: whatsapp_channel.inbox, params: params).perform | ||||||
|  |         expect(whatsapp_channel.inbox.conversations.count).not_to eq(0) | ||||||
|  |         expect(Contact.all.first.name).to eq('Sojan Jose') | ||||||
|  |         expect(whatsapp_channel.inbox.messages.first.content).to eq('Check out my product!') | ||||||
|  |         expect(whatsapp_channel.inbox.messages.first.attachments.present?).to eq true | ||||||
|  |       end | ||||||
|  |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|   | |||||||
| @@ -2,6 +2,10 @@ require 'rails_helper' | |||||||
|  |  | ||||||
| describe Whatsapp::SendOnWhatsappService do | describe Whatsapp::SendOnWhatsappService do | ||||||
|   describe '#perform' do |   describe '#perform' do | ||||||
|  |     before do | ||||||
|  |       stub_request(:post, 'https://waba.360dialog.io/v1/configs/webhook') | ||||||
|  |     end | ||||||
|  |  | ||||||
|     context 'when a valid message' do |     context 'when a valid message' do | ||||||
|       it 'calls channel.send_message' do |       it 'calls channel.send_message' do | ||||||
|         whatsapp_request = double |         whatsapp_request = double | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ require 'simplecov' | |||||||
| require 'webmock/rspec' | require 'webmock/rspec' | ||||||
|  |  | ||||||
| SimpleCov.start 'rails' | SimpleCov.start 'rails' | ||||||
| WebMock.allow_net_connect! | WebMock.disable_net_connect!(allow_localhost: true) | ||||||
|  |  | ||||||
| RSpec.configure do |config| | RSpec.configure do |config| | ||||||
|   config.expect_with :rspec do |expectations| |   config.expect_with :rspec do |expectations| | ||||||
|   | |||||||
| @@ -78,11 +78,11 @@ module SlackStubs | |||||||
|     [ |     [ | ||||||
|       { |       { | ||||||
|         mimetype: 'image/png', |         mimetype: 'image/png', | ||||||
|         url_private: 'https://via.placeholder.com/250x250.png', |         url_private: 'https://chatwoot-assets.local/sample.png', | ||||||
|         name: 'name_of_the_file', |         name: 'name_of_the_file', | ||||||
|         title: 'title_of_the_file', |         title: 'title_of_the_file', | ||||||
|         filetype: 'png', |         filetype: 'png', | ||||||
|         url_private_download: 'https://via.placeholder.com/250x250.png' |         url_private_download: 'https://chatwoot-assets.local/sample.png' | ||||||
|       } |       } | ||||||
|     ] |     ] | ||||||
|   end |   end | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Sojan Jose
					Sojan Jose