mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-09 16:46:11 +00:00
This PR improves the voice call creation flow by simplifying configuration and automating setup with Twilio APIs. references: #11602 , #11481 ## Key changes - Removed the requirement for twiml_app_sid – provisioning is now automated through APIs. - Auto-configured webhook URLs for: - Voice number callbacks - Status callbacks - twiML callbacks - Disabled business hours, help center, and related options until voice inbox is fully supported. - Added a configuration tab in the voice inbox to display the required Twilio URLs (to make verification easier in Twilio console). ## Test Cases - Provisioning - Create a new voice inbox → verify that Twilio app provisioning happens automatically. - Verify twiML callback - Webhook configuration - Check that both voice number callback and status callback URLs are auto-populated in Twilio. - Disabled features - Confirm that business hours and help center options are hidden/disabled for voice inbox. - Configuration tab - Open the voice inbox configuration tab → verify that the displayed Twilio URLs match what’s set in Twilio.
89 lines
3.4 KiB
Ruby
89 lines
3.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'rails_helper'
|
|
|
|
RSpec.describe Twilio::VoiceWebhookSetupService do
|
|
let(:account_sid) { 'ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' }
|
|
let(:auth_token) { 'auth_token_123' }
|
|
let(:api_key_sid) { 'SKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' }
|
|
let(:api_key_secret) { 'api_key_secret_123' }
|
|
let(:phone_number) { '+15551230001' }
|
|
let(:frontend_url) { 'https://app.chatwoot.test' }
|
|
|
|
let(:channel) do
|
|
build(:channel_voice, phone_number: phone_number, provider_config: {
|
|
account_sid: account_sid,
|
|
auth_token: auth_token,
|
|
api_key_sid: api_key_sid,
|
|
api_key_secret: api_key_secret
|
|
})
|
|
end
|
|
|
|
let(:twilio_base_url) { "https://api.twilio.com/2010-04-01/Accounts/#{account_sid}" }
|
|
let(:incoming_numbers_url) { "#{twilio_base_url}/IncomingPhoneNumbers.json" }
|
|
let(:applications_url) { "#{twilio_base_url}/Applications.json" }
|
|
let(:phone_number_sid) { 'PN123' }
|
|
let(:phone_number_url) { "#{twilio_base_url}/IncomingPhoneNumbers/#{phone_number_sid}.json" }
|
|
|
|
before do
|
|
# Token validation using Account SID + Auth Token
|
|
stub_request(:get, /#{Regexp.escape(incoming_numbers_url)}.*/)
|
|
.with(basic_auth: [account_sid, auth_token])
|
|
.to_return(status: 200,
|
|
body: { incoming_phone_numbers: [], meta: { key: 'incoming_phone_numbers' } }.to_json,
|
|
headers: { 'Content-Type' => 'application/json' })
|
|
|
|
# Number lookup using API Key SID/Secret
|
|
stub_request(:get, /#{Regexp.escape(incoming_numbers_url)}.*/)
|
|
.with(basic_auth: [api_key_sid, api_key_secret])
|
|
.to_return(status: 200,
|
|
body: { incoming_phone_numbers: [{ sid: phone_number_sid }], meta: { key: 'incoming_phone_numbers' } }.to_json,
|
|
headers: { 'Content-Type' => 'application/json' })
|
|
|
|
# TwiML App create (voice only)
|
|
stub_request(:post, applications_url)
|
|
.with(basic_auth: [api_key_sid, api_key_secret])
|
|
.to_return(status: 201,
|
|
body: { sid: 'AP123' }.to_json,
|
|
headers: { 'Content-Type' => 'application/json' })
|
|
|
|
# Incoming Phone Number webhook update
|
|
stub_request(:post, phone_number_url)
|
|
.with(basic_auth: [api_key_sid, api_key_secret])
|
|
.to_return(status: 200,
|
|
body: { sid: phone_number_sid }.to_json,
|
|
headers: { 'Content-Type' => 'application/json' })
|
|
end
|
|
|
|
it 'creates a TwiML App and configures number webhooks with correct URLs' do
|
|
with_modified_env FRONTEND_URL: frontend_url do
|
|
service = described_class.new(channel: channel)
|
|
sid = service.perform
|
|
|
|
expect(sid).to eq('AP123')
|
|
|
|
expected_voice_url = channel.voice_call_webhook_url
|
|
expected_status_url = channel.voice_status_webhook_url
|
|
|
|
# Assert TwiML App creation body includes voice URL and POST method
|
|
expect(
|
|
a_request(:post, applications_url)
|
|
.with(body: hash_including('VoiceUrl' => expected_voice_url, 'VoiceMethod' => 'POST'))
|
|
).to have_been_made
|
|
|
|
# Assert number webhook update body includes both URLs and POST methods
|
|
expect(
|
|
a_request(:post, phone_number_url)
|
|
.with(
|
|
body: hash_including(
|
|
'VoiceUrl' => expected_voice_url,
|
|
'VoiceMethod' => 'POST',
|
|
'StatusCallback' => expected_status_url,
|
|
'StatusCallbackMethod' => 'POST'
|
|
)
|
|
)
|
|
).to have_been_made
|
|
end
|
|
end
|
|
end
|