mirror of https://github.com/docusealco/docuseal
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
71 lines
2.4 KiB
71 lines
2.4 KiB
# frozen_string_literal: true
|
|
|
|
module Sms
|
|
class Error < StandardError; end
|
|
class NotConfiguredError < Error; end
|
|
class ProviderError < Error; end
|
|
class InvalidNumberError < Error; end
|
|
|
|
SUPPORTED_PROVIDERS = %w[bulkvs twilio voipms signalwire].freeze
|
|
|
|
module_function
|
|
|
|
# Returns the SMS configuration hash for an account. Keys vary by provider —
|
|
# see the per-provider class for which keys it consumes. Returns nil if no
|
|
# record exists.
|
|
def configuration_for(account)
|
|
return nil if account.nil?
|
|
|
|
record = EncryptedConfig.find_by(account_id: account.id, key: EncryptedConfig::SMS_CONFIGS_KEY)
|
|
record&.value
|
|
end
|
|
|
|
def enabled_for?(account)
|
|
config = configuration_for(account)
|
|
return false unless config.is_a?(Hash)
|
|
return false unless config['enabled']
|
|
|
|
klass = provider_class(config['provider'].to_s)
|
|
klass ? klass.configured?(config) : false
|
|
end
|
|
|
|
# Send an SMS via the account's configured provider.
|
|
#
|
|
# account: a WaboSign Account record
|
|
# to: the recipient phone number (E.164, leading + tolerated; the
|
|
# provider class decides whether to keep or strip the +)
|
|
# text: the message body (already variable-substituted)
|
|
# webhook: optional override of the per-message delivery callback URL
|
|
#
|
|
# Returns the provider's parsed response on success. Raises
|
|
# NotConfiguredError or ProviderError on failure.
|
|
def send_message(account:, to:, text:, webhook: nil)
|
|
raise NotConfiguredError, 'SMS provider is not configured' unless enabled_for?(account)
|
|
|
|
config = configuration_for(account)
|
|
klass = provider_class(config['provider'].to_s)
|
|
raise NotConfiguredError, "Unsupported SMS provider: #{config['provider'].inspect}" unless klass
|
|
|
|
klass.new(config).deliver(to: to, text: text, webhook: webhook)
|
|
end
|
|
|
|
# Normalize a phone number to digits-only. Each provider class is responsible
|
|
# for prepending '+' if its wire format requires E.164 with leading plus
|
|
# (Twilio, SignalWire); BulkVS and VoIP.ms take digits-only.
|
|
def normalize_phone(raw)
|
|
digits = raw.to_s.gsub(/[^\d]/, '')
|
|
raise InvalidNumberError, "Invalid phone number: #{raw.inspect}" if digits.length < 8
|
|
|
|
digits
|
|
end
|
|
|
|
def provider_class(name)
|
|
case name
|
|
when 'bulkvs' then Sms::Providers::Bulkvs
|
|
when 'twilio' then Sms::Providers::Twilio
|
|
when 'voipms' then Sms::Providers::Voipms
|
|
when 'signalwire' then Sms::Providers::Signalwire
|
|
end
|
|
end
|
|
end
|