18F/identity-idp

View on GitHub
lib/telephony/otp_sender.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
97%
# frozen_string_literal: true
 
module Telephony
class OtpSender
attr_reader :recipient_phone, :otp, :expiration, :otp_format, :otp_length, :channel,
:domain, :country_code, :extra_metadata
 
def initialize(to:, otp:, expiration:, otp_format:,
channel:, domain:, country_code:, extra_metadata:,
otp_length: I18n.t('telephony.format_length.six'))
@recipient_phone = to
@otp = otp
@otp_format = otp_format
@otp_length = otp_length
@expiration = expiration
@channel = channel.to_sym
@domain = domain
@country_code = country_code
@extra_metadata = extra_metadata
end
 
def send_authentication_otp
response = adapter.deliver(
message: authentication_message,
to: recipient_phone,
otp: otp,
country_code: country_code,
)
log_response(response, context: :authentication)
response
end
 
def send_confirmation_otp
response = adapter.deliver(
message: confirmation_message,
to: recipient_phone,
otp: otp,
country_code: country_code,
)
log_response(response, context: :confirmation)
response
end
 
def authentication_message
wrap_in_ssml_if_needed(
I18n.t(
"telephony.authentication_otp.#{channel}",
app_name: APP_NAME,
code: otp_transformed_for_channel,
format_type: otp_format,
expiration: expiration,
domain: domain,
),
)
end
 
def confirmation_message
wrap_in_ssml_if_needed(
I18n.t(
"telephony.confirmation_otp.#{channel}",
app_name: APP_NAME,
code: otp_transformed_for_channel,
format_length: otp_length,
format_type: otp_format,
expiration: expiration,
domain: domain,
),
)
end
 
private
 
def adapter
case [Telephony.config.adapter, channel.to_sym]
when [:pinpoint, :sms]
Pinpoint::SmsSender.new
when [:pinpoint, :voice]
Pinpoint::VoiceSender.new
when [:test, :sms]
Test::SmsSender.new
when [:test, :voice]
Test::VoiceSender.new
else
raise "Unknown telephony adapter #{Telephony.config.adapter} for channel #{channel.to_sym}"
end
end
 
def log_response(response, context:)
extra = extra_metadata.merge(
{
adapter: Telephony.config.adapter,
channel: channel,
context: context,
country_code: country_code,
},
)
output = response.to_h.merge(extra)
Telephony.log_info(event: output)
end
 
def otp_transformed_for_channel
return otp if channel != :voice
 
[*otp.chars, ''].join(" <break time='#{Telephony.config.voice_pause_time}' /> ")
end
 
def wrap_in_ssml_if_needed(message)
return message if channel != :voice
 
<<~XML.squish
<speak>
<prosody rate='#{Telephony.config.voice_rate}'>
#{message}
</prosody>
</speak>
XML
end
end
end