From 881de008a78465dee98b79629c182c0ea564f71e Mon Sep 17 00:00:00 2001 From: David Wilkie Date: Tue, 9 Jul 2024 21:25:29 +0700 Subject: [PATCH] WIP --- components/app/app/workflows/execute_dial.rb | 36 ++-- components/app/lib/call_platform/client.rb | 4 - .../app/spec/call_controllers/dial_spec.rb | 81 +++++---- .../build_multiple_routing_parameters.yml | 162 ------------------ .../build_routing_parameters.yml | 56 ------ ...uting_parameters_with_national_dialing.yml | 56 ------ ..._parameters_without_symmetric_latching.yml | 56 ------ .../fixtures/vcr_cassettes/dial_multiple.yml | 55 ++++++ .../dial_multiple_with_caller_id.yml | 54 ++++++ .../spec/fixtures/vcr_cassettes/dial_sip.yml | 54 ++++++ .../vcr_cassettes/dial_with_caller_id.yml | 54 ++++++ .../dial_with_national_dialing.yml | 55 ++++++ .../dial_without_symmetric_latching.yml | 54 ++++++ .../app/spec/workflows/execute_dial_spec.rb | 64 ------- 14 files changed, 390 insertions(+), 451 deletions(-) delete mode 100644 components/app/spec/fixtures/vcr_cassettes/build_multiple_routing_parameters.yml delete mode 100644 components/app/spec/fixtures/vcr_cassettes/build_routing_parameters.yml delete mode 100644 components/app/spec/fixtures/vcr_cassettes/build_routing_parameters_with_national_dialing.yml delete mode 100644 components/app/spec/fixtures/vcr_cassettes/build_routing_parameters_without_symmetric_latching.yml create mode 100644 components/app/spec/fixtures/vcr_cassettes/dial_multiple.yml create mode 100644 components/app/spec/fixtures/vcr_cassettes/dial_multiple_with_caller_id.yml create mode 100644 components/app/spec/fixtures/vcr_cassettes/dial_sip.yml create mode 100644 components/app/spec/fixtures/vcr_cassettes/dial_with_caller_id.yml create mode 100644 components/app/spec/fixtures/vcr_cassettes/dial_with_national_dialing.yml create mode 100644 components/app/spec/fixtures/vcr_cassettes/dial_without_symmetric_latching.yml delete mode 100644 components/app/spec/workflows/execute_dial_spec.rb diff --git a/components/app/app/workflows/execute_dial.rb b/components/app/app/workflows/execute_dial.rb index e0480a847..e88b95bdc 100644 --- a/components/app/app/workflows/execute_dial.rb +++ b/components/app/app/workflows/execute_dial.rb @@ -12,15 +12,25 @@ class ExecuteDial < ExecuteTwiMLVerb def call answer! phone_calls = create_outbound_calls - dial_status = context.dial(build_dial_params(phone_calls)) + dial_params = build_dial_params(phone_calls) + dial_status = context.dial(dial_params) return if verb.action.blank? - redirect(build_callback_params(dial_status)) + callback_params = build_callback_params(dial_status) + redirect(callback_params) end private + def create_outbound_calls + call_platform_client.create_outbound_calls( + destinations: verb.nested_nouns.map { |nested_noun| nested_noun.content.strip }, + parent_call_sid: call_properties.call_sid, + from: verb.caller_id + ) + end + def build_dial_params(phone_calls) phone_calls.each_with_object({}) do |phone_call, result| dial_string, from = build_dial_string(phone_call) @@ -36,12 +46,13 @@ def build_dial_params(phone_calls) end end - def create_outbound_calls - call_platform_client.create_outbound_calls( - destinations: verb.nested_nouns.map { |nested_noun| nested_noun.content.strip }, - parent_call_sid: call_properties.call_sid, - from: verb.caller_id - ) + def build_dial_string(phone_call_response) + if phone_call_response.address.present? + DialString.new(address: phone_call_response.address) + else + dial_string = DialString.new(phone_call_response.routing_parameters) + [ dial_string, dial_string.format_number(phone_call_response.from) ] + end end def redirect(params) @@ -72,13 +83,4 @@ def find_joined_call(dial_status) return outbound_call if join_status.result == :joined end end - - def build_dial_string(phone_call_response) - if phone_call_response.address.present? - DialString.new(address: phone_call_response.address) - else - dial_string = DialString.new(phone_call_response.routing_parameters) - [ dial_string, dial_string.format_number(phone_call_response.from) ] - end - end end diff --git a/components/app/lib/call_platform/client.rb b/components/app/lib/call_platform/client.rb index 236229b59..47ef4ffd1 100644 --- a/components/app/lib/call_platform/client.rb +++ b/components/app/lib/call_platform/client.rb @@ -59,10 +59,6 @@ def notify_media_stream_event(params) notify_request("/services/media_stream_events", params) end - def build_routing_parameters(params) - make_request("/services/routing_parameters", params: params) - end - def create_inbound_call(params) json_response = make_request("/services/inbound_phone_calls", params: params) InboundPhoneCallResponse.new( diff --git a/components/app/spec/call_controllers/dial_spec.rb b/components/app/spec/call_controllers/dial_spec.rb index 492789d65..e91c54138 100644 --- a/components/app/spec/call_controllers/dial_spec.rb +++ b/components/app/spec/call_controllers/dial_spec.rb @@ -2,6 +2,8 @@ RSpec.describe CallController, type: :call_controller do describe "" do + let(:parent_call_sid) { "15f55641-7728-4cab-8e2e-8077c4b3c6b4" } # From VCR cassette + # From: https://www.twilio.com/docs/api/twiml/dial # The verb connects the current caller to another phone. @@ -29,10 +31,7 @@ controller = build_controller( stub_voice_commands: [ :play_audio, { dial: build_dial_status } ], call_properties: { - account_sid: "96b4557a-341c-46b3-ba3c-a1793e9dae3c", - call_sid: "15f55641-7728-4cab-8e2e-8077c4b3c6b4", - from: "855715100860", - direction: "inbound" + call_sid: parent_call_sid } ) @@ -48,19 +47,24 @@ expect(controller).to have_received(:dial).with( include( - dial_string("85516701721") => { for: 30.seconds, from: "855715100860" } + dial_string("85516701721") => hash_including( + for: 30.seconds, + from: match(/\A855/), + headers: hash_including( + "X-Somleng-CallSid" => be_present, + "X-Somleng-AccountSid" => be_present + ) + ) ) ) expect(controller).to have_received(:play_audio).with("foo.mp3") end - it "handles national dialing", :vcr, cassette: :build_routing_parameters_with_national_dialing do + it "handles national dialing", :vcr, cassette: :dial_with_national_dialing do controller = build_controller( stub_voice_commands: [ :play_audio, { dial: build_dial_status } ], call_properties: { - account_sid: "ea471a9f-d4b3-4035-966e-f507b8da6d34", - to: "855715100860", - direction: "outbound-api" + call_sid: parent_call_sid } ) @@ -75,16 +79,16 @@ expect(controller).to have_received(:dial).with( include( - dial_string("016701721") => hash_including(from: "0715100860") + dial_string("016701721") => hash_including(from: match(/\A0/)) ) ) end - it "handles numbers without symmetric latching support", :vcr, cassette: :build_routing_parameters_without_symmetric_latching do + it "handles numbers without symmetric latching support", :vcr, cassette: :dial_without_symmetric_latching do controller = build_controller( stub_voice_commands: [ { dial: build_dial_status } ], call_properties: { - account_sid: "ea471a9f-d4b3-4035-966e-f507b8da6d34" + call_sid: parent_call_sid } ) @@ -104,13 +108,11 @@ ) end - it "dials to ", :vcr, cassette: :build_multiple_routing_parameters do + it "dials to ", :vcr, cassette: :dial_multiple do controller = build_controller( stub_voice_commands: { dial: build_dial_status }, call_properties: { - account_sid: "ea471a9f-d4b3-4035-966e-f507b8da6d34", - from: "855715200860", - direction: "inbound" + call_sid: parent_call_sid } ) @@ -129,19 +131,19 @@ expect(controller).to have_received(:dial).with( include( - dial_string("85516701721") => hash_including(from: "855715200860"), - dial_string("0715100860", profile: "alternative-outbound") => hash_including(from: "0715200860"), - dial_string("85510555777") => hash_including(from: "855715200860") + dial_string("85516701721") => hash_including(from: match(/\A855/),), + dial_string("0715100860", profile: "alternative-outbound") => hash_including(from: match(/\A0/)), + dial_string("85510555777") => hash_including(from: match(/\A855/)) ), any_args ) end - it "dials to " do + it "dials to ", :vcr, cassette: :dial_sip do controller = build_controller( stub_voice_commands: { dial: build_dial_status }, call_properties: { - account_sid: "ea471a9f-d4b3-4035-966e-f507b8da6d34" + call_sid: parent_call_sid } ) @@ -158,14 +160,17 @@ expect(controller).to have_received(:dial).with( include( - "sofia/external/alice@sip.example.com" => { for: 30.seconds } + "sofia/external/alice@sip.example.com" => hash_including(for: 30.seconds, headers: be_a_kind_of(Hash)) ) ) end - it "supports callerId", :vcr, cassette: :build_multiple_routing_parameters do + it "supports callerId", :vcr, cassette: :dial_multiple_with_caller_id do controller = build_controller( - stub_voice_commands: { dial: build_dial_status } + stub_voice_commands: { dial: build_dial_status }, + call_properties: { + call_sid: parent_call_sid + } ) stub_twiml_request(controller, response: <<~TWIML) @@ -251,7 +256,7 @@ # | | a properly formatted but non-existent phone number. | # | canceled | The call was canceled via the REST API before it was answered. | - it "POSTS to the action url", :vcr, cassette: :build_routing_parameters do + it "POSTS to the action url", :vcr, cassette: :dial do outbound_call = build_outbound_call(id: "481f77b9-a95b-4c6a-bbb1-23afcc42c959") joins_status = build_dial_join_status(:joined, duration: 23.7) @@ -284,7 +289,7 @@ }) end - it "handles multiple calls", :vcr, cassette: :build_multiple_routing_parameters do + it "handles multiple calls", :vcr, cassette: :dial_multiple do joined_outbound_call = build_outbound_call(id: "481f77b9-a95b-4c6a-bbb1-23afcc42c959") no_answer_outbound_call = build_outbound_call @@ -334,7 +339,7 @@ # This attribute is modeled after the HTML form 'method' attribute. # 'POST' is the default value. - it "executes a GET request", :vcr, cassette: :build_routing_parameters do + it "executes a GET request", :vcr, cassette: :dial do controller = build_controller( stub_voice_commands: { dial: build_dial_status } ) @@ -389,15 +394,18 @@ # | callerId | a valid phone number, or client identifier | Caller's callerId | # | | if you are dialing a . | | - it "sets the callerId", :vcr, cassette: :build_routing_parameters do + it "sets the callerId", :vcr, cassette: :dial_with_caller_id do controller = build_controller( - stub_voice_commands: { dial: build_dial_status } + stub_voice_commands: { dial: build_dial_status }, + call_properties: { + call_sid: parent_call_sid + } ) stub_twiml_request(controller, response: <<~TWIML) - +85516701721 + +85516701721 TWIML @@ -405,14 +413,14 @@ expect(controller).to have_received(:dial).with( include( - dial_string("85516701721") => hash_including(from: "2442") + dial_string("85516701721") => hash_including(from: "85523238265") ) ) end end describe "timeout" do - it "handles timeout", :vcr, cassette: :build_multiple_routing_parameters do + it "handles timeout", :vcr, cassette: :dial_multiple do controller = build_controller( stub_voice_commands: { dial: build_dial_status } ) @@ -435,16 +443,17 @@ end end - def build_dial_status(result = :answer, joins: {}) - instance_double(Adhearsion::CallController::DialStatus, result:, joins:) + def build_dial_status(result = :answer, joins: {}, calls: Set.new) + calls << build_outbound_call if calls.empty? + instance_double(Adhearsion::CallController::DialStatus, result:, joins:, calls:) end def build_dial_join_status(result = :joined, options = {}) instance_double(Adhearsion::CallController::Dial::JoinStatus, result:, **options) end - def build_outbound_call(options = {}) - instance_double(Adhearsion::OutboundCall, options) + def build_outbound_call(**options) + instance_double(Adhearsion::OutboundCall, id: SecureRandom.uuid, **options) end def dial_string(number, profile: :external) diff --git a/components/app/spec/fixtures/vcr_cassettes/build_multiple_routing_parameters.yml b/components/app/spec/fixtures/vcr_cassettes/build_multiple_routing_parameters.yml deleted file mode 100644 index 26f95cad1..000000000 --- a/components/app/spec/fixtures/vcr_cassettes/build_multiple_routing_parameters.yml +++ /dev/null @@ -1,162 +0,0 @@ ---- -http_interactions: -- request: - method: post - uri: http://api.lvh.me:3000/services/routing_parameters - body: - encoding: UTF-8 - string: '{"phone_number":"85516701721","account_sid":"ea471a9f-d4b3-4035-966e-f507b8da6d34"}' - headers: - Accept: - - application/json - Content-Type: - - application/json - Authorization: - - Basic c2VydmljZXM6cGFzc3dvcmQ= - User-Agent: - - Faraday v1.4.1 - Accept-Encoding: - - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 - response: - status: - code: 201 - message: Created - headers: - X-Frame-Options: - - SAMEORIGIN - X-Xss-Protection: - - '0' - X-Content-Type-Options: - - nosniff - X-Download-Options: - - noopen - X-Permitted-Cross-Domain-Policies: - - none - Referrer-Policy: - - strict-origin-when-cross-origin - Content-Type: - - application/vnd.api+json; charset=utf-8 - Etag: - - W/"6b3b0e604a2f060346e5e9d66ba27359" - Cache-Control: - - max-age=0, private, must-revalidate - X-Request-Id: - - 36b9f46f-5701-4626-93a6-9aee331a32d5 - X-Runtime: - - '0.018712' - Server-Timing: - - start_processing.action_controller;dur=0.208984375, sql.active_record;dur=2.351806640625, - instantiation.active_record;dur=0.300048828125, process_action.action_controller;dur=5.954833984375 - Transfer-Encoding: - - chunked - body: - encoding: UTF-8 - string: '{"destination":"85516701721","dial_string_prefix":null,"plus_prefix":false,"national_dialing":false,"host":"host.docker.internal:5061","username":null,"symmetric_latching":true}' - recorded_at: Fri, 23 Sep 2022 06:27:36 GMT -- request: - method: post - uri: http://api.lvh.me:3000/services/routing_parameters - body: - encoding: UTF-8 - string: '{"phone_number":"855715100860","account_sid":"ea471a9f-d4b3-4035-966e-f507b8da6d34"}' - headers: - Accept: - - application/json - Content-Type: - - application/json - Authorization: - - Basic c2VydmljZXM6cGFzc3dvcmQ= - User-Agent: - - Faraday v1.4.1 - Accept-Encoding: - - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 - response: - status: - code: 201 - message: Created - headers: - X-Frame-Options: - - SAMEORIGIN - X-Xss-Protection: - - '0' - X-Content-Type-Options: - - nosniff - X-Download-Options: - - noopen - X-Permitted-Cross-Domain-Policies: - - none - Referrer-Policy: - - strict-origin-when-cross-origin - Content-Type: - - application/vnd.api+json; charset=utf-8 - Etag: - - W/"d030e55792b2532e09f07ebd758b1ad4" - Cache-Control: - - max-age=0, private, must-revalidate - X-Request-Id: - - a81dfb14-526b-44aa-9f45-8c2772eac861 - X-Runtime: - - '0.018729' - Server-Timing: - - start_processing.action_controller;dur=0.18798828125, sql.active_record;dur=3.088134765625, - instantiation.active_record;dur=0.2841796875, process_action.action_controller;dur=5.993896484375 - Transfer-Encoding: - - chunked - body: - encoding: UTF-8 - string: '{"destination":"855715100860","dial_string_prefix":null,"plus_prefix":false,"national_dialing":true,"host":"host.docker.internal:5061","username":null,"symmetric_latching":false}' - recorded_at: Fri, 23 Sep 2022 06:27:36 GMT -- request: - method: post - uri: http://api.lvh.me:3000/services/routing_parameters - body: - encoding: UTF-8 - string: '{"phone_number":"85510555777","account_sid":"ea471a9f-d4b3-4035-966e-f507b8da6d34"}' - headers: - Accept: - - application/json - Content-Type: - - application/json - Authorization: - - Basic c2VydmljZXM6cGFzc3dvcmQ= - User-Agent: - - Faraday v1.4.1 - Accept-Encoding: - - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 - response: - status: - code: 201 - message: Created - headers: - X-Frame-Options: - - SAMEORIGIN - X-Xss-Protection: - - '0' - X-Content-Type-Options: - - nosniff - X-Download-Options: - - noopen - X-Permitted-Cross-Domain-Policies: - - none - Referrer-Policy: - - strict-origin-when-cross-origin - Content-Type: - - application/vnd.api+json; charset=utf-8 - Etag: - - W/"5435b6344a62d55ffb20194df8a94139" - Cache-Control: - - max-age=0, private, must-revalidate - X-Request-Id: - - 737f06e9-eca6-4e62-9ea6-83696dc71404 - X-Runtime: - - '0.021020' - Server-Timing: - - start_processing.action_controller;dur=0.218017578125, sql.active_record;dur=3.67236328125, - instantiation.active_record;dur=0.387939453125, process_action.action_controller;dur=7.1328125 - Transfer-Encoding: - - chunked - body: - encoding: UTF-8 - string: '{"destination":"85510555777","dial_string_prefix":null,"plus_prefix":false,"national_dialing":false,"host":"host.docker.internal:5061","username":null,"symmetric_latching":true}' - recorded_at: Fri, 23 Sep 2022 06:27:36 GMT -recorded_with: VCR 6.0.0 diff --git a/components/app/spec/fixtures/vcr_cassettes/build_routing_parameters.yml b/components/app/spec/fixtures/vcr_cassettes/build_routing_parameters.yml deleted file mode 100644 index 6c9d4c933..000000000 --- a/components/app/spec/fixtures/vcr_cassettes/build_routing_parameters.yml +++ /dev/null @@ -1,56 +0,0 @@ ---- -http_interactions: -- request: - method: post - uri: http://api.lvh.me:3000/services/routing_parameters - body: - encoding: UTF-8 - string: '{"phone_number":"85516701721","account_sid":"ea471a9f-d4b3-4035-966e-f507b8da6d34"}' - headers: - Accept: - - application/json - Content-Type: - - application/json - Authorization: - - Basic c2VydmljZXM6cGFzc3dvcmQ= - User-Agent: - - Faraday v1.4.1 - Accept-Encoding: - - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 - response: - status: - code: 201 - message: Created - headers: - X-Frame-Options: - - SAMEORIGIN - X-Xss-Protection: - - '0' - X-Content-Type-Options: - - nosniff - X-Download-Options: - - noopen - X-Permitted-Cross-Domain-Policies: - - none - Referrer-Policy: - - strict-origin-when-cross-origin - Content-Type: - - application/vnd.api+json; charset=utf-8 - Etag: - - W/"6b3b0e604a2f060346e5e9d66ba27359" - Cache-Control: - - max-age=0, private, must-revalidate - X-Request-Id: - - b5c1cc26-7e43-4cbf-956d-431e76ad3aac - X-Runtime: - - '0.026926' - Server-Timing: - - start_processing.action_controller;dur=0.157958984375, sql.active_record;dur=2.203857421875, - instantiation.active_record;dur=0.25244140625, process_action.action_controller;dur=13.60009765625 - Transfer-Encoding: - - chunked - body: - encoding: UTF-8 - string: '{"destination":"85516701721","dial_string_prefix":null,"plus_prefix":false,"national_dialing":false,"host":"host.docker.internal:5061","username":null,"symmetric_latching":true}' - recorded_at: Fri, 23 Sep 2022 06:27:36 GMT -recorded_with: VCR 6.0.0 diff --git a/components/app/spec/fixtures/vcr_cassettes/build_routing_parameters_with_national_dialing.yml b/components/app/spec/fixtures/vcr_cassettes/build_routing_parameters_with_national_dialing.yml deleted file mode 100644 index d0260727f..000000000 --- a/components/app/spec/fixtures/vcr_cassettes/build_routing_parameters_with_national_dialing.yml +++ /dev/null @@ -1,56 +0,0 @@ ---- -http_interactions: -- request: - method: post - uri: http://api.lvh.me:3000/services/routing_parameters - body: - encoding: UTF-8 - string: '{"phone_number":"85516701721","account_sid":"ea471a9f-d4b3-4035-966e-f507b8da6d34"}' - headers: - Accept: - - application/json - Content-Type: - - application/json - Authorization: - - Basic c2VydmljZXM6cGFzc3dvcmQ= - User-Agent: - - Faraday v1.4.1 - Accept-Encoding: - - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 - response: - status: - code: 201 - message: Created - headers: - X-Frame-Options: - - SAMEORIGIN - X-Xss-Protection: - - '0' - X-Content-Type-Options: - - nosniff - X-Download-Options: - - noopen - X-Permitted-Cross-Domain-Policies: - - none - Referrer-Policy: - - strict-origin-when-cross-origin - Content-Type: - - application/vnd.api+json; charset=utf-8 - Etag: - - W/"6b3b0e604a2f060346e5e9d66ba27359" - Cache-Control: - - max-age=0, private, must-revalidate - X-Request-Id: - - b5c1cc26-7e43-4cbf-956d-431e76ad3aac - X-Runtime: - - '0.026926' - Server-Timing: - - start_processing.action_controller;dur=0.157958984375, sql.active_record;dur=2.203857421875, - instantiation.active_record;dur=0.25244140625, process_action.action_controller;dur=13.60009765625 - Transfer-Encoding: - - chunked - body: - encoding: UTF-8 - string: '{"destination":"85516701721","dial_string_prefix":null,"plus_prefix":false,"national_dialing":true,"host":"host.docker.internal:5061","username":null,"symmetric_latching":true}' - recorded_at: Fri, 23 Sep 2022 06:27:36 GMT -recorded_with: VCR 6.0.0 diff --git a/components/app/spec/fixtures/vcr_cassettes/build_routing_parameters_without_symmetric_latching.yml b/components/app/spec/fixtures/vcr_cassettes/build_routing_parameters_without_symmetric_latching.yml deleted file mode 100644 index f50057e4b..000000000 --- a/components/app/spec/fixtures/vcr_cassettes/build_routing_parameters_without_symmetric_latching.yml +++ /dev/null @@ -1,56 +0,0 @@ ---- -http_interactions: -- request: - method: post - uri: http://api.lvh.me:3000/services/routing_parameters - body: - encoding: UTF-8 - string: '{"phone_number":"85516701721","account_sid":"ea471a9f-d4b3-4035-966e-f507b8da6d34"}' - headers: - Accept: - - application/json - Content-Type: - - application/json - Authorization: - - Basic c2VydmljZXM6cGFzc3dvcmQ= - User-Agent: - - Faraday v1.4.1 - Accept-Encoding: - - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 - response: - status: - code: 201 - message: Created - headers: - X-Frame-Options: - - SAMEORIGIN - X-Xss-Protection: - - '0' - X-Content-Type-Options: - - nosniff - X-Download-Options: - - noopen - X-Permitted-Cross-Domain-Policies: - - none - Referrer-Policy: - - strict-origin-when-cross-origin - Content-Type: - - application/vnd.api+json; charset=utf-8 - Etag: - - W/"21103aaeb76a9e3ee988d8273a166fc7" - Cache-Control: - - max-age=0, private, must-revalidate - X-Request-Id: - - 8efc63c7-a871-4ecd-80ac-ae87b1539748 - X-Runtime: - - '0.019747' - Server-Timing: - - start_processing.action_controller;dur=0.177001953125, sql.active_record;dur=2.358154296875, - instantiation.active_record;dur=0.3193359375, process_action.action_controller;dur=5.7978515625 - Transfer-Encoding: - - chunked - body: - encoding: UTF-8 - string: '{"destination":"85516701721","dial_string_prefix":null,"plus_prefix":false,"national_dialing":true,"host":"host.docker.internal:5061","username":null,"symmetric_latching":false}' - recorded_at: Fri, 23 Sep 2022 06:26:42 GMT -recorded_with: VCR 6.0.0 diff --git a/components/app/spec/fixtures/vcr_cassettes/dial_multiple.yml b/components/app/spec/fixtures/vcr_cassettes/dial_multiple.yml new file mode 100644 index 000000000..2c0427197 --- /dev/null +++ b/components/app/spec/fixtures/vcr_cassettes/dial_multiple.yml @@ -0,0 +1,55 @@ +--- +http_interactions: +- request: + method: post + uri: http://api.lvh.me:3000/services/outbound_phone_calls + body: + encoding: UTF-8 + string: '{"destinations":["85516701721","855715100860","85510555777"],"parent_call_sid":"15f55641-7728-4cab-8e2e-8077c4b3c6b4"}' + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Faraday v2.10.0 + Authorization: + - Basic c2VydmljZXM6cGFzc3dvcmQ= + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 201 + message: Created + headers: + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - '0' + X-Content-Type-Options: + - nosniff + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + Content-Type: + - application/vnd.api+json; charset=utf-8 + Etag: + - W/"38f72f1a8b5aded3d225b4950b9c105a" + Cache-Control: + - max-age=0, private, must-revalidate + X-Request-Id: + - bce2f08f-7b20-41ed-817f-fdd6875d921f + X-Runtime: + - '0.164603' + Server-Timing: + - start_processing.action_controller;dur=0.00, sql.active_record;dur=35.18, + instantiation.active_record;dur=11.74, transaction.active_record;dur=5.87, + process_action.action_controller;dur=89.19 + Content-Length: + - '1419' + body: + encoding: UTF-8 + string: '{"phone_calls":[{"created_at":"2024-07-09T06:44:47Z","updated_at":"2024-07-09T06:44:47Z","sid":"43d53a33-0965-427e-ba86-6ba79f90a0bf","parent_call_sid":"15f55641-7728-4cab-8e2e-8077c4b3c6b4","account_sid":"96b4557a-341c-46b3-ba3c-a1793e9dae3c","from":"+855715100678","routing_parameters":{"destination":"+85516701721","dial_string_prefix":null,"plus_prefix":false,"national_dialing":false,"host":"host.docker.internal:5061","username":null,"symmetric_latching":true},"address":null},{"created_at":"2024-07-09T06:44:47Z","updated_at":"2024-07-09T06:44:47Z","sid":"b94fbd47-7900-45eb-aff7-e2892b572afc","parent_call_sid":"15f55641-7728-4cab-8e2e-8077c4b3c6b4","account_sid":"96b4557a-341c-46b3-ba3c-a1793e9dae3c","from":"+855715100678","routing_parameters":{"destination":"+855715100860","dial_string_prefix":null,"plus_prefix":false,"national_dialing":true,"host":"host.docker.internal:5061","username":null,"symmetric_latching":false},"address":null},{"created_at":"2024-07-09T06:44:47Z","updated_at":"2024-07-09T06:44:47Z","sid":"64c0f12c-5181-4267-9fa7-2c3bcfa0e10e","parent_call_sid":"15f55641-7728-4cab-8e2e-8077c4b3c6b4","account_sid":"96b4557a-341c-46b3-ba3c-a1793e9dae3c","from":"+855715100678","routing_parameters":{"destination":"+85510555777","dial_string_prefix":null,"plus_prefix":false,"national_dialing":false,"host":"host.docker.internal:5061","username":null,"symmetric_latching":true},"address":null}]}' + recorded_at: Tue, 09 Jul 2024 06:44:47 GMT +recorded_with: VCR 6.2.0 diff --git a/components/app/spec/fixtures/vcr_cassettes/dial_multiple_with_caller_id.yml b/components/app/spec/fixtures/vcr_cassettes/dial_multiple_with_caller_id.yml new file mode 100644 index 000000000..e20d76464 --- /dev/null +++ b/components/app/spec/fixtures/vcr_cassettes/dial_multiple_with_caller_id.yml @@ -0,0 +1,54 @@ +--- +http_interactions: +- request: + method: post + uri: http://api.lvh.me:3000/services/outbound_phone_calls + body: + encoding: UTF-8 + string: '{"destinations":["85516701721","855715100860","85510555777"],"parent_call_sid":"15f55641-7728-4cab-8e2e-8077c4b3c6b4","from":"85523238265"}' + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Faraday v2.10.0 + Authorization: + - Basic c2VydmljZXM6cGFzc3dvcmQ= + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 201 + message: Created + headers: + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - '0' + X-Content-Type-Options: + - nosniff + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + Content-Type: + - application/vnd.api+json; charset=utf-8 + Etag: + - W/"324c73376115215abece5d60d7a737a0" + Cache-Control: + - max-age=0, private, must-revalidate + X-Request-Id: + - 0f3587c8-8b2a-4644-8ba9-c351be8a8cac + X-Runtime: + - '0.036188' + Server-Timing: + - start_processing.action_controller;dur=0.00, sql.active_record;dur=8.08, instantiation.active_record;dur=0.45, + transaction.active_record;dur=8.83, process_action.action_controller;dur=20.12 + Content-Length: + - '1416' + body: + encoding: UTF-8 + string: '{"phone_calls":[{"created_at":"2024-07-09T06:54:28Z","updated_at":"2024-07-09T06:54:28Z","sid":"c95a70b5-cd82-41f3-b4f7-fcc7177fe1be","parent_call_sid":"15f55641-7728-4cab-8e2e-8077c4b3c6b4","account_sid":"96b4557a-341c-46b3-ba3c-a1793e9dae3c","from":"+85523238265","routing_parameters":{"destination":"+85516701721","dial_string_prefix":null,"plus_prefix":false,"national_dialing":false,"host":"host.docker.internal:5061","username":null,"symmetric_latching":true},"address":null},{"created_at":"2024-07-09T06:54:28Z","updated_at":"2024-07-09T06:54:28Z","sid":"56e87b91-a5cc-4fda-a0f4-7db3a259c0d7","parent_call_sid":"15f55641-7728-4cab-8e2e-8077c4b3c6b4","account_sid":"96b4557a-341c-46b3-ba3c-a1793e9dae3c","from":"+85523238265","routing_parameters":{"destination":"+855715100860","dial_string_prefix":null,"plus_prefix":false,"national_dialing":true,"host":"host.docker.internal:5061","username":null,"symmetric_latching":false},"address":null},{"created_at":"2024-07-09T06:54:28Z","updated_at":"2024-07-09T06:54:28Z","sid":"43daf827-46f6-4957-aad4-a09f2723653e","parent_call_sid":"15f55641-7728-4cab-8e2e-8077c4b3c6b4","account_sid":"96b4557a-341c-46b3-ba3c-a1793e9dae3c","from":"+85523238265","routing_parameters":{"destination":"+85510555777","dial_string_prefix":null,"plus_prefix":false,"national_dialing":false,"host":"host.docker.internal:5061","username":null,"symmetric_latching":true},"address":null}]}' + recorded_at: Tue, 09 Jul 2024 06:54:28 GMT +recorded_with: VCR 6.2.0 diff --git a/components/app/spec/fixtures/vcr_cassettes/dial_sip.yml b/components/app/spec/fixtures/vcr_cassettes/dial_sip.yml new file mode 100644 index 000000000..e345f94ed --- /dev/null +++ b/components/app/spec/fixtures/vcr_cassettes/dial_sip.yml @@ -0,0 +1,54 @@ +--- +http_interactions: +- request: + method: post + uri: http://api.lvh.me:3000/services/outbound_phone_calls + body: + encoding: UTF-8 + string: '{"destinations":["sip:alice@sip.example.com"],"parent_call_sid":"15f55641-7728-4cab-8e2e-8077c4b3c6b4"}' + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Faraday v2.10.0 + Authorization: + - Basic c2VydmljZXM6cGFzc3dvcmQ= + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 201 + message: Created + headers: + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - '0' + X-Content-Type-Options: + - nosniff + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + Content-Type: + - application/vnd.api+json; charset=utf-8 + Etag: + - W/"7078d81644cbb895b788a8a8b92b7f18" + Cache-Control: + - max-age=0, private, must-revalidate + X-Request-Id: + - '05109ee5-bb52-4a45-b6b3-d898759922d8' + X-Runtime: + - '0.023853' + Server-Timing: + - start_processing.action_controller;dur=0.00, sql.active_record;dur=2.68, instantiation.active_record;dur=0.21, + transaction.active_record;dur=1.95, process_action.action_controller;dur=7.23 + Content-Length: + - '329' + body: + encoding: UTF-8 + string: '{"phone_calls":[{"created_at":"2024-07-09T06:48:33Z","updated_at":"2024-07-09T06:48:33Z","sid":"b88d99e8-68b5-4d03-9d50-c8104e095c11","parent_call_sid":"15f55641-7728-4cab-8e2e-8077c4b3c6b4","account_sid":"96b4557a-341c-46b3-ba3c-a1793e9dae3c","from":"+855715100678","routing_parameters":null,"address":"alice@sip.example.com"}]}' + recorded_at: Tue, 09 Jul 2024 06:48:33 GMT +recorded_with: VCR 6.2.0 diff --git a/components/app/spec/fixtures/vcr_cassettes/dial_with_caller_id.yml b/components/app/spec/fixtures/vcr_cassettes/dial_with_caller_id.yml new file mode 100644 index 000000000..3ab316670 --- /dev/null +++ b/components/app/spec/fixtures/vcr_cassettes/dial_with_caller_id.yml @@ -0,0 +1,54 @@ +--- +http_interactions: +- request: + method: post + uri: http://api.lvh.me:3000/services/outbound_phone_calls + body: + encoding: UTF-8 + string: '{"destinations":["+85516701721"],"parent_call_sid":"15f55641-7728-4cab-8e2e-8077c4b3c6b4","from":"85523238265"}' + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Faraday v2.10.0 + Authorization: + - Basic c2VydmljZXM6cGFzc3dvcmQ= + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 201 + message: Created + headers: + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - '0' + X-Content-Type-Options: + - nosniff + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + Content-Type: + - application/vnd.api+json; charset=utf-8 + Etag: + - W/"544a926e975c1304ed645e31097049b0" + Cache-Control: + - max-age=0, private, must-revalidate + X-Request-Id: + - c41f7e36-35f4-4cdf-928c-4c252647487a + X-Runtime: + - '0.021208' + Server-Timing: + - start_processing.action_controller;dur=0.00, sql.active_record;dur=3.20, instantiation.active_record;dur=0.71, + transaction.active_record;dur=2.12, process_action.action_controller;dur=11.14 + Content-Length: + - '483' + body: + encoding: UTF-8 + string: '{"phone_calls":[{"created_at":"2024-07-09T06:59:30Z","updated_at":"2024-07-09T06:59:30Z","sid":"e80a212e-4066-4394-8b7d-ea28c589a717","parent_call_sid":"15f55641-7728-4cab-8e2e-8077c4b3c6b4","account_sid":"96b4557a-341c-46b3-ba3c-a1793e9dae3c","from":"+85523238265","routing_parameters":{"destination":"+85516701721","dial_string_prefix":null,"plus_prefix":false,"national_dialing":false,"host":"host.docker.internal:5061","username":null,"symmetric_latching":true},"address":null}]}' + recorded_at: Tue, 09 Jul 2024 06:59:30 GMT +recorded_with: VCR 6.2.0 diff --git a/components/app/spec/fixtures/vcr_cassettes/dial_with_national_dialing.yml b/components/app/spec/fixtures/vcr_cassettes/dial_with_national_dialing.yml new file mode 100644 index 000000000..ae00322fa --- /dev/null +++ b/components/app/spec/fixtures/vcr_cassettes/dial_with_national_dialing.yml @@ -0,0 +1,55 @@ +--- +http_interactions: +- request: + method: post + uri: http://api.lvh.me:3000/services/outbound_phone_calls + body: + encoding: UTF-8 + string: '{"destinations":["85516701721"],"parent_call_sid":"15f55641-7728-4cab-8e2e-8077c4b3c6b4"}' + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Faraday v2.10.0 + Authorization: + - Basic c2VydmljZXM6cGFzc3dvcmQ= + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 201 + message: Created + headers: + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - '0' + X-Content-Type-Options: + - nosniff + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + Content-Type: + - application/vnd.api+json; charset=utf-8 + Etag: + - W/"9b5b99a3361bc4c3d59f2dc553e4960a" + Cache-Control: + - max-age=0, private, must-revalidate + X-Request-Id: + - 8c1aab6d-e48c-4a23-8e2e-df896516769f + X-Runtime: + - '0.357902' + Server-Timing: + - sql.active_record;dur=55.00, start_processing.action_controller;dur=0.00, + instantiation.active_record;dur=21.18, transaction.active_record;dur=14.93, + process_action.action_controller;dur=250.55 + Content-Length: + - '483' + body: + encoding: UTF-8 + string: '{"phone_calls":[{"created_at":"2024-07-09T06:27:40Z","updated_at":"2024-07-09T06:27:40Z","sid":"c843486f-1d7b-4ec9-960d-7944cc501ee5","parent_call_sid":"15f55641-7728-4cab-8e2e-8077c4b3c6b4","account_sid":"96b4557a-341c-46b3-ba3c-a1793e9dae3c","from":"+855715100678","routing_parameters":{"destination":"+85516701721","dial_string_prefix":null,"plus_prefix":false,"national_dialing":true,"host":"host.docker.internal:5061","username":null,"symmetric_latching":true},"address":null}]}' + recorded_at: Tue, 09 Jul 2024 06:27:40 GMT +recorded_with: VCR 6.2.0 diff --git a/components/app/spec/fixtures/vcr_cassettes/dial_without_symmetric_latching.yml b/components/app/spec/fixtures/vcr_cassettes/dial_without_symmetric_latching.yml new file mode 100644 index 000000000..1c45f08b0 --- /dev/null +++ b/components/app/spec/fixtures/vcr_cassettes/dial_without_symmetric_latching.yml @@ -0,0 +1,54 @@ +--- +http_interactions: +- request: + method: post + uri: http://api.lvh.me:3000/services/outbound_phone_calls + body: + encoding: UTF-8 + string: '{"destinations":["85516701721"],"parent_call_sid":"15f55641-7728-4cab-8e2e-8077c4b3c6b4"}' + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - Faraday v2.10.0 + Authorization: + - Basic c2VydmljZXM6cGFzc3dvcmQ= + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 201 + message: Created + headers: + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - '0' + X-Content-Type-Options: + - nosniff + X-Permitted-Cross-Domain-Policies: + - none + Referrer-Policy: + - strict-origin-when-cross-origin + Content-Type: + - application/vnd.api+json; charset=utf-8 + Etag: + - W/"ad3df94476f9a2757680cc062e82f553" + Cache-Control: + - max-age=0, private, must-revalidate + X-Request-Id: + - a6fa45a1-beb1-4142-a5e4-ebd714f7edf9 + X-Runtime: + - '0.039109' + Server-Timing: + - start_processing.action_controller;dur=0.00, sql.active_record;dur=3.28, instantiation.active_record;dur=0.23, + transaction.active_record;dur=2.19, process_action.action_controller;dur=7.74 + Content-Length: + - '484' + body: + encoding: UTF-8 + string: '{"phone_calls":[{"created_at":"2024-07-09T06:32:09Z","updated_at":"2024-07-09T06:32:09Z","sid":"88f1c78b-716b-4308-83db-047b6e0e1be7","parent_call_sid":"15f55641-7728-4cab-8e2e-8077c4b3c6b4","account_sid":"96b4557a-341c-46b3-ba3c-a1793e9dae3c","from":"+855715100678","routing_parameters":{"destination":"+85516701721","dial_string_prefix":null,"plus_prefix":false,"national_dialing":true,"host":"host.docker.internal:5061","username":null,"symmetric_latching":false},"address":null}]}' + recorded_at: Tue, 09 Jul 2024 06:32:09 GMT +recorded_with: VCR 6.2.0 diff --git a/components/app/spec/workflows/execute_dial_spec.rb b/components/app/spec/workflows/execute_dial_spec.rb deleted file mode 100644 index 679f4363f..000000000 --- a/components/app/spec/workflows/execute_dial_spec.rb +++ /dev/null @@ -1,64 +0,0 @@ -require "spec_helper" - -RSpec.describe ExecuteDial, type: :call_controller do - it "creates a call" do - verb = build_verb( - nested_nouns: build_nested_nouns("85516701721", "855715100860", "sip:example.com:5080") - ) - joined_outbound_call = build_outbound_call(id: "481f77b9-a95b-4c6a-bbb1-23afcc42c959") - no_answer_outbound_call = build_outbound_call - - context = build_controller( - stub_voice_commands: { - dial: build_dial_status( - :answer, - joins: { - joined_outbound_call => build_dial_join_status(:joined, duration: 25), - no_answer_outbound_call => build_dial_join_status(:no_answer) - } - ) - } - ) - - ExecuteDial.call(verb, **build_workflow_options(context:)) - end - - def build_verb(**options) - TwiML::DialVerb.new( - name: "Dial", - attributes: {}, - nested_nouns: [], - **options - ) - end - - def build_nested_nouns(*destinations) - Array(destinations).map do |destination| - TwiML::TwiMLNode.new(name: destination.start_with?("sip:") ? "Sip" : "Number", content: destination) - end - end - - def build_workflow_options(**options) - context = options.fetch(:context) { build_controller } - - { - context:, - call_properties: build_call_properties, - phone_call: context.call, - call_platform_client: context.call_platform_client, - **options - } - end - - def build_outbound_call(options = {}) - instance_double(Adhearsion::OutboundCall, options) - end - - def build_dial_status(result = :answer, joins: {}) - instance_double(Adhearsion::CallController::DialStatus, result:, joins:) - end - - def build_dial_join_status(result = :joined, options = {}) - instance_double(Adhearsion::CallController::Dial::JoinStatus, result:, **options) - end -end