nexmo 4.8.0 → 5.0.0.pre1
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 +4 -4
- data/README.md +48 -42
- data/lib/nexmo.rb +20 -0
- data/lib/nexmo/account.rb +23 -0
- data/lib/nexmo/alerts.rb +25 -0
- data/lib/nexmo/applications.rb +25 -0
- data/lib/nexmo/call_dtmf.rb +15 -0
- data/lib/nexmo/call_stream.rb +19 -0
- data/lib/nexmo/call_talk.rb +19 -0
- data/lib/nexmo/calls.rb +68 -0
- data/lib/nexmo/client.rb +75 -324
- data/lib/nexmo/conversions.rb +15 -0
- data/lib/nexmo/entity.rb +53 -0
- data/lib/nexmo/files.rb +25 -0
- data/lib/nexmo/jwt.rb +2 -1
- data/lib/nexmo/keys.rb +31 -0
- data/lib/nexmo/messages.rb +23 -0
- data/lib/nexmo/namespace.rb +83 -0
- data/lib/nexmo/number_insight.rb +21 -0
- data/lib/nexmo/numbers.rb +33 -0
- data/lib/nexmo/pricing.rb +31 -0
- data/lib/nexmo/pricing_types.rb +17 -0
- data/lib/nexmo/signature.rb +9 -1
- data/lib/nexmo/sms.rb +17 -0
- data/lib/nexmo/user_agent.rb +13 -0
- data/lib/nexmo/verify.rb +31 -0
- data/lib/nexmo/version.rb +1 -1
- data/nexmo.gemspec +3 -11
- metadata +39 -23
- data/spec/nexmo/client_spec.rb +0 -651
- data/spec/nexmo/jwt_spec.rb +0 -53
- data/spec/nexmo/params_spec.rb +0 -18
- data/spec/nexmo/signature_spec.rb +0 -20
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nexmo
|
4
|
+
class Conversions < Namespace
|
5
|
+
include Keys
|
6
|
+
|
7
|
+
def track_sms(params)
|
8
|
+
request('/conversions/sms', params: hyphenate(params), type: Post)
|
9
|
+
end
|
10
|
+
|
11
|
+
def track_voice(params)
|
12
|
+
request('/conversions/voice', params: hyphenate(params), type: Post)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/nexmo/entity.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
module Nexmo
|
2
|
+
class Entity
|
3
|
+
def initialize(**kwargs)
|
4
|
+
@attributes = kwargs
|
5
|
+
end
|
6
|
+
|
7
|
+
def []=(key, value)
|
8
|
+
name = self.class.attribute_names[key]
|
9
|
+
|
10
|
+
@attributes[name] = value
|
11
|
+
end
|
12
|
+
|
13
|
+
def respond_to_missing?(name, include_private = false)
|
14
|
+
@attributes.key?(name) or super
|
15
|
+
end
|
16
|
+
|
17
|
+
def method_missing(name, *args)
|
18
|
+
return super unless @attributes.key?(name)
|
19
|
+
|
20
|
+
@attributes[name]
|
21
|
+
end
|
22
|
+
|
23
|
+
def ==(entity)
|
24
|
+
entity.class == self.class && entity.attributes == @attributes
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_h
|
28
|
+
@attributes
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_reader :attributes
|
32
|
+
|
33
|
+
protected :attributes
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def self.attribute_names
|
38
|
+
@attribute_names ||= Hash.new do |hash, key|
|
39
|
+
hash[key] = attribute_name(key)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.attribute_name(key)
|
44
|
+
return key if key.is_a?(Symbol)
|
45
|
+
|
46
|
+
key.split(PATTERN).join(UNDERSCORE).downcase.to_sym
|
47
|
+
end
|
48
|
+
|
49
|
+
PATTERN = /[\-_]|(?<=\w)(?=[A-Z])/
|
50
|
+
|
51
|
+
UNDERSCORE = '_'
|
52
|
+
end
|
53
|
+
end
|
data/lib/nexmo/files.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nexmo
|
4
|
+
class Files < Namespace
|
5
|
+
def get(id)
|
6
|
+
request('/v1/files/' + id.split('/').last)
|
7
|
+
end
|
8
|
+
|
9
|
+
def save(id, filename)
|
10
|
+
request('/v1/files/' + id.split('/').last) do |response|
|
11
|
+
File.open(filename, 'wb') do |file|
|
12
|
+
response.read_body do |chunk|
|
13
|
+
file.write(chunk)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def authorization_header?
|
22
|
+
true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/nexmo/jwt.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'securerandom'
|
2
3
|
require 'openssl'
|
3
4
|
require 'jwt'
|
4
5
|
|
5
6
|
module Nexmo
|
6
7
|
module JWT
|
7
|
-
def self.
|
8
|
+
def self.generate(payload, private_key)
|
8
9
|
payload[:iat] = iat = Time.now.to_i unless payload.key?(:iat) || payload.key?('iat')
|
9
10
|
payload[:exp] = iat + 60 unless payload.key?(:exp) || payload.key?('exp')
|
10
11
|
payload[:jti] = SecureRandom.uuid unless payload.key?(:jti) || payload.key?('jti')
|
data/lib/nexmo/keys.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nexmo
|
4
|
+
module Keys
|
5
|
+
if {}.respond_to?(:transform_keys)
|
6
|
+
def hyphenate(hash)
|
7
|
+
hash.transform_keys { |k| hyphenate_key(k) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def camelcase(hash)
|
11
|
+
hash.transform_keys { |k| camelcase_key(k) }
|
12
|
+
end
|
13
|
+
else
|
14
|
+
def hyphenate(hash)
|
15
|
+
hash.each_with_object({}) { |(k, v), h| h[hyphenate_key(k)] = v }
|
16
|
+
end
|
17
|
+
|
18
|
+
def camelcase(hash)
|
19
|
+
hash.each_with_object({}) { |(k, v), h| h[camelcase_key(k)] = v }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def hyphenate_key(k)
|
24
|
+
k.to_s.tr('_', '-')
|
25
|
+
end
|
26
|
+
|
27
|
+
def camelcase_key(k)
|
28
|
+
k.to_s.gsub(/_(\w)/) { $1.upcase }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nexmo
|
4
|
+
class Messages < Namespace
|
5
|
+
def get(id)
|
6
|
+
request('/search/message', params: {id: id})
|
7
|
+
end
|
8
|
+
|
9
|
+
def search(params)
|
10
|
+
request('/search/messages', params: params)
|
11
|
+
end
|
12
|
+
|
13
|
+
def rejections(params)
|
14
|
+
request('/search/rejections', params: params)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def host
|
20
|
+
'rest.nexmo.com'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Nexmo
|
5
|
+
class Namespace
|
6
|
+
def initialize(client)
|
7
|
+
@client = client
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
Get = Net::HTTP::Get
|
13
|
+
Put = Net::HTTP::Put
|
14
|
+
Post = Net::HTTP::Post
|
15
|
+
Delete = Net::HTTP::Delete
|
16
|
+
|
17
|
+
def host
|
18
|
+
'api.nexmo.com'
|
19
|
+
end
|
20
|
+
|
21
|
+
def authorization_header?
|
22
|
+
false
|
23
|
+
end
|
24
|
+
|
25
|
+
def request(path, params: nil, type: Get, &block)
|
26
|
+
uri = URI('https://' + host + path)
|
27
|
+
|
28
|
+
unless authorization_header?
|
29
|
+
params ||= {}
|
30
|
+
params[:api_key] = @client.api_key
|
31
|
+
params[:api_secret] = @client.api_secret
|
32
|
+
end
|
33
|
+
|
34
|
+
unless type::REQUEST_HAS_BODY || params.nil? || params.empty?
|
35
|
+
uri.query = Params.encode(params)
|
36
|
+
end
|
37
|
+
|
38
|
+
message = type.new(uri.request_uri)
|
39
|
+
|
40
|
+
if type::REQUEST_HAS_BODY
|
41
|
+
message['Content-Type'] = 'application/json'
|
42
|
+
message.body = JSON.generate(params)
|
43
|
+
end
|
44
|
+
|
45
|
+
message['Authorization'] = @client.authorization if authorization_header?
|
46
|
+
message['User-Agent'] = @client.user_agent
|
47
|
+
|
48
|
+
http = Net::HTTP.new(uri.host, Net::HTTP.https_default_port)
|
49
|
+
http.use_ssl = true
|
50
|
+
|
51
|
+
response = http.request(message)
|
52
|
+
|
53
|
+
parse(response, &block)
|
54
|
+
end
|
55
|
+
|
56
|
+
def parse(response, &block)
|
57
|
+
case response
|
58
|
+
when Net::HTTPNoContent
|
59
|
+
:no_content
|
60
|
+
when Net::HTTPSuccess
|
61
|
+
parse_success(response, &block)
|
62
|
+
when Net::HTTPUnauthorized
|
63
|
+
raise AuthenticationError, "#{response.code} response from #{host}"
|
64
|
+
when Net::HTTPClientError
|
65
|
+
raise ClientError, "#{response.code} response from #{host}"
|
66
|
+
when Net::HTTPServerError
|
67
|
+
raise ServerError, "#{response.code} response from #{host}"
|
68
|
+
else
|
69
|
+
raise Error, "#{response.code} response from #{host}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def parse_success(response)
|
74
|
+
if response['Content-Type'].split(';').first == 'application/json'
|
75
|
+
JSON.parse(response.body, object_class: Nexmo::Entity)
|
76
|
+
elsif block_given?
|
77
|
+
yield response
|
78
|
+
else
|
79
|
+
response.body
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nexmo
|
4
|
+
class NumberInsight < Namespace
|
5
|
+
def basic(params)
|
6
|
+
request('/ni/basic/json', params: params)
|
7
|
+
end
|
8
|
+
|
9
|
+
def standard(params)
|
10
|
+
request('/ni/standard/json', params: params)
|
11
|
+
end
|
12
|
+
|
13
|
+
def advanced(params)
|
14
|
+
request('/ni/advanced/json', params: params)
|
15
|
+
end
|
16
|
+
|
17
|
+
def advanced_async(params)
|
18
|
+
request('/ni/advanced/async/json', params: params)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nexmo
|
4
|
+
class Numbers < Namespace
|
5
|
+
include Keys
|
6
|
+
|
7
|
+
def list(params)
|
8
|
+
request('/account/numbers', params: params)
|
9
|
+
end
|
10
|
+
|
11
|
+
def search(params)
|
12
|
+
request('/number/search', params: params)
|
13
|
+
end
|
14
|
+
|
15
|
+
def buy(params)
|
16
|
+
request('/number/buy', params: params, type: Post)
|
17
|
+
end
|
18
|
+
|
19
|
+
def cancel(params)
|
20
|
+
request('/number/cancel', params: params, type: Post)
|
21
|
+
end
|
22
|
+
|
23
|
+
def update(params)
|
24
|
+
request('/number/update', params: camelcase(params), type: Post)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def host
|
30
|
+
'rest.nexmo.com'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nexmo
|
4
|
+
class Pricing < Namespace
|
5
|
+
def initialize(client, type: nil)
|
6
|
+
raise ArgumentError if type.nil?
|
7
|
+
|
8
|
+
@client, @type = client, type
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :type
|
12
|
+
|
13
|
+
def get(country)
|
14
|
+
request('/get-pricing/outbound/' + @type, params: {country: country})
|
15
|
+
end
|
16
|
+
|
17
|
+
def list
|
18
|
+
request('/get-full-pricing/outbound/' + @type)
|
19
|
+
end
|
20
|
+
|
21
|
+
def prefix(prefix)
|
22
|
+
request('/get-prefix-pricing/outbound/' + @type, params: {prefix: prefix})
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def host
|
28
|
+
'rest.nexmo.com'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nexmo
|
4
|
+
class PricingTypes
|
5
|
+
def initialize(client)
|
6
|
+
@client = client
|
7
|
+
end
|
8
|
+
|
9
|
+
def sms
|
10
|
+
@sms ||= Pricing.new(@client, type: 'sms')
|
11
|
+
end
|
12
|
+
|
13
|
+
def voice
|
14
|
+
@voice ||= Pricing.new(@client, type: 'voice')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/nexmo/signature.rb
CHANGED
@@ -2,7 +2,7 @@ require 'digest/md5'
|
|
2
2
|
require 'jwt'
|
3
3
|
|
4
4
|
module Nexmo
|
5
|
-
|
5
|
+
class Signature
|
6
6
|
def self.check(params, secret)
|
7
7
|
params = params.dup
|
8
8
|
|
@@ -11,6 +11,14 @@ module Nexmo
|
|
11
11
|
secure_compare(signature, digest(params, secret))
|
12
12
|
end
|
13
13
|
|
14
|
+
def initialize(client)
|
15
|
+
@client = client
|
16
|
+
end
|
17
|
+
|
18
|
+
def check(params)
|
19
|
+
self.class.check(params, @client.signature_secret)
|
20
|
+
end
|
21
|
+
|
14
22
|
private
|
15
23
|
|
16
24
|
if defined?(::JWT::SecurityUtils) # ruby-jwt v2
|
data/lib/nexmo/sms.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nexmo
|
4
|
+
module UserAgent
|
5
|
+
def self.string(app_name, app_version)
|
6
|
+
identifiers = []
|
7
|
+
identifiers << 'nexmo-ruby/' + VERSION
|
8
|
+
identifiers << 'ruby/' + RUBY_VERSION
|
9
|
+
identifiers << app_name + '/' + app_version if app_name && app_version
|
10
|
+
identifiers.join(' ')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/nexmo/verify.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nexmo
|
4
|
+
class Verify < Namespace
|
5
|
+
alias_method :http_request, :request
|
6
|
+
|
7
|
+
def request(params)
|
8
|
+
http_request('/verify/json', params: params, type: Post)
|
9
|
+
end
|
10
|
+
|
11
|
+
def check(params)
|
12
|
+
http_request('/verify/check/json', params: params, type: Post)
|
13
|
+
end
|
14
|
+
|
15
|
+
def search(params)
|
16
|
+
http_request('/verify/search/json', params: params)
|
17
|
+
end
|
18
|
+
|
19
|
+
def control(params)
|
20
|
+
http_request('/verify/control/json', params: params, type: Post)
|
21
|
+
end
|
22
|
+
|
23
|
+
def cancel(id)
|
24
|
+
control(request_id: id, cmd: 'cancel')
|
25
|
+
end
|
26
|
+
|
27
|
+
def trigger_next_event(id)
|
28
|
+
control(request_id: id, cmd: 'trigger_next_event')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|