nexmo 4.2.0 → 4.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +181 -51
- data/lib/nexmo.rb +155 -31
- data/lib/nexmo/errors/authentication_error.rb +4 -0
- data/lib/nexmo/errors/client_error.rb +4 -0
- data/lib/nexmo/errors/error.rb +4 -0
- data/lib/nexmo/errors/server_error.rb +4 -0
- data/lib/nexmo/jwt.rb +19 -0
- data/lib/nexmo/params.rb +13 -0
- data/lib/nexmo/signature.rb +26 -0
- data/lib/nexmo/version.rb +1 -1
- data/nexmo.gemspec +1 -0
- data/spec/nexmo_spec.rb +246 -36
- metadata +23 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39100089701618826f373695cb54cd0d3c2dde95
|
4
|
+
data.tar.gz: fec02db08356b21dd202c39b88fd06a92cb52516
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52979a00c3fcbc1b52fd7c84b51b0b2fa312a8543c6a15585fd037ae6f35479016e67cf1176f32be71ce57a91caf58ee72e98aea93c906de4256bbbeda874aa3
|
7
|
+
data.tar.gz: 67c7ff10e27a0862833c95483f79bf16f1b39b0b0d1423bb7a509e54e946359d15556153ca95956cf15a964314d59595eb99d8e8a3bae196f9c7f20ea887a4d0
|
data/README.md
CHANGED
@@ -8,7 +8,10 @@ need a Nexmo account. Sign up [for free at nexmo.com][signup].
|
|
8
8
|
|
9
9
|
* [Installation](#installation)
|
10
10
|
* [Usage](#usage)
|
11
|
-
* [
|
11
|
+
* [SMS API](#sms-api)
|
12
|
+
* [Voice API](#voice-api)
|
13
|
+
* [Verify API](#verify-api)
|
14
|
+
* [Application API](#application-api)
|
12
15
|
* [Coverage](#api-coverage)
|
13
16
|
* [License](#license)
|
14
17
|
|
@@ -28,100 +31,150 @@ Alternatively you can clone the repository:
|
|
28
31
|
Usage
|
29
32
|
-----
|
30
33
|
|
31
|
-
|
32
|
-
environment variables; require the nexmo library; and construct a client object.
|
33
|
-
For example:
|
34
|
+
Begin by requiring the nexmo library:
|
34
35
|
|
35
36
|
```ruby
|
36
37
|
require 'nexmo'
|
37
|
-
|
38
|
-
client = Nexmo::Client.new
|
39
38
|
```
|
40
39
|
|
41
|
-
|
42
|
-
and `secret` options:
|
40
|
+
Then construct a client object with your key and secret:
|
43
41
|
|
44
42
|
```ruby
|
45
|
-
require 'nexmo'
|
46
|
-
|
47
43
|
client = Nexmo::Client.new(key: 'YOUR-API-KEY', secret: 'YOUR-API-SECRET')
|
48
44
|
```
|
49
45
|
|
46
|
+
For production you can specify the `NEXMO_API_KEY` and `NEXMO_API_SECRET`
|
47
|
+
environment variables instead of specifying the key and secret explicitly.
|
50
48
|
|
51
|
-
|
52
|
-
|
49
|
+
For newer endpoints that support JWT authentication such as the Voice API,
|
50
|
+
you can also specify the `application_id` and `private_key` arguments:
|
53
51
|
|
54
|
-
|
52
|
+
```ruby
|
53
|
+
client = Nexmo::Client.new(application_id: application_id, private_key: private_key)
|
54
|
+
```
|
55
55
|
|
56
|
-
|
57
|
-
|
56
|
+
In order to check signatures for incoming webhook requests, you'll also need
|
57
|
+
to specify the `signature_secret` argument (or the `NEXMO_SIGNATURE_SECRET`
|
58
|
+
environment variable).
|
58
59
|
|
59
|
-
```ruby
|
60
|
-
response = client.send_message(from: 'Ruby', to: 'YOUR NUMBER', text: 'Hello world')
|
61
60
|
|
62
|
-
|
61
|
+
## SMS API
|
63
62
|
|
64
|
-
|
65
|
-
|
63
|
+
### Send a text message
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
response = client.send_message(from: 'Ruby', to: 'YOUR NUMBER', text: 'Hello world')
|
66
67
|
|
67
|
-
|
68
|
+
if response['messages'][0]['status'] == '0'
|
69
|
+
puts "Sent message #{response['messages'][0]['message-id']}"
|
68
70
|
else
|
69
|
-
puts "Error: #{response['error-text']}"
|
71
|
+
puts "Error: #{response['messages'][0]['error-text']}"
|
70
72
|
end
|
71
73
|
```
|
72
74
|
|
73
|
-
|
75
|
+
Docs: [https://docs.nexmo.com/messaging/sms-api/api-reference#request](https://docs.nexmo.com/messaging/sms-api/api-reference#request?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library)
|
74
76
|
|
75
|
-
|
77
|
+
|
78
|
+
## Voice API
|
79
|
+
|
80
|
+
### Make a call
|
76
81
|
|
77
82
|
```ruby
|
78
|
-
|
83
|
+
response = client.create_call({
|
84
|
+
to: [{type: 'phone', number: '14843331234'}],
|
85
|
+
from: {type: 'phone', number: '14843335555'},
|
86
|
+
answer_url: ['https://example.com/answer']
|
87
|
+
})
|
88
|
+
```
|
79
89
|
|
80
|
-
|
90
|
+
Docs: [https://docs.nexmo.com/voice/voice-api/api-reference#call_create](https://docs.nexmo.com/voice/voice-api/api-reference#call_create?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library)
|
91
|
+
|
92
|
+
### Retrieve a list of calls
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
response = client.get_calls
|
81
96
|
```
|
82
97
|
|
83
|
-
|
98
|
+
Docs: [https://docs.nexmo.com/voice/voice-api/api-reference#call_retrieve](https://docs.nexmo.com/voice/voice-api/api-reference#call_retrieve?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library)
|
99
|
+
|
100
|
+
### Retrieve a single call
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
response = client.get_call(uuid)
|
104
|
+
```
|
84
105
|
|
85
|
-
|
86
|
-
own phone number during signup, or implement second factor authentication during signin.
|
106
|
+
Docs: [https://docs.nexmo.com/voice/voice-api/api-reference#call_retrieve_single](https://docs.nexmo.com/voice/voice-api/api-reference#call_retrieve_single?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library)
|
87
107
|
|
88
|
-
|
108
|
+
### Update a call
|
89
109
|
|
90
110
|
```ruby
|
91
|
-
response = client.
|
111
|
+
response = client.update_call(uuid, action: 'hangup')
|
112
|
+
```
|
92
113
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
114
|
+
Docs: [https://docs.nexmo.com/voice/voice-api/api-reference#call_modify_single](https://docs.nexmo.com/voice/voice-api/api-reference#call_modify_single?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library)
|
115
|
+
|
116
|
+
### Stream audio to a call
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
stream_url = 'https://nexmo-community.github.io/ncco-examples/assets/voice_api_audio_streaming.mp3'
|
120
|
+
|
121
|
+
response = client.send_audio(uuid, stream_url: stream_url)
|
98
122
|
```
|
99
123
|
|
100
|
-
|
101
|
-
|
124
|
+
Docs: [https://docs.nexmo.com/voice/voice-api/api-reference#stream_put](https://docs.nexmo.com/voice/voice-api/api-reference#stream_put?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library)
|
125
|
+
|
126
|
+
### Stop streaming audio to a call
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
response = client.stop_audio(uuid)
|
130
|
+
```
|
102
131
|
|
103
|
-
|
132
|
+
Docs: [https://docs.nexmo.com/voice/voice-api/api-reference#stream_delete](https://docs.nexmo.com/voice/voice-api/api-reference#stream_delete?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library)
|
104
133
|
|
105
|
-
|
106
|
-
to cancel an in-progress verification:
|
134
|
+
### Send a synthesized speech message to a call
|
107
135
|
|
108
136
|
```ruby
|
109
|
-
client.
|
137
|
+
response = client.send_speech(uuid, text: 'Hello')
|
110
138
|
```
|
111
139
|
|
112
|
-
|
113
|
-
|
140
|
+
Docs: [https://docs.nexmo.com/voice/voice-api/api-reference#talk_put](https://docs.nexmo.com/voice/voice-api/api-reference#talk_put?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library)
|
141
|
+
|
142
|
+
### Stop sending a synthesized speech message to a call
|
114
143
|
|
115
144
|
```ruby
|
116
|
-
client.
|
145
|
+
response = client.stop_speech(uuid)
|
117
146
|
```
|
118
147
|
|
119
|
-
|
148
|
+
Docs: [https://docs.nexmo.com/voice/voice-api/api-reference#talk_delete](https://docs.nexmo.com/voice/voice-api/api-reference#talk_delete?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library)
|
149
|
+
|
150
|
+
### Send DTMF tones to a call
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
response = client.send_dtmf(uuid, digits: '1234')
|
154
|
+
```
|
155
|
+
|
156
|
+
Docs: [https://docs.nexmo.com/voice/voice-api/api-reference#dtmf_put](https://docs.nexmo.com/voice/voice-api/api-reference#dtmf_put?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library)
|
157
|
+
|
158
|
+
|
159
|
+
## Verify API
|
160
|
+
|
161
|
+
### Start a verification
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
response = client.start_verification(number: '441632960960', brand: 'MyApp')
|
165
|
+
|
166
|
+
if response['status'] == '0'
|
167
|
+
puts "Started verification request_id=#{response['request_id']}"
|
168
|
+
else
|
169
|
+
puts "Error: #{response['error_text']}"
|
170
|
+
end
|
171
|
+
```
|
120
172
|
|
121
|
-
|
173
|
+
Docs: [https://docs.nexmo.com/verify/api-reference/api-reference#vrequest](https://docs.nexmo.com/verify/api-reference/api-reference#vrequest?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library)
|
122
174
|
|
123
|
-
|
124
|
-
|
175
|
+
The response contains a verification request id which you will need to store temporarily.
|
176
|
+
|
177
|
+
### Check a verification
|
125
178
|
|
126
179
|
```ruby
|
127
180
|
response = client.check_verification('00e6c3377e5348cdaf567e1417c707a5', code: '1234')
|
@@ -133,9 +186,88 @@ else
|
|
133
186
|
end
|
134
187
|
```
|
135
188
|
|
189
|
+
Docs: [https://docs.nexmo.com/verify/api-reference/api-reference#check](https://docs.nexmo.com/verify/api-reference/api-reference#check?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library)
|
190
|
+
|
136
191
|
The verification request id comes from the call to the start_verification method.
|
192
|
+
|
137
193
|
The PIN code is entered into your application by the user.
|
138
194
|
|
195
|
+
### Cancel a verification
|
196
|
+
|
197
|
+
```ruby
|
198
|
+
client.cancel_verification('00e6c3377e5348cdaf567e1417c707a5')
|
199
|
+
```
|
200
|
+
|
201
|
+
Docs: [https://docs.nexmo.com/verify/api-reference/api-reference#control](https://docs.nexmo.com/verify/api-reference/api-reference#control?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library)
|
202
|
+
|
203
|
+
### Trigger next verification step
|
204
|
+
|
205
|
+
```ruby
|
206
|
+
client.trigger_next_verification_event('00e6c3377e5348cdaf567e1417c707a5')
|
207
|
+
```
|
208
|
+
|
209
|
+
Docs: [https://docs.nexmo.com/verify/api-reference/api-reference#control](https://docs.nexmo.com/verify/api-reference/api-reference#control?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library)
|
210
|
+
|
211
|
+
|
212
|
+
## Application API
|
213
|
+
|
214
|
+
### Create an application
|
215
|
+
|
216
|
+
```ruby
|
217
|
+
response = client.create_application(name: 'Example App', type: 'voice', answer_url: answer_url)
|
218
|
+
```
|
219
|
+
|
220
|
+
Docs: [https://docs.nexmo.com/tools/application-api/api-reference#create](https://docs.nexmo.com/tools/application-api/api-reference#create?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library)
|
221
|
+
|
222
|
+
### Retrieve a list of applications
|
223
|
+
|
224
|
+
```ruby
|
225
|
+
response = client.get_applications
|
226
|
+
```
|
227
|
+
|
228
|
+
Docs: [https://docs.nexmo.com/tools/application-api/api-reference#list](https://docs.nexmo.com/tools/application-api/api-reference#list?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library)
|
229
|
+
|
230
|
+
### Retrieve a single application
|
231
|
+
|
232
|
+
```ruby
|
233
|
+
response = client.get_application(uuid)
|
234
|
+
```
|
235
|
+
|
236
|
+
Docs: [https://docs.nexmo.com/tools/application-api/api-reference#retrieve](https://docs.nexmo.com/tools/application-api/api-reference#retrieve?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library)
|
237
|
+
|
238
|
+
### Update an application
|
239
|
+
|
240
|
+
```ruby
|
241
|
+
response = client.update_application(uuid, answer_method: 'POST')
|
242
|
+
```
|
243
|
+
|
244
|
+
Docs: [https://docs.nexmo.com/tools/application-api/api-reference#update](https://docs.nexmo.com/tools/application-api/api-reference#update?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library)
|
245
|
+
|
246
|
+
### Delete an application
|
247
|
+
|
248
|
+
```ruby
|
249
|
+
response = client.delete_application(uuid)
|
250
|
+
```
|
251
|
+
|
252
|
+
Docs: [https://docs.nexmo.com/tools/application-api/api-reference#delete](https://docs.nexmo.com/tools/application-api/api-reference#delete?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library)
|
253
|
+
|
254
|
+
|
255
|
+
## Validate webhook signatures
|
256
|
+
|
257
|
+
```ruby
|
258
|
+
client = Nexmo::Client.new(signature_secret: 'secret')
|
259
|
+
|
260
|
+
if client.check_signature(request.params):
|
261
|
+
# valid signature
|
262
|
+
else:
|
263
|
+
# invalid signature
|
264
|
+
```
|
265
|
+
|
266
|
+
Docs: [https://docs.nexmo.com/messaging/signing-messages](https://docs.nexmo.com/messaging/signing-messages?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library)
|
267
|
+
|
268
|
+
Note: you'll need to contact support@nexmo.com to enable message signing on
|
269
|
+
your account before you can validate webhook signatures.
|
270
|
+
|
139
271
|
|
140
272
|
API Coverage
|
141
273
|
------------
|
@@ -186,6 +318,4 @@ License
|
|
186
318
|
This library is released under the [MIT License][license]
|
187
319
|
|
188
320
|
[signup]: https://dashboard.nexmo.com/sign-up?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library
|
189
|
-
[doc_sms]: https://docs.nexmo.com/messaging/sms-api?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library
|
190
|
-
[doc_verify]: https://docs.nexmo.com/verify/api-reference?utm_source=DEV_REL&utm_medium=github&utm_campaign=ruby-client-library
|
191
321
|
[license]: LICENSE.txt
|
data/lib/nexmo.rb
CHANGED
@@ -1,17 +1,15 @@
|
|
1
1
|
require 'nexmo/version'
|
2
|
+
require 'nexmo/params'
|
3
|
+
require 'nexmo/jwt'
|
4
|
+
require 'nexmo/signature'
|
5
|
+
require 'nexmo/errors/error'
|
6
|
+
require 'nexmo/errors/client_error'
|
7
|
+
require 'nexmo/errors/server_error'
|
8
|
+
require 'nexmo/errors/authentication_error'
|
2
9
|
require 'net/http'
|
3
10
|
require 'json'
|
4
|
-
require 'cgi'
|
5
11
|
|
6
12
|
module Nexmo
|
7
|
-
class Error < StandardError; end
|
8
|
-
|
9
|
-
class ClientError < Error; end
|
10
|
-
|
11
|
-
class ServerError < Error; end
|
12
|
-
|
13
|
-
class AuthenticationError < ClientError; end
|
14
|
-
|
15
13
|
class Client
|
16
14
|
attr_accessor :key, :secret
|
17
15
|
|
@@ -20,9 +18,23 @@ module Nexmo
|
|
20
18
|
|
21
19
|
@secret = options.fetch(:secret) { ENV.fetch('NEXMO_API_SECRET') }
|
22
20
|
|
21
|
+
@signature_secret = options.fetch(:signature_secret) { ENV['NEXMO_SIGNATURE_SECRET'] }
|
22
|
+
|
23
|
+
@application_id = options[:application_id]
|
24
|
+
|
25
|
+
@private_key = options[:private_key]
|
26
|
+
|
23
27
|
@host = options.fetch(:host) { 'rest.nexmo.com' }
|
24
28
|
|
25
29
|
@api_host = options.fetch(:api_host) { 'api.nexmo.com' }
|
30
|
+
|
31
|
+
@sns_host = options.fetch(:sns_host) { 'sns.nexmo.com' }
|
32
|
+
|
33
|
+
@user_agent = "ruby-nexmo/#{VERSION}/#{RUBY_VERSION}"
|
34
|
+
|
35
|
+
if options.key?(:app_name) && options.key?(:app_version)
|
36
|
+
@user_agent << "/#{options[:app_name]}/#{options[:app_version]}"
|
37
|
+
end
|
26
38
|
end
|
27
39
|
|
28
40
|
def send_message(params)
|
@@ -117,15 +129,29 @@ module Nexmo
|
|
117
129
|
post(@host, '/sc/us/alert/opt-in/manage/json', params)
|
118
130
|
end
|
119
131
|
|
132
|
+
def sns_publish(message, params)
|
133
|
+
post(@sns_host, '/sns/json', {cmd: 'publish', message: message}.merge(params))
|
134
|
+
end
|
135
|
+
|
136
|
+
def sns_subscribe(recipient, params)
|
137
|
+
post(@sns_host, '/sns/json', {cmd: 'subscribe', to: recipient}.merge(params))
|
138
|
+
end
|
139
|
+
|
120
140
|
def initiate_call(params)
|
141
|
+
Kernel.warn "#{self.class}##{__method__} is deprecated (use the Voice API instead)."
|
142
|
+
|
121
143
|
post(@host, '/call/json', params)
|
122
144
|
end
|
123
145
|
|
124
146
|
def initiate_tts_call(params)
|
147
|
+
Kernel.warn "#{self.class}##{__method__} is deprecated (use the Voice API instead)."
|
148
|
+
|
125
149
|
post(@api_host, '/tts/json', params)
|
126
150
|
end
|
127
151
|
|
128
152
|
def initiate_tts_prompt_call(params)
|
153
|
+
Kernel.warn "#{self.class}##{__method__} is deprecated (use the Voice API instead)."
|
154
|
+
|
129
155
|
post(@api_host, '/tts-prompt/json', params)
|
130
156
|
end
|
131
157
|
|
@@ -134,6 +160,8 @@ module Nexmo
|
|
134
160
|
end
|
135
161
|
|
136
162
|
def send_verification_request(params)
|
163
|
+
Kernel.warn "#{self.class}##{__method__} is deprecated (use #start_verification instead)."
|
164
|
+
|
137
165
|
post(@api_host, '/verify/json', params)
|
138
166
|
end
|
139
167
|
|
@@ -142,6 +170,8 @@ module Nexmo
|
|
142
170
|
end
|
143
171
|
|
144
172
|
def check_verification_request(params)
|
173
|
+
Kernel.warn "#{self.class}##{__method__} is deprecated (use #check_verification instead)."
|
174
|
+
|
145
175
|
post(@api_host, '/verify/check/json', params)
|
146
176
|
end
|
147
177
|
|
@@ -150,6 +180,8 @@ module Nexmo
|
|
150
180
|
end
|
151
181
|
|
152
182
|
def get_verification_request(id)
|
183
|
+
Kernel.warn "#{self.class}##{__method__} is deprecated (use #get_verification instead)."
|
184
|
+
|
153
185
|
get(@api_host, '/verify/search/json', request_id: id)
|
154
186
|
end
|
155
187
|
|
@@ -162,6 +194,8 @@ module Nexmo
|
|
162
194
|
end
|
163
195
|
|
164
196
|
def control_verification_request(params)
|
197
|
+
Kernel.warn "#{self.class}##{__method__} is deprecated."
|
198
|
+
|
165
199
|
post(@api_host, '/verify/control/json', params)
|
166
200
|
end
|
167
201
|
|
@@ -177,18 +211,75 @@ module Nexmo
|
|
177
211
|
post(@host, '/ni/json', params)
|
178
212
|
end
|
179
213
|
|
180
|
-
|
214
|
+
def get_applications(params = {})
|
215
|
+
get(@api_host, '/v1/applications', params)
|
216
|
+
end
|
217
|
+
|
218
|
+
def get_application(id)
|
219
|
+
get(@api_host, "/v1/applications/#{id}")
|
220
|
+
end
|
221
|
+
|
222
|
+
def create_application(params)
|
223
|
+
post(@api_host, '/v1/applications', params)
|
224
|
+
end
|
225
|
+
|
226
|
+
def update_application(id, params)
|
227
|
+
put(@api_host, "/v1/applications/#{id}", params)
|
228
|
+
end
|
229
|
+
|
230
|
+
def delete_application(id)
|
231
|
+
delete(@api_host, "/v1/applications/#{id}")
|
232
|
+
end
|
233
|
+
|
234
|
+
def create_call(params)
|
235
|
+
api_request(Net::HTTP::Post, '/v1/calls', params)
|
236
|
+
end
|
237
|
+
|
238
|
+
def get_calls(params = nil)
|
239
|
+
api_request(Net::HTTP::Get, '/v1/calls', params)
|
240
|
+
end
|
181
241
|
|
182
|
-
|
242
|
+
def get_call(uuid)
|
243
|
+
api_request(Net::HTTP::Get, "/v1/calls/#{uuid}")
|
244
|
+
end
|
245
|
+
|
246
|
+
def update_call(uuid, params)
|
247
|
+
api_request(Net::HTTP::Put, "/v1/calls/#{uuid}", params)
|
248
|
+
end
|
249
|
+
|
250
|
+
def send_audio(uuid, params)
|
251
|
+
api_request(Net::HTTP::Put, "/v1/calls/#{uuid}/stream", params)
|
252
|
+
end
|
253
|
+
|
254
|
+
def stop_audio(uuid)
|
255
|
+
api_request(Net::HTTP::Delete, "/v1/calls/#{uuid}/stream")
|
256
|
+
end
|
257
|
+
|
258
|
+
def send_speech(uuid, params)
|
259
|
+
api_request(Net::HTTP::Put, "/v1/calls/#{uuid}/talk", params)
|
260
|
+
end
|
261
|
+
|
262
|
+
def stop_speech(uuid)
|
263
|
+
api_request(Net::HTTP::Delete, "/v1/calls/#{uuid}/talk")
|
264
|
+
end
|
265
|
+
|
266
|
+
def send_dtmf(uuid, params)
|
267
|
+
api_request(Net::HTTP::Put, "/v1/calls/#{uuid}/dtmf", params)
|
268
|
+
end
|
269
|
+
|
270
|
+
def check_signature(params)
|
271
|
+
Signature.check(params, @signature_secret)
|
272
|
+
end
|
273
|
+
|
274
|
+
private
|
183
275
|
|
184
276
|
def get(host, request_uri, params = {})
|
185
277
|
uri = URI('https://' + host + request_uri)
|
186
|
-
uri.query =
|
278
|
+
uri.query = Params.encode(params.merge(api_key: @key, api_secret: @secret))
|
187
279
|
|
188
280
|
message = Net::HTTP::Get.new(uri.request_uri)
|
189
|
-
message['User-Agent'] = USER_AGENT
|
190
281
|
|
191
|
-
|
282
|
+
request(uri, message)
|
192
283
|
end
|
193
284
|
|
194
285
|
def post(host, request_uri, params)
|
@@ -196,19 +287,60 @@ module Nexmo
|
|
196
287
|
|
197
288
|
message = Net::HTTP::Post.new(uri.request_uri)
|
198
289
|
message.form_data = params.merge(api_key: @key, api_secret: @secret)
|
199
|
-
message['User-Agent'] = USER_AGENT
|
200
290
|
|
201
|
-
|
291
|
+
request(uri, message)
|
292
|
+
end
|
293
|
+
|
294
|
+
def put(host, request_uri, params)
|
295
|
+
uri = URI('https://' + host + request_uri)
|
296
|
+
|
297
|
+
message = Net::HTTP::Put.new(uri.request_uri)
|
298
|
+
message.form_data = params.merge(api_key: @key, api_secret: @secret)
|
299
|
+
|
300
|
+
request(uri, message)
|
301
|
+
end
|
302
|
+
|
303
|
+
def delete(host, request_uri)
|
304
|
+
uri = URI('https://' + host + request_uri)
|
305
|
+
uri.query = Params.encode({api_key: @key, api_secret: @secret})
|
306
|
+
|
307
|
+
message = Net::HTTP::Delete.new(uri.request_uri)
|
308
|
+
|
309
|
+
request(uri, message)
|
310
|
+
end
|
311
|
+
|
312
|
+
def api_request(message_class, path, params = nil)
|
313
|
+
uri = URI('https://' + @api_host + path)
|
314
|
+
|
315
|
+
unless message_class::REQUEST_HAS_BODY || params.nil? || params.empty?
|
316
|
+
uri.query = Params.encode(params)
|
317
|
+
end
|
318
|
+
|
319
|
+
message = message_class.new(uri.request_uri)
|
320
|
+
|
321
|
+
if message_class::REQUEST_HAS_BODY
|
322
|
+
message['Content-Type'] = 'application/json'
|
323
|
+
message.body = JSON.generate(params)
|
324
|
+
end
|
325
|
+
|
326
|
+
auth_payload = {application_id: @application_id}
|
327
|
+
|
328
|
+
message['Authorization'] = JWT.auth_header(auth_payload, @private_key)
|
329
|
+
|
330
|
+
request(uri, message)
|
202
331
|
end
|
203
332
|
|
204
333
|
def request(uri, message)
|
205
334
|
http = Net::HTTP.new(uri.host, Net::HTTP.https_default_port)
|
206
335
|
http.use_ssl = true
|
207
|
-
http.request(message)
|
208
|
-
end
|
209
336
|
|
210
|
-
|
337
|
+
message['User-Agent'] = @user_agent
|
338
|
+
|
339
|
+
http_response = http.request(message)
|
340
|
+
|
211
341
|
case http_response
|
342
|
+
when Net::HTTPNoContent
|
343
|
+
:no_content
|
212
344
|
when Net::HTTPSuccess
|
213
345
|
if http_response['Content-Type'].split(';').first == 'application/json'
|
214
346
|
JSON.parse(http_response.body)
|
@@ -216,22 +348,14 @@ module Nexmo
|
|
216
348
|
http_response.body
|
217
349
|
end
|
218
350
|
when Net::HTTPUnauthorized
|
219
|
-
raise AuthenticationError, "#{http_response.code} response from #{host}"
|
351
|
+
raise AuthenticationError, "#{http_response.code} response from #{uri.host}"
|
220
352
|
when Net::HTTPClientError
|
221
|
-
raise ClientError, "#{http_response.code} response from #{host}"
|
353
|
+
raise ClientError, "#{http_response.code} response from #{uri.host}"
|
222
354
|
when Net::HTTPServerError
|
223
|
-
raise ServerError, "#{http_response.code} response from #{host}"
|
355
|
+
raise ServerError, "#{http_response.code} response from #{uri.host}"
|
224
356
|
else
|
225
|
-
raise Error, "#{http_response.code} response from #{host}"
|
357
|
+
raise Error, "#{http_response.code} response from #{uri.host}"
|
226
358
|
end
|
227
359
|
end
|
228
|
-
|
229
|
-
def query_string(params)
|
230
|
-
params.flat_map { |k, vs| Array(vs).map { |v| "#{escape(k)}=#{escape(v)}" } }.join('&')
|
231
|
-
end
|
232
|
-
|
233
|
-
def escape(component)
|
234
|
-
CGI.escape(component.to_s)
|
235
|
-
end
|
236
360
|
end
|
237
361
|
end
|
data/lib/nexmo/jwt.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'openssl'
|
3
|
+
require 'jwt'
|
4
|
+
|
5
|
+
module Nexmo
|
6
|
+
module JWT
|
7
|
+
def self.auth_header(payload, private_key)
|
8
|
+
payload[:iat] = iat = Time.now.to_i
|
9
|
+
payload[:exp] = iat + 60
|
10
|
+
payload[:jti] = SecureRandom.uuid
|
11
|
+
|
12
|
+
private_key = OpenSSL::PKey::RSA.new(private_key) unless private_key.respond_to?(:sign)
|
13
|
+
|
14
|
+
token = ::JWT.encode(payload, private_key, 'RS256')
|
15
|
+
|
16
|
+
"Bearer #{token}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/nexmo/params.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
require 'jwt'
|
3
|
+
|
4
|
+
module Nexmo
|
5
|
+
module Signature
|
6
|
+
def self.check(params, secret)
|
7
|
+
params = params.dup
|
8
|
+
|
9
|
+
signature = params.delete(:sig)
|
10
|
+
|
11
|
+
::JWT.secure_compare(signature, digest(params, secret))
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.digest(params, secret)
|
15
|
+
md5 = Digest::MD5.new
|
16
|
+
|
17
|
+
params.sort.each do |k, v|
|
18
|
+
md5.update("&#{k}=#{v}")
|
19
|
+
end
|
20
|
+
|
21
|
+
md5.update(secret)
|
22
|
+
|
23
|
+
md5.hexdigest
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/nexmo/version.rb
CHANGED
data/nexmo.gemspec
CHANGED
@@ -12,6 +12,7 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.summary = 'This is the Ruby client library for Nexmo\'s API. To use it you\'ll need a Nexmo account. Sign up for free at https://www.nexmo.com'
|
13
13
|
s.files = Dir.glob('{lib,spec}/**/*') + %w(LICENSE.txt README.md nexmo.gemspec)
|
14
14
|
s.required_ruby_version = '>= 1.9.3'
|
15
|
+
s.add_dependency('jwt')
|
15
16
|
s.add_development_dependency('rake', '~> 10.1')
|
16
17
|
s.add_development_dependency('webmock', '~> 1.18')
|
17
18
|
s.add_development_dependency('minitest', '~> 5.0')
|
data/spec/nexmo_spec.rb
CHANGED
@@ -8,24 +8,28 @@ describe 'Nexmo::Client' do
|
|
8
8
|
|
9
9
|
@api_secret = 'api_secret_xxx'
|
10
10
|
|
11
|
+
@application_id = 'nexmo-application-id'
|
12
|
+
|
13
|
+
@private_key = File.read('test/private_key.txt')
|
14
|
+
|
11
15
|
@base_url = 'https://rest.nexmo.com'
|
12
16
|
|
13
17
|
@api_base_url = 'https://api.nexmo.com'
|
14
18
|
|
19
|
+
@sns_base_url = 'https://sns.nexmo.com'
|
20
|
+
|
15
21
|
@response_body = {body: '{"key":"value"}', headers: {'Content-Type' => 'application/json;charset=utf-8'}}
|
16
22
|
|
17
23
|
@response_object = {'key' => 'value'}
|
18
24
|
|
19
|
-
@
|
20
|
-
|
21
|
-
@client = Nexmo::Client.new(key: @api_key, secret: @api_secret)
|
25
|
+
@client = Nexmo::Client.new(key: @api_key, secret: @api_secret, application_id: @application_id, private_key: @private_key)
|
22
26
|
end
|
23
27
|
|
24
28
|
describe 'send_message method' do
|
25
29
|
it 'posts to the sms resource and returns the response object' do
|
26
30
|
expect_post "#@base_url/sms/json", "from=ruby&to=number&text=Hey!&api_key=#@api_key&api_secret=#@api_secret"
|
27
31
|
|
28
|
-
@client.send_message(
|
32
|
+
@client.send_message(from: 'ruby', to: 'number', text: 'Hey!').must_equal(@response_object)
|
29
33
|
end
|
30
34
|
end
|
31
35
|
|
@@ -93,6 +97,14 @@ describe 'Nexmo::Client' do
|
|
93
97
|
end
|
94
98
|
end
|
95
99
|
|
100
|
+
describe 'get_available_numbers method' do
|
101
|
+
it 'fetches the number search resource with the given parameters and returns the response object' do
|
102
|
+
expect_get "#@base_url/number/search?api_key=#@api_key&api_secret=#@api_secret&country=CA&size=25"
|
103
|
+
|
104
|
+
@client.get_available_numbers('CA', size: 25).must_equal(@response_object)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
96
108
|
describe 'buy_number method' do
|
97
109
|
it 'purchases the number requested with the given parameters and returns the response object' do
|
98
110
|
expect_post "#@base_url/number/buy", "api_key=#@api_key&api_secret=#@api_secret&country=US&msisdn=number"
|
@@ -151,7 +163,7 @@ describe 'Nexmo::Client' do
|
|
151
163
|
it 'posts to the ussd resource and returns the response object' do
|
152
164
|
expect_post "#@base_url/ussd/json", "api_key=#@api_key&api_secret=#@api_secret&from=MyCompany20&to=447525856424&text=Hello"
|
153
165
|
|
154
|
-
@client.send_ussd_push_message(from: 'MyCompany20', to: '447525856424', text: 'Hello')
|
166
|
+
@client.send_ussd_push_message(from: 'MyCompany20', to: '447525856424', text: 'Hello').must_equal(@response_object)
|
155
167
|
end
|
156
168
|
end
|
157
169
|
|
@@ -159,7 +171,7 @@ describe 'Nexmo::Client' do
|
|
159
171
|
it 'posts to the ussd prompt resource and returns the response object' do
|
160
172
|
expect_post "#@base_url/ussd-prompt/json", "api_key=#@api_key&api_secret=#@api_secret&from=virtual-number&to=447525856424&text=Hello"
|
161
173
|
|
162
|
-
@client.send_ussd_prompt_message(from: 'virtual-number', to: '447525856424', text: 'Hello')
|
174
|
+
@client.send_ussd_prompt_message(from: 'virtual-number', to: '447525856424', text: 'Hello').must_equal(@response_object)
|
163
175
|
end
|
164
176
|
end
|
165
177
|
|
@@ -167,7 +179,7 @@ describe 'Nexmo::Client' do
|
|
167
179
|
it 'posts to the short code two factor authentication resource and returns the response object' do
|
168
180
|
expect_post "#@base_url/sc/us/2fa/json", "api_key=#@api_key&api_secret=#@api_secret&to=16365553226&pin=1234"
|
169
181
|
|
170
|
-
@client.send_2fa_message(to: '16365553226', pin: 1234)
|
182
|
+
@client.send_2fa_message(to: '16365553226', pin: 1234).must_equal(@response_object)
|
171
183
|
end
|
172
184
|
end
|
173
185
|
|
@@ -175,7 +187,7 @@ describe 'Nexmo::Client' do
|
|
175
187
|
it 'posts to the short code alert resource and returns the response object' do
|
176
188
|
expect_post "#@base_url/sc/us/alert/json", "api_key=#@api_key&api_secret=#@api_secret&to=16365553226&server=host&link=http://example.com/"
|
177
189
|
|
178
|
-
@client.send_event_alert_message(to: '16365553226', server: 'host', link: 'http://example.com/')
|
190
|
+
@client.send_event_alert_message(to: '16365553226', server: 'host', link: 'http://example.com/').must_equal(@response_object)
|
179
191
|
end
|
180
192
|
end
|
181
193
|
|
@@ -183,7 +195,7 @@ describe 'Nexmo::Client' do
|
|
183
195
|
it 'posts to the short code marketing resource and returns the response object' do
|
184
196
|
expect_post "#@base_url/sc/us/marketing/json", "api_key=#@api_key&api_secret=#@api_secret&from=666&to=16365553226&keyword=NEXMO&text=Hello"
|
185
197
|
|
186
|
-
@client.send_marketing_message(from: '666', to: '16365553226', keyword: 'NEXMO', text: 'Hello')
|
198
|
+
@client.send_marketing_message(from: '666', to: '16365553226', keyword: 'NEXMO', text: 'Hello').must_equal(@response_object)
|
187
199
|
end
|
188
200
|
end
|
189
201
|
|
@@ -191,7 +203,7 @@ describe 'Nexmo::Client' do
|
|
191
203
|
it 'fetches the short code alert opt-in query resource and returns the response object' do
|
192
204
|
expect_get "#@base_url/sc/us/alert/opt-in/query/json?api_key=#@api_key&api_secret=#@api_secret"
|
193
205
|
|
194
|
-
@client.get_event_alert_numbers
|
206
|
+
@client.get_event_alert_numbers.must_equal(@response_object)
|
195
207
|
end
|
196
208
|
end
|
197
209
|
|
@@ -199,7 +211,23 @@ describe 'Nexmo::Client' do
|
|
199
211
|
it 'posts to the short code alert opt-in manage resource and returns the response object' do
|
200
212
|
expect_post "#@base_url/sc/us/alert/opt-in/manage/json", "api_key=#@api_key&api_secret=#@api_secret&msisdn=441632960960"
|
201
213
|
|
202
|
-
@client.resubscribe_event_alert_number(msisdn: '441632960960')
|
214
|
+
@client.resubscribe_event_alert_number(msisdn: '441632960960').must_equal(@response_object)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe 'sns_publish method' do
|
219
|
+
it 'posts to the sns resource and returns the response object' do
|
220
|
+
expect_post "#@sns_base_url/sns/json", "api_key=#@api_key&api_secret=#@api_secret&cmd=publish&message=Hello&topic=arn&from=MyCompany20"
|
221
|
+
|
222
|
+
@client.sns_publish('Hello', topic: 'arn', from: 'MyCompany20').must_equal(@response_object)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
describe 'sns_subscribe method' do
|
227
|
+
it 'posts to the sns resource and returns the response object' do
|
228
|
+
expect_post "#@sns_base_url/sns/json", "api_key=#@api_key&api_secret=#@api_secret&cmd=subscribe&to=447525856424&topic=arn"
|
229
|
+
|
230
|
+
@client.sns_subscribe('447525856424', topic: 'arn').must_equal(@response_object)
|
203
231
|
end
|
204
232
|
end
|
205
233
|
|
@@ -207,7 +235,9 @@ describe 'Nexmo::Client' do
|
|
207
235
|
it 'posts to the call resource and returns the response object' do
|
208
236
|
expect_post "#@base_url/call/json", "api_key=#@api_key&api_secret=#@api_secret&to=16365553226&answer_url=http://example.com/answer"
|
209
237
|
|
210
|
-
|
238
|
+
Kernel.stub :warn, proc { |message| message.must_match(/initiate_call is deprecated/) } do
|
239
|
+
@client.initiate_call(to: '16365553226', answer_url: 'http://example.com/answer').must_equal(@response_object)
|
240
|
+
end
|
211
241
|
end
|
212
242
|
end
|
213
243
|
|
@@ -215,7 +245,9 @@ describe 'Nexmo::Client' do
|
|
215
245
|
it 'posts to the tts resource and returns the response object' do
|
216
246
|
expect_post "#@api_base_url/tts/json", "api_key=#@api_key&api_secret=#@api_secret&to=16365553226&text=Hello"
|
217
247
|
|
218
|
-
|
248
|
+
Kernel.stub :warn, proc { |message| message.must_match(/initiate_tts_call is deprecated/) } do
|
249
|
+
@client.initiate_tts_call(to: '16365553226', text: 'Hello').must_equal(@response_object)
|
250
|
+
end
|
219
251
|
end
|
220
252
|
end
|
221
253
|
|
@@ -223,7 +255,9 @@ describe 'Nexmo::Client' do
|
|
223
255
|
it 'posts to the tts prompt resource and returns the response object' do
|
224
256
|
expect_post "#@api_base_url/tts-prompt/json", "api_key=#@api_key&api_secret=#@api_secret&to=16365553226&text=Hello&max_digits=4&bye_text=Goodbye"
|
225
257
|
|
226
|
-
|
258
|
+
Kernel.stub :warn, proc { |message| message.must_match(/initiate_tts_prompt_call is deprecated/) } do
|
259
|
+
@client.initiate_tts_prompt_call(to: '16365553226', text: 'Hello', max_digits: 4, bye_text: 'Goodbye').must_equal(@response_object)
|
260
|
+
end
|
227
261
|
end
|
228
262
|
end
|
229
263
|
|
@@ -231,7 +265,7 @@ describe 'Nexmo::Client' do
|
|
231
265
|
it 'posts to the verify json resource and returns the response object' do
|
232
266
|
expect_post "#@api_base_url/verify/json", "api_key=#@api_key&api_secret=#@api_secret&number=447525856424&brand=MyApp"
|
233
267
|
|
234
|
-
@client.start_verification(number: '447525856424', brand: 'MyApp')
|
268
|
+
@client.start_verification(number: '447525856424', brand: 'MyApp').must_equal(@response_object)
|
235
269
|
end
|
236
270
|
end
|
237
271
|
|
@@ -239,7 +273,9 @@ describe 'Nexmo::Client' do
|
|
239
273
|
it 'posts to the verify resource and returns the response object' do
|
240
274
|
expect_post "#@api_base_url/verify/json", "api_key=#@api_key&api_secret=#@api_secret&number=447525856424&brand=MyApp"
|
241
275
|
|
242
|
-
|
276
|
+
Kernel.stub :warn, proc { |message| message.must_match(/send_verification_request is deprecated/) } do
|
277
|
+
@client.send_verification_request(number: '447525856424', brand: 'MyApp').must_equal(@response_object)
|
278
|
+
end
|
243
279
|
end
|
244
280
|
end
|
245
281
|
|
@@ -247,7 +283,7 @@ describe 'Nexmo::Client' do
|
|
247
283
|
it 'posts to the verify check resource and returns the response object' do
|
248
284
|
expect_post "#@api_base_url/verify/check/json", "api_key=#@api_key&api_secret=#@api_secret&request_id=8g88g88eg8g8gg9g90&code=123445"
|
249
285
|
|
250
|
-
@client.check_verification('8g88g88eg8g8gg9g90', code: '123445')
|
286
|
+
@client.check_verification('8g88g88eg8g8gg9g90', code: '123445').must_equal(@response_object)
|
251
287
|
end
|
252
288
|
end
|
253
289
|
|
@@ -255,7 +291,9 @@ describe 'Nexmo::Client' do
|
|
255
291
|
it 'posts to the verify check resource and returns the response object' do
|
256
292
|
expect_post "#@api_base_url/verify/check/json", "api_key=#@api_key&api_secret=#@api_secret&request_id=8g88g88eg8g8gg9g90&code=123445"
|
257
293
|
|
258
|
-
|
294
|
+
Kernel.stub :warn, proc { |message| message.must_match(/check_verification_request is deprecated/) } do
|
295
|
+
@client.check_verification_request(request_id: '8g88g88eg8g8gg9g90', code: '123445').must_equal(@response_object)
|
296
|
+
end
|
259
297
|
end
|
260
298
|
end
|
261
299
|
|
@@ -263,7 +301,7 @@ describe 'Nexmo::Client' do
|
|
263
301
|
it 'fetches the verify search resource with the given request id and returns the response object' do
|
264
302
|
expect_get "#@api_base_url/verify/search/json?api_key=#@api_key&api_secret=#@api_secret&request_id=8g88g88eg8g8gg9g90"
|
265
303
|
|
266
|
-
@client.get_verification('8g88g88eg8g8gg9g90')
|
304
|
+
@client.get_verification('8g88g88eg8g8gg9g90').must_equal(@response_object)
|
267
305
|
end
|
268
306
|
end
|
269
307
|
|
@@ -271,7 +309,9 @@ describe 'Nexmo::Client' do
|
|
271
309
|
it 'fetches the verify search resource with the given request id and returns the response object' do
|
272
310
|
expect_get "#@api_base_url/verify/search/json?api_key=#@api_key&api_secret=#@api_secret&request_id=8g88g88eg8g8gg9g90"
|
273
311
|
|
274
|
-
|
312
|
+
Kernel.stub :warn, proc { |message| message.must_match(/get_verification_request is deprecated/) } do
|
313
|
+
@client.get_verification_request('8g88g88eg8g8gg9g90').must_equal(@response_object)
|
314
|
+
end
|
275
315
|
end
|
276
316
|
end
|
277
317
|
|
@@ -279,7 +319,7 @@ describe 'Nexmo::Client' do
|
|
279
319
|
it 'posts to the verify control resource and returns the response object' do
|
280
320
|
expect_post "#@api_base_url/verify/control/json", "api_key=#@api_key&api_secret=#@api_secret&request_id=8g88g88eg8g8gg9g90&cmd=cancel"
|
281
321
|
|
282
|
-
@client.cancel_verification('8g88g88eg8g8gg9g90')
|
322
|
+
@client.cancel_verification('8g88g88eg8g8gg9g90').must_equal(@response_object)
|
283
323
|
end
|
284
324
|
end
|
285
325
|
|
@@ -287,7 +327,7 @@ describe 'Nexmo::Client' do
|
|
287
327
|
it 'posts to the verify control resource and returns the response object' do
|
288
328
|
expect_post "#@api_base_url/verify/control/json", "api_key=#@api_key&api_secret=#@api_secret&request_id=8g88g88eg8g8gg9g90&cmd=trigger_next_event"
|
289
329
|
|
290
|
-
@client.trigger_next_verification_event('8g88g88eg8g8gg9g90')
|
330
|
+
@client.trigger_next_verification_event('8g88g88eg8g8gg9g90').must_equal(@response_object)
|
291
331
|
end
|
292
332
|
end
|
293
333
|
|
@@ -295,7 +335,9 @@ describe 'Nexmo::Client' do
|
|
295
335
|
it 'posts to the verify control resource and returns the response object' do
|
296
336
|
expect_post "#@api_base_url/verify/control/json", "api_key=#@api_key&api_secret=#@api_secret&request_id=8g88g88eg8g8gg9g90&cmd=cancel"
|
297
337
|
|
298
|
-
|
338
|
+
Kernel.stub :warn, proc { |message| message.must_match(/control_verification_request is deprecated/) } do
|
339
|
+
@client.control_verification_request(request_id: '8g88g88eg8g8gg9g90', cmd: 'cancel').must_equal(@response_object)
|
340
|
+
end
|
299
341
|
end
|
300
342
|
end
|
301
343
|
|
@@ -303,7 +345,7 @@ describe 'Nexmo::Client' do
|
|
303
345
|
it 'fetches the number format resource and returns the response object' do
|
304
346
|
expect_get "#@api_base_url/number/format/json?api_key=#@api_key&api_secret=#@api_secret&number=447525856424"
|
305
347
|
|
306
|
-
@client.get_basic_number_insight(number: '447525856424')
|
348
|
+
@client.get_basic_number_insight(number: '447525856424').must_equal(@response_object)
|
307
349
|
end
|
308
350
|
end
|
309
351
|
|
@@ -311,7 +353,7 @@ describe 'Nexmo::Client' do
|
|
311
353
|
it 'fetches the number lookup resource and returns the response object' do
|
312
354
|
expect_get "#@api_base_url/number/lookup/json?api_key=#@api_key&api_secret=#@api_secret&number=447525856424"
|
313
355
|
|
314
|
-
@client.get_number_insight(number: '447525856424')
|
356
|
+
@client.get_number_insight(number: '447525856424').must_equal(@response_object)
|
315
357
|
end
|
316
358
|
end
|
317
359
|
|
@@ -319,34 +361,174 @@ describe 'Nexmo::Client' do
|
|
319
361
|
it 'posts to the number insight resource and returns the response object' do
|
320
362
|
expect_post "#@base_url/ni/json", "api_key=#@api_key&api_secret=#@api_secret&number=447525856424&callback=https://example.com"
|
321
363
|
|
322
|
-
@client.request_number_insight(number: '447525856424', callback: 'https://example.com')
|
364
|
+
@client.request_number_insight(number: '447525856424', callback: 'https://example.com').must_equal(@response_object)
|
323
365
|
end
|
324
366
|
end
|
325
367
|
|
326
|
-
|
327
|
-
|
368
|
+
describe 'get_applications method' do
|
369
|
+
it 'fetches the applications resource and returns the response object' do
|
370
|
+
expect_get "#@api_base_url/v1/applications?api_key=#@api_key&api_secret=#@api_secret"
|
371
|
+
|
372
|
+
@client.get_applications.must_equal(@response_object)
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
describe 'get_application method' do
|
377
|
+
it 'fetches the application resource with the given id and returns the response object' do
|
378
|
+
expect_get "#@api_base_url/v1/applications/xx-xx-xx-xx?api_key=#@api_key&api_secret=#@api_secret"
|
379
|
+
|
380
|
+
@client.get_application('xx-xx-xx-xx').must_equal(@response_object)
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
describe 'create_application method' do
|
385
|
+
it 'posts to the applications resource and returns the response object' do
|
386
|
+
expect_post "#@api_base_url/v1/applications", "api_key=#@api_key&api_secret=#@api_secret&name=Example+App&type=voice"
|
387
|
+
|
388
|
+
@client.create_application(name: 'Example App', type: 'voice')
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
describe 'update_application method' do
|
393
|
+
it 'puts to the application resource with the given id and returns the response object' do
|
394
|
+
expect_put "#@api_base_url/v1/applications/xx-xx-xx-xx", "api_key=#@api_key&api_secret=#@api_secret&answer_url=https%3A%2F%2Fexample.com%2Fncco"
|
395
|
+
|
396
|
+
@client.update_application('xx-xx-xx-xx', answer_url: 'https://example.com/ncco')
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
describe 'delete_application method' do
|
401
|
+
it 'deletes the application resource with the given id' do
|
402
|
+
expect_delete "#@api_base_url/v1/applications/xx-xx-xx-xx?api_key=#@api_key&api_secret=#@api_secret"
|
403
|
+
|
404
|
+
@client.delete_application('xx-xx-xx-xx')
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
describe 'create_call method' do
|
409
|
+
it 'posts to the calls resource and returns the response object' do
|
410
|
+
params = {
|
411
|
+
to: [{type: 'phone', number: '14843331234'}],
|
412
|
+
from: {type: 'phone', number: '14843335555'},
|
413
|
+
answer_url: ['https://example.com/answer']
|
414
|
+
}
|
415
|
+
|
416
|
+
expect :post, "#@api_base_url/v1/calls", params
|
417
|
+
|
418
|
+
@client.create_call(params).must_equal(@response_object)
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
describe 'get_calls method' do
|
423
|
+
it 'fetches the calls resource and returns the response object' do
|
424
|
+
expect :get, "#@api_base_url/v1/calls?status=completed"
|
425
|
+
|
426
|
+
@client.get_calls(status: 'completed').must_equal(@response_object)
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
describe 'get_call method' do
|
431
|
+
it 'fetches the call resource with the given uuid and returns the response object' do
|
432
|
+
expect :get, "#@api_base_url/v1/calls/xx-xx-xx-xx"
|
433
|
+
|
434
|
+
@client.get_call('xx-xx-xx-xx').must_equal(@response_object)
|
435
|
+
end
|
436
|
+
end
|
437
|
+
|
438
|
+
describe 'update_call method' do
|
439
|
+
it 'puts to the call resource with the given uuid and returns the response object' do
|
440
|
+
expect :put, "#@api_base_url/v1/calls/xx-xx-xx-xx", {action: 'hangup'}
|
441
|
+
|
442
|
+
@client.update_call('xx-xx-xx-xx', action: 'hangup').must_equal(@response_object)
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
describe 'send_audio method' do
|
447
|
+
it 'puts to the call stream resource with the given uuid and returns the response object' do
|
448
|
+
expect :put, "#@api_base_url/v1/calls/xx-xx-xx-xx/stream", {stream_url: 'http://example.com/audio.mp3'}
|
449
|
+
|
450
|
+
@client.send_audio('xx-xx-xx-xx', stream_url: 'http://example.com/audio.mp3').must_equal(@response_object)
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
describe 'stop_audio method' do
|
455
|
+
it 'deletes the call stream resource with the given uuid' do
|
456
|
+
expect :delete, "#@api_base_url/v1/calls/xx-xx-xx-xx/stream"
|
457
|
+
|
458
|
+
@client.stop_audio('xx-xx-xx-xx')
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
describe 'send_speech method' do
|
463
|
+
it 'puts to the call talk resource with the given uuid and returns the response object' do
|
464
|
+
expect :put, "#@api_base_url/v1/calls/xx-xx-xx-xx/talk", {text: 'Hello'}
|
465
|
+
|
466
|
+
@client.send_speech('xx-xx-xx-xx', text: 'Hello').must_equal(@response_object)
|
467
|
+
end
|
468
|
+
end
|
328
469
|
|
329
|
-
|
470
|
+
describe 'stop_speech method' do
|
471
|
+
it 'deletes the call talk resource with the given uuid' do
|
472
|
+
expect :delete, "#@api_base_url/v1/calls/xx-xx-xx-xx/talk"
|
330
473
|
|
331
|
-
|
474
|
+
@client.stop_speech('xx-xx-xx-xx')
|
475
|
+
end
|
476
|
+
end
|
477
|
+
|
478
|
+
describe 'send_dtmf method' do
|
479
|
+
it 'puts to the call dtmf resource with the given uuid and returns the response object' do
|
480
|
+
expect :put, "#@api_base_url/v1/calls/xx-xx-xx-xx/dtmf", {digits: '1234'}
|
481
|
+
|
482
|
+
@client.send_dtmf('xx-xx-xx-xx', digits: '1234').must_equal(@response_object)
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
describe 'check_signature method' do
|
487
|
+
it 'returns true if the signature in the given params is correct' do
|
488
|
+
params = {'a': '1', 'b': '2', 'timestamp': '1461605396', 'sig': '6af838ef94998832dbfc29020b564830'}
|
489
|
+
|
490
|
+
client = Nexmo::Client.new(key: @api_key, secret: @api_secret, signature_secret: 'secret')
|
491
|
+
|
492
|
+
client.check_signature(params).must_equal(true)
|
493
|
+
end
|
332
494
|
end
|
333
495
|
|
334
496
|
it 'raises an authentication error exception if the response code is 401' do
|
335
|
-
stub_request(:
|
497
|
+
stub_request(:get, /#{@base_url}/).to_return(status: 401)
|
336
498
|
|
337
|
-
proc { @client.
|
499
|
+
proc { @client.get_balance }.must_raise(Nexmo::AuthenticationError)
|
338
500
|
end
|
339
501
|
|
340
502
|
it 'raises a client error exception if the response code is 4xx' do
|
341
|
-
stub_request(:
|
503
|
+
stub_request(:get, /#{@base_url}/).to_return(status: 400)
|
342
504
|
|
343
|
-
proc { @client.
|
505
|
+
proc { @client.get_balance }.must_raise(Nexmo::ClientError)
|
344
506
|
end
|
345
507
|
|
346
508
|
it 'raises a server error exception if the response code is 5xx' do
|
347
|
-
stub_request(:
|
509
|
+
stub_request(:get, /#{@base_url}/).to_return(status: 500)
|
510
|
+
|
511
|
+
proc { @client.get_balance }.must_raise(Nexmo::ServerError)
|
512
|
+
end
|
348
513
|
|
349
|
-
|
514
|
+
it 'includes a user-agent header with the library version number and ruby version number' do
|
515
|
+
headers = {'User-Agent' => "ruby-nexmo/#{Nexmo::VERSION}/#{RUBY_VERSION}"}
|
516
|
+
|
517
|
+
stub_request(:get, /#{@base_url}/).with(headers: headers).to_return(@response_body)
|
518
|
+
|
519
|
+
@client.get_balance
|
520
|
+
end
|
521
|
+
|
522
|
+
it 'provides options for application name and version to be included in the user-agent header' do
|
523
|
+
app_name, app_version = 'ExampleApp', 'X.Y.Z'
|
524
|
+
|
525
|
+
headers = {'User-Agent' => "ruby-nexmo/#{Nexmo::VERSION}/#{RUBY_VERSION}/#{app_name}/#{app_version}"}
|
526
|
+
|
527
|
+
stub_request(:get, /#{@base_url}/).with(headers: headers).to_return(@response_body)
|
528
|
+
|
529
|
+
@client = Nexmo::Client.new(key: @api_key, secret: @api_secret, app_name: app_name, app_version: app_version)
|
530
|
+
|
531
|
+
@client.get_balance
|
350
532
|
end
|
351
533
|
|
352
534
|
it 'provides an option for specifying a different hostname to connect to' do
|
@@ -367,6 +549,22 @@ describe 'Nexmo::Client' do
|
|
367
549
|
|
368
550
|
private
|
369
551
|
|
552
|
+
def expect(method_symbol, url, body = nil)
|
553
|
+
headers = {'Authorization' => /\ABearer (.+)\.(.+)\.(.+)\z/}
|
554
|
+
|
555
|
+
@request = stub_request(method_symbol, url)
|
556
|
+
|
557
|
+
if method_symbol == :delete
|
558
|
+
@request.with(headers: headers).to_return(status: 204)
|
559
|
+
elsif body.nil?
|
560
|
+
@request.with(headers: headers).to_return(@response_body)
|
561
|
+
else
|
562
|
+
headers['Content-Type'] = 'application/json'
|
563
|
+
|
564
|
+
@request.with(headers: headers, body: body).to_return(@response_body)
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
370
568
|
def expect_get(url)
|
371
569
|
@request = stub_request(:get, url).to_return(@response_body)
|
372
570
|
end
|
@@ -379,6 +577,18 @@ describe 'Nexmo::Client' do
|
|
379
577
|
@request = stub_request(:post, url).with(body: body, headers: headers).to_return(@response_body)
|
380
578
|
end
|
381
579
|
|
580
|
+
def expect_put(url, data)
|
581
|
+
body = WebMock::Util::QueryMapper.query_to_values(data)
|
582
|
+
|
583
|
+
headers = {'Content-Type' => 'application/x-www-form-urlencoded'}
|
584
|
+
|
585
|
+
@request = stub_request(:put, url).with(body: body, headers: headers).to_return(@response_body)
|
586
|
+
end
|
587
|
+
|
588
|
+
def expect_delete(url)
|
589
|
+
@request = stub_request(:delete, url).to_return(status: 204)
|
590
|
+
end
|
591
|
+
|
382
592
|
after do
|
383
593
|
assert_requested(@request) if defined?(@request)
|
384
594
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nexmo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tim Craft
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-10-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: jwt
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rake
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -62,6 +76,13 @@ files:
|
|
62
76
|
- LICENSE.txt
|
63
77
|
- README.md
|
64
78
|
- lib/nexmo.rb
|
79
|
+
- lib/nexmo/errors/authentication_error.rb
|
80
|
+
- lib/nexmo/errors/client_error.rb
|
81
|
+
- lib/nexmo/errors/error.rb
|
82
|
+
- lib/nexmo/errors/server_error.rb
|
83
|
+
- lib/nexmo/jwt.rb
|
84
|
+
- lib/nexmo/params.rb
|
85
|
+
- lib/nexmo/signature.rb
|
65
86
|
- lib/nexmo/version.rb
|
66
87
|
- nexmo.gemspec
|
67
88
|
- spec/nexmo_spec.rb
|