chore: Handle attachments in Whatsapp Channel (#3299)

send and receive attachments in 360Dialog WhatsApp channels
This commit is contained in:
Sojan Jose 2021-11-11 11:33:48 +04:00 committed by GitHub
parent b3e313a200
commit a4c87f2052
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 422 additions and 45 deletions

View file

@ -144,6 +144,8 @@ group :test do
gem 'cypress-on-rails', '~> 1.0'
# fast cleaning of database
gem 'database_cleaner'
# mock http calls
gem 'webmock'
end
group :development, :test do
@ -171,5 +173,4 @@ group :development, :test do
gem 'simplecov', '0.17.1', require: false
gem 'spring'
gem 'spring-watcher-listen'
gem 'webmock'
end

View file

@ -228,7 +228,7 @@ export default {
return (
this.isAWebWidgetInbox ||
this.isAFacebookInbox ||
this.isATwilioWhatsappChannel ||
this.isAWhatsappChannel ||
this.isAPIInbox ||
this.isAnEmailChannel ||
this.isATwilioSMSChannel ||

View file

@ -2,7 +2,12 @@
<div class="wizard-body small-12 medium-9 columns height-auto">
<page-header
: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">
<channel-item
@ -21,12 +26,14 @@ import ChannelItem from 'dashboard/components/widgets/ChannelItem';
import router from '../../../index';
import PageHeader from '../SettingsSubPageHeader';
import { mapGetters } from 'vuex';
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
export default {
components: {
ChannelItem,
PageHeader,
},
mixins: [globalConfigMixin],
data() {
return {
enabledFeatures: {},

View file

@ -43,7 +43,7 @@ class Channel::Telegram < ApplicationRecord
response = HTTParty.get("#{telegram_api_url}/getUserProfilePhotos", query: { user_id: user_id })
return nil unless response.success?
photos = response.parsed_response['result']['photos']
photos = response.parsed_response.dig('result', 'photos')
return if photos.blank?
get_telegram_file_path(photos.first.last['file_id'])

View file

@ -36,15 +36,19 @@ class Channel::Whatsapp < ApplicationRecord
# Extract later into provider Service
def send_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 },
type: 'text'
}.to_json
)
if message.attachments.present?
send_attachment_message(phone_number, message)
else
send_text_message(phone_number, message)
end
end
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
def has_24_hour_messaging_window?
@ -53,6 +57,36 @@ class Channel::Whatsapp < ApplicationRecord
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
def validate_provider_config
response = HTTParty.post(

View file

@ -1,5 +1,5 @@
# Find the various telegram payload samples here: https://core.telegram.org/bots/webhooks#testing-your-bot-with-updates
# https://core.telegram.org/bots/api#available-types
# https://docs.360dialog.com/whatsapp-api/whatsapp-api/media
# https://developers.facebook.com/docs/whatsapp/api/media/
class Whatsapp::IncomingMessageService
pattr_initialize [:inbox!, :params!]
@ -12,7 +12,7 @@ class Whatsapp::IncomingMessageService
return if params[:messages].blank?
@message = @conversation.messages.create(
@message = @conversation.messages.build(
content: params[:messages].first.dig(:text, :body),
account_id: @inbox.account_id,
inbox_id: @inbox.id,
@ -20,6 +20,7 @@ class Whatsapp::IncomingMessageService
sender: @contact,
source_id: params[:messages].first[:id].to_s
)
attach_files
@message.save!
end
@ -58,4 +59,31 @@ class Whatsapp::IncomingMessageService
@conversation = ::Conversation.create!(conversation_params)
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

View file

@ -6,6 +6,6 @@ class Whatsapp::SendOnWhatsappService < Base::SendOnChannelService
end
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

View file

@ -19,7 +19,7 @@ describe ::ContactIdentifyAction do
end
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
described_class.new(contact: contact, params: params).perform
end

BIN
spec/assets/sample.mov Normal file

Binary file not shown.

BIN
spec/assets/sample.mp3 Normal file

Binary file not shown.

BIN
spec/assets/sample.ogg Normal file

Binary file not shown.

198
spec/assets/sample.pdf Normal file
View file

@ -0,0 +1,198 @@
%PDF-1.3
%âãÏÓ
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 KiB

View file

@ -199,6 +199,10 @@ describe ::ContactInboxBuilder do
end
describe 'facebook inbox' do
before do
stub_request(:post, /graph.facebook.com/)
end
let!(:facebook_channel) { create(:channel_facebook_page, account: account) }
let!(:facebook_inbox) { create(:inbox, channel: facebook_channel, account: account) }

View file

@ -3,6 +3,10 @@ require 'rails_helper'
describe ::Messages::Facebook::MessageBuilder do
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!(:message_object) { build(:incoming_fb_text_message).to_json }
let!(:incoming_fb_text_message) { Integrations::Facebook::MessageParser.new(message_object) }
@ -16,7 +20,7 @@ describe ::Messages::Facebook::MessageBuilder do
first_name: 'Jane',
last_name: 'Dae',
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
)
message_builder

View file

@ -3,6 +3,10 @@ require 'rails_helper'
describe ::Messages::Instagram::MessageBuilder do
subject(:instagram_message_builder) { described_class }
before do
stub_request(:post, /graph.facebook.com/)
end
let!(:account) { create(:account) }
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) }
@ -19,7 +23,7 @@ describe ::Messages::Instagram::MessageBuilder do
name: 'Jane',
id: 'Sender-id-1',
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
)
messaging = dm_params[:entry][0]['messaging'][0]

View file

@ -1,16 +1,8 @@
require 'rails_helper'
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
stub_request(:any, /graph.facebook.com/)
# Mock new and return instance doubles defined above
allow(Koala::Facebook::OAuth).to receive(:new).and_return(koala_oauth)
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))
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
context 'when it is an unauthenticated user' do
it 'returns unauthorized' do

