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 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