vonage 7.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +190 -0
- data/README.md +191 -0
- data/lib/vonage.rb +29 -0
- data/lib/vonage/abstract_authentication.rb +9 -0
- data/lib/vonage/account.rb +61 -0
- data/lib/vonage/alerts.rb +72 -0
- data/lib/vonage/applications.rb +148 -0
- data/lib/vonage/applications/list_response.rb +11 -0
- data/lib/vonage/authentication_error.rb +6 -0
- data/lib/vonage/basic.rb +13 -0
- data/lib/vonage/bearer_token.rb +14 -0
- data/lib/vonage/client.rb +134 -0
- data/lib/vonage/client_error.rb +6 -0
- data/lib/vonage/config.rb +208 -0
- data/lib/vonage/conversations.rb +210 -0
- data/lib/vonage/conversations/events.rb +73 -0
- data/lib/vonage/conversations/legs.rb +30 -0
- data/lib/vonage/conversations/members.rb +104 -0
- data/lib/vonage/conversations/users.rb +93 -0
- data/lib/vonage/conversions.rb +19 -0
- data/lib/vonage/entity.rb +51 -0
- data/lib/vonage/error.rb +6 -0
- data/lib/vonage/errors.rb +51 -0
- data/lib/vonage/files.rb +26 -0
- data/lib/vonage/form_data.rb +11 -0
- data/lib/vonage/gsm7.rb +13 -0
- data/lib/vonage/http.rb +43 -0
- data/lib/vonage/json.rb +17 -0
- data/lib/vonage/jwt.rb +43 -0
- data/lib/vonage/key_secret_params.rb +20 -0
- data/lib/vonage/keys.rb +51 -0
- data/lib/vonage/logger.rb +60 -0
- data/lib/vonage/messages.rb +25 -0
- data/lib/vonage/namespace.rb +118 -0
- data/lib/vonage/number_insight.rb +140 -0
- data/lib/vonage/numbers.rb +196 -0
- data/lib/vonage/numbers/list_response.rb +11 -0
- data/lib/vonage/numbers/response.rb +8 -0
- data/lib/vonage/params.rb +27 -0
- data/lib/vonage/pricing.rb +30 -0
- data/lib/vonage/pricing_types.rb +18 -0
- data/lib/vonage/redact.rb +37 -0
- data/lib/vonage/response.rb +25 -0
- data/lib/vonage/secrets.rb +85 -0
- data/lib/vonage/secrets/list_response.rb +11 -0
- data/lib/vonage/server_error.rb +6 -0
- data/lib/vonage/signature.rb +53 -0
- data/lib/vonage/sms.rb +121 -0
- data/lib/vonage/tfa.rb +14 -0
- data/lib/vonage/user_agent.rb +16 -0
- data/lib/vonage/verify.rb +253 -0
- data/lib/vonage/version.rb +5 -0
- data/lib/vonage/voice.rb +250 -0
- data/lib/vonage/voice/dtmf.rb +26 -0
- data/lib/vonage/voice/list_response.rb +11 -0
- data/lib/vonage/voice/stream.rb +44 -0
- data/lib/vonage/voice/talk.rb +48 -0
- data/vonage.gemspec +26 -0
- metadata +155 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Vonage
|
5
|
+
class Conversions < Namespace
|
6
|
+
extend T::Sig
|
7
|
+
include Keys
|
8
|
+
|
9
|
+
sig { params(params: T::Hash[Symbol, T.untyped]).returns(Vonage::Response) }
|
10
|
+
def track_sms(params)
|
11
|
+
request('/conversions/sms', params: hyphenate(params), type: Post)
|
12
|
+
end
|
13
|
+
|
14
|
+
sig { params(params: T::Hash[Symbol, T.untyped]).returns(Vonage::Response) }
|
15
|
+
def track_voice(params)
|
16
|
+
request('/conversions/voice', params: hyphenate(params), type: Post)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# typed: true
|
2
|
+
|
3
|
+
module Vonage
|
4
|
+
class Entity
|
5
|
+
include Keys
|
6
|
+
|
7
|
+
def initialize(attributes = nil)
|
8
|
+
@attributes = attributes || {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def [](key)
|
12
|
+
@attributes[attribute_key(key)]
|
13
|
+
end
|
14
|
+
|
15
|
+
def []=(key, value)
|
16
|
+
@attributes[attribute_key(key)] = value
|
17
|
+
end
|
18
|
+
|
19
|
+
def respond_to_missing?(name, include_private = false)
|
20
|
+
@attributes.key?(name) or super
|
21
|
+
end
|
22
|
+
|
23
|
+
def method_missing(name, *args)
|
24
|
+
return super unless @attributes.key?(name)
|
25
|
+
|
26
|
+
@attributes[name]
|
27
|
+
end
|
28
|
+
|
29
|
+
def ==(entity)
|
30
|
+
entity.class == self.class && entity.attributes == @attributes
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_h
|
34
|
+
@attributes
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_reader :attributes
|
38
|
+
|
39
|
+
protected :attributes
|
40
|
+
|
41
|
+
def each_pair(&block)
|
42
|
+
return to_enum(:each_pair) unless block
|
43
|
+
|
44
|
+
@attributes.each_pair(&block)
|
45
|
+
end
|
46
|
+
|
47
|
+
alias_method :each, :each_pair
|
48
|
+
|
49
|
+
include Enumerable
|
50
|
+
end
|
51
|
+
end
|
data/lib/vonage/error.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Vonage
|
6
|
+
module Errors
|
7
|
+
extend T::Sig
|
8
|
+
|
9
|
+
sig {params(response: T.any(Net::HTTPUnauthorized, Net::HTTPClientError, Net::HTTPServerError, T.untyped)).returns(Vonage::Error)}
|
10
|
+
def self.parse(response)
|
11
|
+
exception_class = case response
|
12
|
+
when Net::HTTPUnauthorized
|
13
|
+
AuthenticationError
|
14
|
+
when Net::HTTPClientError
|
15
|
+
ClientError
|
16
|
+
when Net::HTTPServerError
|
17
|
+
ServerError
|
18
|
+
else
|
19
|
+
Error
|
20
|
+
end
|
21
|
+
|
22
|
+
message = if response.content_type == 'application/json'
|
23
|
+
hash = ::JSON.parse(response.body)
|
24
|
+
|
25
|
+
if hash.key?('error_title')
|
26
|
+
hash['error_title']
|
27
|
+
elsif hash.key?('error-code-label')
|
28
|
+
hash['error-code-label']
|
29
|
+
elsif hash.key?('description')
|
30
|
+
hash['description']
|
31
|
+
elsif problem_details?(hash)
|
32
|
+
problem_details_message(hash)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
exception_class.new(message)
|
37
|
+
end
|
38
|
+
|
39
|
+
sig { params(hash: T::Hash[String, T.untyped]).returns(T::Boolean) }
|
40
|
+
def self.problem_details?(hash)
|
41
|
+
hash.key?('title') && hash.key?('detail') && hash.key?('type')
|
42
|
+
end
|
43
|
+
|
44
|
+
sig { params(hash: T::Hash[String, T.untyped]).returns(String) }
|
45
|
+
def self.problem_details_message(hash)
|
46
|
+
"#{hash['title']}. #{hash['detail']} See #{hash['type']} for more info, or email support@nexmo.com if you have any questions."
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private_constant :Errors
|
51
|
+
end
|
data/lib/vonage/files.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Vonage
|
5
|
+
class Files < Namespace
|
6
|
+
extend T::Sig
|
7
|
+
|
8
|
+
self.authentication = BearerToken
|
9
|
+
|
10
|
+
sig { params(id: String).returns(T.nilable(Vonage::Response)) }
|
11
|
+
def get(id)
|
12
|
+
request('/v1/files/' + T.must(id.split('/').last))
|
13
|
+
end
|
14
|
+
|
15
|
+
sig { params(id: String, filename: String).returns(T.nilable(Vonage::Response)) }
|
16
|
+
def save(id, filename)
|
17
|
+
request('/v1/files/' + T.must(id.split('/').last)) do |response|
|
18
|
+
File.open(filename, 'wb') do |file|
|
19
|
+
response.read_body do |chunk|
|
20
|
+
file.write(chunk)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/vonage/gsm7.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# typed: ignore
|
2
|
+
|
3
|
+
module Vonage
|
4
|
+
module GSM7
|
5
|
+
CHARACTERS = "\n\f\r !\"\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_abcdefghijklmnopqrstuvwxyz{|}~ ¡£¤¥§¿ÄÅÆÉÑÖØÜßàäåæçèéìñòöøùüΓΔΘΛΞΠΣΦΨΩ€"
|
6
|
+
|
7
|
+
REGEXP = /\A[#{Regexp.escape(CHARACTERS)}]*\z/
|
8
|
+
|
9
|
+
def self.encoded?(string)
|
10
|
+
REGEXP =~ string
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/vonage/http.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'net/http'
|
4
|
+
|
5
|
+
module Vonage
|
6
|
+
module HTTP
|
7
|
+
class Options
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
sig { params(hash: T::Hash[Symbol, T.untyped]).void }
|
11
|
+
def initialize(hash)
|
12
|
+
raise ArgumentError, 'hash parameter cannot be empty or nil' if hash == {} || hash.nil?
|
13
|
+
|
14
|
+
@hash = T.let(@hash, T::Hash[Symbol, T.untyped]) if defined? @hash
|
15
|
+
@hash = hash
|
16
|
+
|
17
|
+
@hash.each_key do |name|
|
18
|
+
next if defined_options.key?(name)
|
19
|
+
|
20
|
+
raise ArgumentError, "#{name.inspect} is not a valid option"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
sig { params(http: Net::HTTP).returns(T::Hash[Symbol, T.untyped]) }
|
25
|
+
def set(http)
|
26
|
+
@hash.each do |name, value|
|
27
|
+
http.public_send(defined_options.fetch(name), value)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
sig { returns(T::Hash[Symbol, T.untyped]) }
|
34
|
+
def defined_options
|
35
|
+
@defined_options = T.let(@defined_options, T.nilable(T::Hash[Symbol, T.untyped]))
|
36
|
+
|
37
|
+
@defined_options ||= Net::HTTP.instance_methods.grep(/\w=\z/).each_with_object({}) do |name, hash|
|
38
|
+
hash[name.to_s.chomp('=').to_sym] = name
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/vonage/json.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Vonage
|
6
|
+
module JSON
|
7
|
+
extend T::Sig
|
8
|
+
|
9
|
+
sig { params(http_request: T.any(Net::HTTP::Put, Net::HTTP::Post), params: T::Hash[Symbol, T.untyped]).void }
|
10
|
+
def self.update(http_request, params)
|
11
|
+
http_request['Content-Type'] = 'application/json'
|
12
|
+
http_request.body = ::JSON.generate(params)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private_constant :JSON
|
17
|
+
end
|
data/lib/vonage/jwt.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# typed: false
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'securerandom'
|
4
|
+
require 'openssl'
|
5
|
+
require 'nexmo-jwt'
|
6
|
+
|
7
|
+
module Vonage
|
8
|
+
class JWT
|
9
|
+
# Generate an encoded JSON Web Token.
|
10
|
+
#
|
11
|
+
# By default the Vonage Ruby SDK generates a short lived JWT per request.
|
12
|
+
#
|
13
|
+
# To generate a long lived JWT for multiple requests or to specify JWT claims
|
14
|
+
# directly call {Vonage::JWT.generate} to generate a token, and set the token
|
15
|
+
# attribute on the client object.
|
16
|
+
#
|
17
|
+
# Documentation for the Vonage Ruby JWT generator gem can be found at
|
18
|
+
# https://www.rubydoc.info/github/Nexmo/nexmo-jwt-ruby
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
# claims = {
|
22
|
+
# application_id: application_id,
|
23
|
+
# ttl: 800,
|
24
|
+
# subject: 'My_Subject'
|
25
|
+
# }
|
26
|
+
#
|
27
|
+
# private_key = File.read('path/to/private.key')
|
28
|
+
#
|
29
|
+
# client.config.token = Vonage::JWT.generate(claims, private_key)
|
30
|
+
#
|
31
|
+
# @param [Hash] payload
|
32
|
+
# @param [String, OpenSSL::PKey::RSA] private_key
|
33
|
+
#
|
34
|
+
# @return [String]
|
35
|
+
#
|
36
|
+
def self.generate(payload, private_key = nil)
|
37
|
+
raise "Expecting 'private_key' in either the payload or as a separate parameter" if !payload[:private_key] && !private_key
|
38
|
+
|
39
|
+
payload[:private_key] = private_key if private_key && !payload[:private_key]
|
40
|
+
@token = Nexmo::JWTBuilder.new(payload).jwt.generate
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
module Vonage
|
4
|
+
class KeySecretParams < AbstractAuthentication
|
5
|
+
extend T::Sig
|
6
|
+
|
7
|
+
sig { params(
|
8
|
+
object: T.any(T::Hash[T.untyped, T.untyped], URI::HTTPS, Net::HTTP::Post, Net::HTTP::Get)
|
9
|
+
).void }
|
10
|
+
def update(object)
|
11
|
+
return unless object.is_a?(Hash)
|
12
|
+
|
13
|
+
@config = T.let(@config, T.nilable(Vonage::Config))
|
14
|
+
object[:api_key] = T.must(@config).api_key
|
15
|
+
object[:api_secret] = T.must(@config).api_secret
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private_constant :KeySecretParams
|
20
|
+
end
|
data/lib/vonage/keys.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Vonage
|
5
|
+
module Keys
|
6
|
+
extend T::Sig
|
7
|
+
|
8
|
+
sig { params(hash: T::Hash[T.untyped, T.untyped]).returns(T::Hash[String, T.untyped]) }
|
9
|
+
def hyphenate(hash)
|
10
|
+
hash.transform_keys { |k| k.to_s.tr('_', '-') }
|
11
|
+
end
|
12
|
+
|
13
|
+
sig { params(hash: T::Hash[T.untyped, T.untyped]).returns(T::Hash[T.untyped, T.untyped]) }
|
14
|
+
def camelcase(hash)
|
15
|
+
exceptions = [
|
16
|
+
'dr_call_back_url',
|
17
|
+
'mo_http_url',
|
18
|
+
'mo_smpp_sys_type',
|
19
|
+
'mo_call_back_url',
|
20
|
+
'voice_callback_type',
|
21
|
+
'voice_callback_value',
|
22
|
+
'voice_status_callback',
|
23
|
+
'messages_callback_value',
|
24
|
+
'messages_callback_type'
|
25
|
+
]
|
26
|
+
hash.transform_keys do |k|
|
27
|
+
if exceptions.include?(k.to_s)
|
28
|
+
next k.to_s.gsub(/_(\w)/) { $1.upcase.to_s }
|
29
|
+
end
|
30
|
+
k
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
ATTRIBUTE_KEYS = T.let(Hash.new { |h, k| h[k] = k.split(PATTERN).join('_').downcase.to_sym }, T::Hash[T.untyped, T.untyped])
|
35
|
+
|
36
|
+
PATTERN = /[\-_]|(?<=\w)(?=[A-Z])/
|
37
|
+
|
38
|
+
private_constant :ATTRIBUTE_KEYS
|
39
|
+
|
40
|
+
private_constant :PATTERN
|
41
|
+
|
42
|
+
sig { params(k: T.any(Symbol, String)).returns(Symbol) }
|
43
|
+
def attribute_key(k)
|
44
|
+
return k if k.is_a?(Symbol)
|
45
|
+
|
46
|
+
ATTRIBUTE_KEYS[k]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private_constant :Keys
|
51
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
require 'logger'
|
4
|
+
require 'forwardable'
|
5
|
+
|
6
|
+
module Vonage
|
7
|
+
class Logger
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
sig { params(logger: T.nilable(T.any(::Logger, Vonage::Logger))).void }
|
11
|
+
def initialize(logger)
|
12
|
+
@logger = logger || ::Logger.new(nil)
|
13
|
+
end
|
14
|
+
|
15
|
+
extend Forwardable
|
16
|
+
|
17
|
+
::Logger::Severity.constants.map(&:downcase).each do |name|
|
18
|
+
def_delegator :@logger, name, name
|
19
|
+
end
|
20
|
+
|
21
|
+
sig { params(request: T.any(Net::HTTP::Post, Net::HTTP::Get, Net::HTTP::Delete, Net::HTTP::Put)).void }
|
22
|
+
def log_request_info(request)
|
23
|
+
@logger = T.let(@logger, T.nilable(T.any(::Logger, Vonage::Logger)))
|
24
|
+
|
25
|
+
T.must(@logger).info do
|
26
|
+
format('Vonage API request', {
|
27
|
+
method: request.method,
|
28
|
+
path: request.uri.path
|
29
|
+
})
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
sig { params(
|
34
|
+
response: T.any(Net::HTTPOK, Net::HTTPNoContent, Net::HTTPBadRequest, Net::HTTPInternalServerError, Net::HTTPResponse),
|
35
|
+
host: String
|
36
|
+
).void }
|
37
|
+
def log_response_info(response, host)
|
38
|
+
T.must(@logger).info do
|
39
|
+
format('Vonage API response', {
|
40
|
+
host: host,
|
41
|
+
status: response.code,
|
42
|
+
type: response.content_type,
|
43
|
+
length: response.content_length,
|
44
|
+
trace_id: response['x-Vonage-trace-id']
|
45
|
+
})
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
sig { params(message: String, hash: T::Hash[Symbol, T.untyped]).returns(String) }
|
52
|
+
def format(message, hash)
|
53
|
+
return message if hash.nil?
|
54
|
+
|
55
|
+
fields = hash.map { |key, value| "#{key}=#{value}" if value }.compact
|
56
|
+
fields.unshift(message)
|
57
|
+
fields.join(' ')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Vonage
|
5
|
+
class Messages < Namespace
|
6
|
+
extend T::Sig
|
7
|
+
|
8
|
+
self.host = :rest_host
|
9
|
+
|
10
|
+
sig { params(id: String).returns(Vonage::Response) }
|
11
|
+
def get(id)
|
12
|
+
request('/search/message', params: {id: id})
|
13
|
+
end
|
14
|
+
|
15
|
+
sig { params(params: T::Hash[Symbol, T.untyped]).returns(Vonage::Response) }
|
16
|
+
def search(params)
|
17
|
+
request('/search/messages', params: params)
|
18
|
+
end
|
19
|
+
|
20
|
+
sig { params(params: T::Hash[Symbol, T.untyped]).returns(Vonage::Response) }
|
21
|
+
def rejections(params)
|
22
|
+
request('/search/rejections', params: params)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|