View file

@ -4,7 +4,7 @@ FactoryBot.define do
factory :bot_message_card, class: Hash do
title { Faker::Book.name }
description { Faker::Movie.quote }
media_url { 'https://via.placeholder.com/250x250.png' }
media_url { 'https://chatwoot-assets.local/sample.png' }
actions do
[{
text: 'Select',

View file

@ -22,12 +22,12 @@ FactoryBot.define do
'1' => {
id: '1',
name: 'person 1',
profile_image_url: 'https://via.placeholder.com/250x250.png'
profile_image_url: 'https://chatwoot-assets.local/sample.png'
},
'2' => {
id: '1',
name: 'person 1',
profile_image_url: 'https://via.placeholder.com/250x250.png'
profile_image_url: 'https://chatwoot-assets.local/sample.png'
}
}
end

View file

@ -19,6 +19,7 @@ RSpec.describe SendReplyJob, type: :job do
end
it 'calls Facebook::SendOnFacebookService when its facebook message' do
stub_request(:post, /graph.facebook.com/)
facebook_channel = create(:channel_facebook_page)
facebook_inbox = create(:inbox, channel: facebook_channel)
message = create(:message, conversation: create(:conversation, inbox: facebook_inbox))
@ -66,6 +67,7 @@ RSpec.describe SendReplyJob, type: :job do
end
it 'calls ::Whatsapp:SendOnWhatsappService when its line message' do
stub_request(:post, 'https://waba.360dialog.io/v1/configs/webhook')
whatsapp_channel = create(:channel_whatsapp)
message = create(:message, conversation: create(:conversation, inbox: whatsapp_channel.inbox))
allow(::Whatsapp::SendOnWhatsappService).to receive(:new).with(message: message).and_return(process_service)

View file

@ -4,6 +4,10 @@ require 'webhooks/twitter'
describe Webhooks::InstagramEventsJob do
subject(:instagram_webhook) { described_class }
before do
stub_request(:post, /graph.facebook.com/)
end
let!(:account) { create(:account) }
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) }
@ -20,7 +24,7 @@ describe Webhooks::InstagramEventsJob do
name: 'Jane',
id: 'Sender-id-1',
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
)
instagram_webhook.perform_now(dm_params[:entry])
@ -39,7 +43,7 @@ describe Webhooks::InstagramEventsJob do
name: 'Jane',
id: 'Sender-id-1',
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
)
instagram_webhook.perform_now(test_params[:entry])

View file

@ -10,6 +10,14 @@ describe Integrations::Slack::IncomingMessageBuilder do
let!(:hook) { create(:integrations_hook, account: account, reference_id: message_params[:event][:channel]) }
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
context 'when url verification' do
it 'return challenge code as response' do

View file

@ -25,6 +25,10 @@ RSpec.describe AdministratorNotifications::ChannelNotificationsMailer, type: :ma
end
describe 'facebook_disconnect' do
before do
stub_request(:post, /graph.facebook.com/)
end
let!(:facebook_channel) { create(:channel_facebook_page, 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 }

View file

@ -22,6 +22,10 @@ RSpec.describe Campaign, type: :model do
end
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_inbox) { create(:inbox, channel: facebook_channel) }
let(:campaign) { build(:campaign, inbox: facebook_inbox) }

