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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 49b51d133374ce76a15e6a597f0f9946651185b4
4
- data.tar.gz: 94d0243ccf112419f3ebf62cb9c532d775de26ff
3
+ metadata.gz: 39100089701618826f373695cb54cd0d3c2dde95
4
+ data.tar.gz: fec02db08356b21dd202c39b88fd06a92cb52516
5
5
  SHA512:
6
- metadata.gz: e3a0b6310e548f87fa93ab582cfe25ed4afdec5264ffeb3cee6988bbe14883112dcd8a31682dd45ee6470d17e9e7ca1ab83fe96b4b30a244e3a962ba3b9ac42c
7
- data.tar.gz: a07ad566361244c9062a7e4b35fb825b468197f6a5b62c870297f252a584a7c5155cf88675474dfee2f58a6e6633c8ccf518360d5826dc581d65e2f7adc95264
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
- * [Examples](#examples)
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
- Specify your credentials using the `NEXMO_API_KEY` and `NEXMO_API_SECRET`
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
- Alternatively you can specify your credentials directly using the `key`
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
- Examples
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
- ### Sending a message
52
+ ```ruby
53
+ client = Nexmo::Client.new(application_id: application_id, private_key: private_key)
54
+ ```
55
55
 
56
- To use [Nexmo's SMS API][doc_sms] to send an SMS message, call the Nexmo::Client#send_message
57
- method with a hash containing the API parameters. For example:
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
- response = response['messages'].first
61
+ ## SMS API
63
62
 
64
- if response['status'] == '0'
65
- puts "Sent message #{response['message-id']}"
63
+ ### Send a text message
64
+
65
+ ```ruby
66
+ response = client.send_message(from: 'Ruby', to: 'YOUR NUMBER', text: 'Hello world')
66
67
 
67
- puts "Remaining balance is #{response['remaining-balance']}"
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
- ### Fetching a message
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
- You can retrieve a message log from the API using the ID of the message:
77
+
78
+ ## Voice API
79
+
80
+ ### Make a call
76
81
 
77
82
  ```ruby
78
- message = client.get_message('02000000DA7C52E7')
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
- puts "The body of the message was: #{message['body']}"
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
- ### Starting a verification
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
- Nexmo's [Verify API][doc_verify] makes it easy to prove that a user has provided their
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
- You can start the verification process by calling the start_verification method:
108
+ ### Update a call
89
109
 
90
110
  ```ruby
91
- response = client.start_verification(number: '441632960960', brand: 'MyApp')
111
+ response = client.update_call(uuid, action: 'hangup')
112
+ ```
92
113
 
93
- if response['status'] == '0'
94
- puts "Started verification request_id=#{response['request_id']}"
95
- else
96
- puts "Error: #{response['error_text']}"
97
- end
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
- The response contains a verification request id which you will need to
101
- store temporarily (in the session, database, url etc).
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
- ### Controlling a verification
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
- Call the cancel_verification method with the verification request id
106
- to cancel an in-progress verification:
134
+ ### Send a synthesized speech message to a call
107
135
 
108
136
  ```ruby
109
- client.cancel_verification('00e6c3377e5348cdaf567e1417c707a5')
137
+ response = client.send_speech(uuid, text: 'Hello')
110
138
  ```
111
139
 
112
- Call the trigger_next_verification_event method with the verification
113
- request id to trigger the next attempt to send the confirmation code:
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.trigger_next_verification_event('00e6c3377e5348cdaf567e1417c707a5')
145
+ response = client.stop_speech(uuid)
117
146
  ```
118
147
 
119
- The verification request id comes from the call to the start_verification method.
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
- ### Checking a verification
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
- Call the check_verification method with the verification request id and the
124
- PIN code to complete the verification process:
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
@@ -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
- private
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
- USER_AGENT = "ruby-nexmo/#{VERSION}/#{RUBY_VERSION}"
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 = query_string(params.merge(api_key: @key, api_secret: @secret))
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
- parse(request(uri, message), host)
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
- parse(request(uri, message), host)
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
- def parse(http_response, host)
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
@@ -0,0 +1,4 @@
1
+ module Nexmo
2
+ class AuthenticationError < ClientError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Nexmo
2
+ class ClientError < Error
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Nexmo
2
+ class Error < StandardError
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Nexmo
2
+ class ServerError < Error
3
+ end
4
+ end
@@ -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
@@ -0,0 +1,13 @@
1
+ require 'cgi'
2
+
3
+ module Nexmo
4
+ module Params
5
+ def self.encode(params)
6
+ params.flat_map { |k, vs| Array(vs).map { |v| "#{escape(k)}=#{escape(v)}" } }.join('&')
7
+ end
8
+
9
+ def self.escape(component)
10
+ CGI.escape(component.to_s)
11
+ end
12
+ end
13
+ end
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Nexmo
2
- VERSION = '4.2.0'
2
+ VERSION = '4.3.0'
3
3
  end
@@ -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')
@@ -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
- @example_message_hash = {from: 'ruby', to: 'number', text: 'Hey!'}
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(@example_message_hash).must_equal(@response_object)
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
- @client.initiate_call(to: '16365553226', answer_url: 'http://example.com/answer')
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
- @client.initiate_tts_call(to: '16365553226', text: 'Hello')
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
- @client.initiate_tts_prompt_call(to: '16365553226', text: 'Hello', max_digits: 4, bye_text: 'Goodbye')
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
- @client.send_verification_request(number: '447525856424', brand: 'MyApp')
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
- @client.check_verification_request(request_id: '8g88g88eg8g8gg9g90', code: '123445')
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
- @client.get_verification_request('8g88g88eg8g8gg9g90')
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
- @client.control_verification_request(request_id: '8g88g88eg8g8gg9g90', cmd: 'cancel')
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
- it 'includes a user-agent header with the library version number and ruby version number' do
327
- headers = {'User-Agent' => "ruby-nexmo/#{Nexmo::VERSION}/#{RUBY_VERSION}"}
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
- stub_request(:post, "#@base_url/sms/json").with(headers: headers).to_return(@response_body)
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
- @client.send_message(@example_message_hash)
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(:post, "#@base_url/sms/json").to_return(status: 401)
497
+ stub_request(:get, /#{@base_url}/).to_return(status: 401)
336
498
 
337
- proc { @client.send_message(@example_message_hash) }.must_raise(Nexmo::AuthenticationError)
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(:post, "#@base_url/sms/json").to_return(status: 400)
503
+ stub_request(:get, /#{@base_url}/).to_return(status: 400)
342
504
 
343
- proc { @client.send_message(@example_message_hash) }.must_raise(Nexmo::ClientError)
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(:post, "#@base_url/sms/json").to_return(status: 500)
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
- proc { @client.send_message(@example_message_hash) }.must_raise(Nexmo::ServerError)
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.2.0
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-06-30 00:00:00.000000000 Z
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