Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
dwilkie committed Jun 26, 2024
1 parent 76da840 commit 0192304
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 103 deletions.
2 changes: 1 addition & 1 deletion components/app/app/call_controllers/call_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def build_call_properties

call_serializer = CallSerializer.new(call)

response = call_platform_client.create_call(
response = call_platform_client.create_inbound_call(
to: call.variables.fetch("variable_sip_h_x_somleng_callee_identity"),
from: call.variables.fetch("variable_sip_h_x_somleng_caller_identity"),
external_id: call_serializer.id,
Expand Down
74 changes: 28 additions & 46 deletions components/app/app/workflows/execute_dial.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,8 @@ class ExecuteDial < ExecuteTwiMLVerb

def call
answer!
calls = create_calls
dial_to(calls)

dial_status = context.dial(build_dial_strings)
phone_calls = create_outbound_calls
dial_status = context.dial(build_dial_params(phone_calls))

return if verb.action.blank?

Expand All @@ -23,14 +21,29 @@ def call

private

def create_calls
verb.nested_nouns.each_with_object(Hash.new({})) do |nested_noun, result|
dial_string, from = build_dial_string(nested_noun)

result[dial_string.to_s] = { from:, for: verb.timeout.seconds }.compact
def build_dial_params(phone_calls)
phone_calls.each_with_object({}) do |phone_call, result|
dial_string, from = build_dial_string(phone_call)

result[dial_string.to_s] = {
from:,
for: verb.timeout.seconds,
headers: SIPHeaders.new(
call_sid: phone_call.sid,
account_sid: phone_call.account_sid
).to_h
}.compact
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
)
end

def redirect(params)
throw(
:redirect,
Expand Down Expand Up @@ -60,43 +73,12 @@ def find_joined_call(dial_status)
end
end

def build_dial_strings
verb.nested_nouns.each_with_object(Hash.new({})) do |nested_noun, result|
dial_string, from = build_dial_string(nested_noun)

result[dial_string.to_s] = { from:, for: verb.timeout.seconds }.compact
end
end

def build_dial_string(nested_noun)
dial_content = nested_noun.content.strip

if dial_to_number?(nested_noun)
dial_string = DialString.new(build_routing_parameters(dial_content))
[ dial_string, dial_string.format_number(caller_id) ]
elsif dial_to_sip?(nested_noun)
DialString.new(address: dial_content.delete_prefix("sip:"))
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 dial_to_number?(nested_noun)
nested_noun.text? || nested_noun.name == "Number"
end

def dial_to_sip?(nested_noun)
nested_noun.name == "Sip"
end

def caller_id
return verb.caller_id if verb.caller_id.present?

call_properties.inbound? ? call_properties.from : call_properties.to
end

def build_routing_parameters(number)
call_platform_client.build_routing_parameters(
phone_number: number,
account_sid: call_properties.account_sid
)
end
end
27 changes: 26 additions & 1 deletion components/app/lib/call_platform/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ class InvalidRequestError < StandardError; end
keyword_init: true
)

OutboundPhoneCallResponse = Struct.new(
:sid,
:from,
:account_sid,
:parent_call_sid,
:routing_parameters,
:address,
keyword_init: true
)

RecordingResponse = Struct.new(
:id,
:url,
Expand Down Expand Up @@ -53,7 +63,7 @@ def build_routing_parameters(params)
make_request("/services/routing_parameters", params: params)
end

def create_call(params)
def create_inbound_call(params)
json_response = make_request("/services/inbound_phone_calls", params: params)
InboundPhoneCallResponse.new(
voice_url: json_response.fetch("voice_url"),
Expand All @@ -70,6 +80,21 @@ def create_call(params)
)
end

def create_outbound_calls(params)
json_response = make_request("/services/outbound_phone_calls", params: params.compact)

json_response.fetch("phone_calls").map do |phone_call_response|
OutboundPhoneCallResponse.new(
sid: phone_call_response.fetch("sid"),
parent_call_sid: phone_call_response.fetch("parent_call_sid"),
account_sid: phone_call_response.fetch("account_sid"),
from: phone_call_response.fetch("from"),
routing_parameters: phone_call_response.fetch("routing_parameters"),
address: phone_call_response.fetch("address")
)
end
end

def create_recording(params)
json_response = make_request("/services/recordings", params:)
RecordingResponse.new(
Expand Down
2 changes: 1 addition & 1 deletion components/app/lib/call_platform/fake_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def audio_file_url
ConnectTestNumberWithTwiMLResponse.new(number: "2222")
].freeze

def create_call(params)
def create_inbound_call(params)
validate_gateway_headers(params)

test_number = find_test_number(params.fetch(:to))
Expand Down
5 changes: 3 additions & 2 deletions components/app/spec/call_controllers/dial_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,12 @@
# | <Queue> | A nested XML element identifying a queue |
# | | that this call should be connected to. |

it "dials to plain text", :vcr, cassette: :build_routing_parameters do
it "dials to plain text", :vcr, cassette: :dial do
controller = build_controller(
stub_voice_commands: [ :play_audio, { dial: build_dial_status } ],
call_properties: {
account_sid: "ea471a9f-d4b3-4035-966e-f507b8da6d34",
account_sid: "96b4557a-341c-46b3-ba3c-a1793e9dae3c",
call_sid: "15f55641-7728-4cab-8e2e-8077c4b3c6b4",
from: "855715100860",
direction: "inbound"
}
Expand Down
55 changes: 55 additions & 0 deletions components/app/spec/fixtures/vcr_cassettes/dial.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions components/app/spec/lib/call_platform/fake_client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

module CallPlatform
RSpec.describe FakeClient do
describe "#create_call" do
describe "#create_inbound_call" do
it "returns a mock <Play> response by default" do
client = FakeClient.new

response = client.create_call(
response = client.create_inbound_call(
to: "+85512345678",
from: "+855715200987"
)
Expand All @@ -23,7 +23,7 @@ module CallPlatform
it "returns a mock <Say> response" do
client = FakeClient.new

response = client.create_call(
response = client.create_inbound_call(
to: "1111",
from: "+855715200987"
)
Expand All @@ -36,7 +36,7 @@ module CallPlatform
it "returns a mock <Connect> response" do
client = FakeClient.new

response = client.create_call(
response = client.create_inbound_call(
to: "2222",
from: "+855715200987"
)
Expand Down
39 changes: 0 additions & 39 deletions components/app/spec/models/dial_string_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,45 +96,6 @@
end
end

describe "#format_number" do
it "formats a number in national format" do
dial_string = DialString.new(
build_routing_parameters(
national_dialing: true
)
)

result = dial_string.format_number("+855 (716)-100-987")

expect(result).to eq("0716100987")
end

it "formats a number in national format for countries without a trunk prefix" do
dial_string = DialString.new(
build_routing_parameters(
national_dialing: true
)
)

result = dial_string.format_number("+16505130514")

expect(result).to eq("6505130514")
end

it "formats a number in E.164 format" do
dial_string = DialString.new(
build_routing_parameters(
national_dialing: false,
plus_prefix: true
)
)

result = dial_string.format_number("+855 (716)-100-987")

expect(result).to eq("+855716100987")
end
end

def build_routing_parameters(options)
options.reverse_merge(
destination: "855716100987",
Expand Down
15 changes: 6 additions & 9 deletions components/app/spec/workflows/execute_dial_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@

RSpec.describe ExecuteDial, type: :call_controller do
it "creates a call" do

nested_nouns = #<struct TwiML::TwiMLNode name="Number", attributes={}, content="85516701721", text?=false>,
#<struct TwiML::TwiMLNode name="Number", attributes={}, content="855715100860", text?=false>,
#<struct TwiML::TwiMLNode name="Number", attributes={}, content="85510555777", text?=false>]

verb = build_verb(nested_nouns: build_nested_nouns("85516701721", "855715100860", "85510555777"))
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

Expand Down Expand Up @@ -35,9 +32,9 @@ def build_verb(**options)
)
end

def build_nested_nouns(numbers)
Array(numbers).map do |number|
TwiML::TwiMLNode.new(name: "Number", content: number)
def build_nested_nouns(*destinations)
Array(destinations).map do |destination|
TwiML::TwiMLNode.new(name: destination.start_with?("sip:") ? "Sip" : "Number", content: destination)
end
end

Expand Down

0 comments on commit 0192304

Please sign in to comment.