View file

@ -4,6 +4,10 @@ require 'rails_helper'
require Rails.root.join 'spec/models/concerns/reauthorizable_shared.rb'
RSpec.describe Channel::FacebookPage do
before do
stub_request(:post, /graph.facebook.com/)
end
let(:channel) { create(:channel_facebook_page) }
it { is_expected.to validate_presence_of(:account_id) }

View file

@ -394,6 +394,10 @@ RSpec.describe Conversation, type: :model do
end
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_inbox) { create(:inbox, channel: facebook_channel, account: facebook_channel.account) }
let!(:conversation) { create(:conversation, inbox: facebook_inbox, account: facebook_channel.account) }

View file

@ -1,6 +1,10 @@
require 'rails_helper'
describe Contacts::ContactableInboxesService do
before do
stub_request(:post, /graph.facebook.com/)
end
let(:account) { create(:account) }
let(:contact) { create(:contact, account: account, email: 'contact@example.com', phone_number: '+2320000') }
let!(:twilio_sms) { create(:channel_twilio_sms, account: account) }

View file

@ -4,6 +4,7 @@ describe Instagram::SendOnInstagramService do
subject(:send_reply_service) { described_class.new(message: message) }
before do
stub_request(:post, /graph.facebook.com/)
create(:message, message_type: :incoming, inbox: instagram_inbox, account: account, conversation: conversation)
end

View file

@ -1,6 +1,35 @@
require 'rails_helper'
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) }
describe '#perform' do
@ -64,7 +93,7 @@ describe Telegram::IncomingMessageService do
context 'when valid audio messages params' 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 = {
'update_id' => 2_342_342_343_242,
'message' => {
@ -92,7 +121,7 @@ describe Telegram::IncomingMessageService do
context 'when valid image attachment params' 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 = {
'update_id' => 2_342_342_343_242,
'message' => {
@ -117,7 +146,7 @@ describe Telegram::IncomingMessageService do
context 'when valid sticker attachment params' 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 = {
'update_id' => 2_342_342_343_242,
'message' => {
@ -147,7 +176,7 @@ describe Telegram::IncomingMessageService do
context 'when valid video messages params' 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 = {
'update_id' => 2_342_342_343_242,
'message' => {
@ -175,7 +204,7 @@ describe Telegram::IncomingMessageService do
context 'when valid voice attachment params' 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 = {
'update_id' => 2_342_342_343_242,
'message' => {
@ -200,7 +229,7 @@ describe Telegram::IncomingMessageService do
context 'when valid document message params' 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 = {
'update_id' => 2_342_342_343_242,
'message' => {

View file

@ -1,9 +1,13 @@
require 'rails_helper'
describe Whatsapp::IncomingMessageService do
let!(:whatsapp_channel) { create(:channel_whatsapp) }
describe '#perform' do
before do
stub_request(:post, 'https://waba.360dialog.io/v1/configs/webhook')
end
let!(:whatsapp_channel) { create(:channel_whatsapp) }
context 'when valid text message params' do
it 'creates appropriate conversations, message and contacts' do
params = {
@ -17,5 +21,29 @@ describe Whatsapp::IncomingMessageService do
expect(whatsapp_channel.inbox.messages.first.content).to eq('Test')
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

View file

@ -2,6 +2,10 @@ require 'rails_helper'
describe Whatsapp::SendOnWhatsappService do
describe '#perform' do
before do
stub_request(:post, 'https://waba.360dialog.io/v1/configs/webhook')
end
context 'when a valid message' do
it 'calls channel.send_message' do
whatsapp_request = double

View file

@ -2,7 +2,7 @@ require 'simplecov'
require 'webmock/rspec'
SimpleCov.start 'rails'
WebMock.allow_net_connect!
WebMock.disable_net_connect!(allow_localhost: true)
RSpec.configure do |config|
config.expect_with :rspec do |expectations|

View file

@ -78,11 +78,11 @@ module SlackStubs
[
{
mimetype: 'image/png',
url_private: 'https://via.placeholder.com/250x250.png',
url_private: 'https://chatwoot-assets.local/sample.png',
name: 'name_of_the_file',
title: 'title_of_the_file',
filetype: 'png',
url_private_download: 'https://via.placeholder.com/250x250.png'
url_private_download: 'https://chatwoot-assets.local/sample.png'
}
]
end