JSON route for outbound calls

Stephen Paul Weber created

For use from Asterisk

Change summary

lib/call_attempt.rb | 84 ++++++++++++++++++++++++++++++++++++++++++++--
lib/tts_template.rb | 17 +++++++++
web.rb              |  6 ++
3 files changed, 101 insertions(+), 6 deletions(-)

Detailed changes

lib/call_attempt.rb 🔗

@@ -2,6 +2,7 @@
 
 require "value_semantics/monkey_patched"
 
+require_relative "tts_template"
 require_relative "low_balance"
 
 class CallAttempt
@@ -24,14 +25,19 @@ class CallAttempt
 
 	def self.for_ask_or_go(customer, otel, rate, usage, digits: nil, **kwargs)
 		can_use = customer.minute_limit.to_d + customer.monthly_overage_limit
+		kwargs.merge!(
+			customer_id: customer.customer_id,
+			from: customer.registered?.phone, to: otel
+		)
 		if digits != "1" && can_use - usage < rate * 10
-			AtLimit.new(**kwargs.slice(:direction, :call_id))
+			AtLimit.new(**kwargs)
 		else
-			new(from: customer.registered?.phone, to: otel, **kwargs)
+			new(**kwargs)
 		end
 	end
 
 	value_semantics do
+		customer_id String
 		from(/\A\+\d+\Z/)
 		to(/\A\+\d+\Z/)
 		call_id String
@@ -46,16 +52,44 @@ class CallAttempt
 		fwd.create_call(*args, &block)
 	end
 
+	def as_json(*)
+		{
+			from: from,
+			to: to,
+			customer_id: customer_id
+		}
+	end
+
+	def to_json(*args)
+		as_json.to_json(*args)
+	end
+
 	class Unsupported
 		value_semantics do
 			direction Either(:inbound, :outbound)
 		end
 
+		def view
+			"#{direction}/unsupported"
+		end
+
+		def tts
+			TTSTemplate.new(view).tts(self)
+		end
+
 		def to_render
-			["#{direction}/unsupported"]
+			[view]
 		end
 
 		def create_call(*); end
+
+		def as_json(*)
+			{ tts: tts }
+		end
+
+		def to_json(*args)
+			as_json.to_json(*args)
+		end
 	end
 
 	class NoBalance
@@ -77,25 +111,65 @@ class CallAttempt
 			direction Either(:inbound, :outbound)
 		end
 
+		def view
+			"#{direction}/no_balance"
+		end
+
+		def tts
+			TTSTemplate.new(view).tts(self)
+		end
+
 		def to_render
-			["#{direction}/no_balance", { locals: to_h }]
+			[view, { locals: to_h }]
 		end
 
 		def create_call(*); end
+
+		def as_json(*)
+			{ tts: tts }
+		end
+
+		def to_json(*args)
+			as_json.to_json(*args)
+		end
 	end
 
 	class AtLimit
 		value_semantics do
+			customer_id String
+			from(/\A\+\d+\Z/)
+			to(/\A\+\d+\Z/)
 			call_id String
 			direction Either(:inbound, :outbound)
 		end
 
+		def view
+			"#{direction}/at_limit"
+		end
+
+		def tts
+			TTSTemplate.new(view).tts(self)
+		end
+
 		def to_render
-			["#{direction}/at_limit", { locals: to_h }]
+			[view, { locals: to_h }]
 		end
 
 		def create_call(fwd, *args, &block)
 			fwd.create_call(*args, &block)
 		end
+
+		def as_json(*)
+			{
+				tts: tts,
+				from: from,
+				to: to,
+				customer_id: customer_id
+			}
+		end
+
+		def to_json(*args)
+			as_json.to_json(*args)
+		end
 	end
 end

lib/tts_template.rb 🔗

@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class TTSTemplate
+	def initialize(view)
+		@view = view
+	end
+
+	def template_path
+		"#{File.dirname(__dir__)}/views/#{@view}.slim"
+	end
+
+	def tts(scope)
+		Nokogiri::XML.parse(
+			Slim::Template.new(template_path).render(scope)
+		).find("//SpeakSentence").map(&:content).join(" ")
+	end
+end

web.rb 🔗

@@ -307,7 +307,11 @@ class Web < Roda
 							params["to"],
 							call_id: params["callId"],
 							digits: params["digits"]
-						).then { |ca| render(*ca.to_render) }
+						).then do |ca|
+							r.json { ca.to_json }
+
+							render(*ca.to_render)
+						end
 					end
 				end
 			end