nexmo 4.2.0 → 4.3.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 +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
|