Merge branch 'disable-voicemail'

Stephen Paul Weber created

* disable-voicemail:
  Allow infinite timeout / disabled voicemail

Change summary

forms/configure_calls.rb    | 33 ++++++++++++++--------
lib/configure_calls_form.rb |  7 ++--
lib/customer_fwd.rb         | 55 ++++++++++++++++++++++++++++++++++----
lib/registration.rb         |  2 
sgx_jmp.rb                  |  2 
views/forward.slim          |  3 ++
views/hangup.slim           |  3 ++
web.rb                      |  6 +++
8 files changed, 87 insertions(+), 24 deletions(-)

Detailed changes

forms/configure_calls.rb 🔗

@@ -2,21 +2,30 @@ form!
 title "Configure Calls"
 
 field(
-	var: "fwd[timeout]",
-	type: "text-single",
-	datatype: "xs:integer",
-	label: "Seconds to ring before voicemail",
-	description: "One ring is ~5 seconds. Negative means ring forever.",
-	value: @customer.fwd.timeout.to_i.to_s
-)
-
-field(
-	var: "voicemail_transcription",
+	var: "fwd[voicemail_enabled]",
 	type: "boolean",
-	label: "Voicemail transcription",
-	value: @customer.transcription_enabled.to_s
+	label: "Voicemail enabled",
+	value: @customer.fwd.voicemail_enabled?
 )
 
+if @customer.fwd.voicemail_enabled?
+	field(
+		var: "fwd[timeout]",
+		type: "text-single",
+		datatype: "xs:integer",
+		label: "Seconds to ring before voicemail",
+		description: "One ring is ~5 seconds. Negative means ring forever.",
+		value: @customer.fwd.timeout.to_i.to_s
+	)
+
+	field(
+		var: "voicemail_transcription",
+		type: "boolean",
+		label: "Voicemail transcription",
+		value: @customer.transcription_enabled.to_s
+	)
+end
+
 field(
 	var: "fwd[uri]",
 	type: "list-single",

lib/configure_calls_form.rb 🔗

@@ -33,8 +33,9 @@ protected
 	end
 
 	def parse_fwd(fwd_from_form)
-		fwd_from_form.reduce(@customer.fwd) do |fwd, (var, val)|
-			fwd.with(var.to_sym => val.strip)
-		end
+		@customer.fwd.with(fwd_from_form.each_with_object({}) { |(var, val), args|
+			args[var.to_sym] =
+				var == "voicemail_enabled" ? ["1", "true"].include?(val) : val&.strip
+		})
 	end
 end

lib/customer_fwd.rb 🔗

@@ -5,8 +5,17 @@ require "value_semantics/monkey_patched"
 require "uri"
 
 class CustomerFwd
-	def self.for(uri:, timeout:)
-		timeout = Timeout.new(timeout)
+	class InfiniteTimeout < StandardError
+		attr_reader :fwd
+
+		def initialize(fwd)
+			super "Infinite timeout"
+			@fwd = fwd
+		end
+	end
+
+	def self.for(uri:, timeout: nil, voicemail_enabled: :default)
+		timeout = Timeout.for(timeout, voicemail_enabled: voicemail_enabled)
 
 		fwd = if uri
 			if uri =~ /\Asip:(.*)@sip.cheogram.com\Z/
@@ -22,18 +31,32 @@ class CustomerFwd
 	end
 
 	class Timeout
-		def self.new(s)
-			s.is_a?(self) ? s : super
+		def self.for(s, voicemail_enabled: :default)
+			return Infinite.new unless voicemail_enabled
+
+			if s.nil? || s.is_a?(Infinite) || s.to_i.negative?
+				return new(25) if voicemail_enabled == true # ~5s / ring, 5 rings
+
+				return Infinite.new
+			end
+
+			return s if s.is_a?(self)
+
+			new(s)
 		end
 
 		def initialize(s)
-			@timeout = s.nil? || s.to_i.negative? || s.to_i > 300 ? 300 : s.to_i
+			@timeout = [s.to_i, 300].min
 		end
 
 		def zero?
 			@timeout.zero?
 		end
 
+		def infinite?
+			false
+		end
+
 		def to_i
 			@timeout
 		end
@@ -41,18 +64,38 @@ class CustomerFwd
 		def to_s
 			to_i.to_s
 		end
+
+		class Infinite < Timeout
+			def initialize; end
+
+			def zero?
+				false
+			end
+
+			def infinite?
+				1
+			end
+
+			def to_i; end
+		end
 	end
 
 	value_semantics do
 		uri Either(/:/, NilClass)
-		def_attr :timeout, Timeout, coerce: Timeout.method(:new)
+		def_attr :timeout, Timeout, coerce: Timeout.method(:for)
 	end
 
 	def with(new_attrs)
 		CustomerFwd.for(to_h.merge(new_attrs))
 	end
 
+	def voicemail_enabled?
+		!timeout.infinite?
+	end
+
 	def create_call(account)
+		raise InfiniteTimeout, self if timeout.infinite?
+
 		request = Bandwidth::ApiCreateCallRequest.new.tap { |cc|
 			cc.to = to
 			cc.call_timeout = timeout.to_i

lib/registration.rb 🔗

@@ -470,7 +470,7 @@ class Registration
 				EMPromise.all([
 					REDIS.del("pending_tel_for-#{@customer.jid}"),
 					Bwmsgsv2Repo.new.put_fwd(@customer.customer_id, @tel, CustomerFwd.for(
-						uri: "xmpp:#{@customer.jid}", timeout: 25 # ~5s / ring, 5 rings
+						uri: "xmpp:#{@customer.jid}", voicemail_enabled: true
 					))
 				])
 			}.then do

sgx_jmp.rb 🔗

@@ -527,7 +527,7 @@ Command.new(
 Command.new(
 	"ogm",
 	"Record Voicemail Greeting",
-	list_for: ->(fwd: nil, **) { !!fwd },
+	list_for: ->(fwd: nil, **) { fwd&.voicemail_enabled? },
 	customer_repo: CustomerRepo.new(sgx_repo: Bwmsgsv2Repo.new)
 ) {
 	Command.customer.then do |customer|

views/forward.slim 🔗

@@ -0,0 +1,3 @@
+doctype xml
+Response
+	Forward to=fwd.to from=from callTimeout=300

web.rb 🔗

@@ -296,8 +296,10 @@ class Web < Roda
 								sgx_repo: Bwmsgsv2Repo.new,
 								ogm_url: nil
 							).then { |c|
-								c.ogm(params["from"])
+								c.ogm(params["from"]) if c.fwd.voicemail_enabled?
 							}.then { |ogm|
+								next render :hangup unless ogm
+
 								render :voicemail, locals: { ogm: ogm }
 							}
 						end
@@ -339,6 +341,8 @@ class Web < Roda
 
 						outbound_transfers[params["callId"]] = call
 						render :ring, locals: { duration: 300 }
+					}.catch_only(CustomerFwd::InfiniteTimeout) { |e|
+						render :forward, locals: { fwd: e.fwd, from: params["from"] }
 					}.catch { |e|
 						log_error(e) unless e == :voicemail
 						render :redirect, locals: { to: inbound_calls_path(:voicemail) }