diff --git a/examples/call.rb b/examples/call.rb new file mode 100755 index 0000000..2feea25 --- /dev/null +++ b/examples/call.rb @@ -0,0 +1,36 @@ +#!/usr/bin/env ruby + +# frozen_string_literal: true + +$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib/') +require 'messagebird' + +ACCESS_KEY = 'YOUR ACCESS KEY HERE' + +unless defined?(ACCESS_KEY) + puts 'You need to set an ACCESS_KEY constant in this file' + exit 1 +end + +begin + # Create a MessageBird client with the specified ACCESS_KEY. + client = MessageBird::Client.new(ACCESS_KEY) + + # Start a conversation + calls = client.call_list(10, 0) + + calls.items.each do |call| + puts "Call ID: #{call.id}" + end +rescue MessageBird::ErrorException => e + puts + puts 'An error occured while listing the calls:' + puts + + e.errors.each do |error| + puts " code : #{error.code}" + puts " description : #{error.description}" + puts " parameter : #{error.parameter}" + puts + end +end diff --git a/examples/call_leg_recordings.rb b/examples/call_leg_recordings.rb new file mode 100755 index 0000000..288b451 --- /dev/null +++ b/examples/call_leg_recordings.rb @@ -0,0 +1,58 @@ +#!/usr/bin/env ruby + +# frozen_string_literal: true + +$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib/') +require 'messagebird' + +ACCESS_KEY = 'YOUR KEY HERE' +CALL_ID = 'YOUR CALL ID HERE' + +unless defined?(ACCESS_KEY) + puts 'You need to set an ACCESS_KEY constant in this file' + exit 1 +end + +begin + # Create a MessageBird client with the specified ACCESS_KEY. + client = MessageBird::Client.new(ACCESS_KEY) + + # Request the legs (overview of inbound/outbound portions of this call) + puts "Retrieving legs for call #{CALL_ID}" + legs = client.call_leg_list(CALL_ID) + + legs.items.each do |leg| + puts " Retrieving recordings for leg #{leg.id}" + recordings = client.call_leg_recording_list(CALL_ID, leg.id) + + recordings.items.each do |recording| + client.call_leg_recording_view(CALL_ID, leg.id, recording.id) + + puts ' --------------------------------------------------' + puts " recording ID : #{recording.id}" + puts " recording URI : #{recording.uri}" + print ' downloading : ' + client.call_leg_recording_download(recording.uri) do |response| + File.open("#{recording.id}.wav", 'w') do |io| + response.read_body do |chunk| + putc '.' + io.write(chunk) + end + end + end + puts ' DONE!' + puts + end + end +rescue MessageBird::ErrorException => e + puts + puts 'An error occured while listing the calls:' + puts + + e.errors.each do |error| + puts " code : #{error.code}" + puts " description : #{error.description}" + puts " parameter : #{error.parameter}" + puts + end +end diff --git a/examples/call_legs.rb b/examples/call_legs.rb new file mode 100755 index 0000000..b3310be --- /dev/null +++ b/examples/call_legs.rb @@ -0,0 +1,49 @@ +#!/usr/bin/env ruby + +# frozen_string_literal: true + +$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib/') +require 'messagebird' + +ACCESS_KEY = 'YOUR ACCESS KEY HERE' +CALL_ID = 'YOUR CALL ID HERE' + +unless defined?(ACCESS_KEY) + puts 'You need to set an ACCESS_KEY constant in this file' + exit 1 +end + +begin + # Create a MessageBird client with the specified ACCESS_KEY. + client = MessageBird::Client.new(ACCESS_KEY) + + # Start a conversation + legs = client.call_leg_list(CALL_ID, 10, 0) + + legs.items.each do |leg_obj| + puts "leg ID: #{leg_obj.id}" + puts " call ID : #{leg_obj.callId}" + puts " source : #{leg_obj.source}" + puts " destination : #{leg_obj.destination}" + puts " status : #{leg_obj.status}" + puts " direction : #{leg_obj.direction}" + puts " cost : #{leg_obj.cost}" + puts " currency : #{leg_obj.currency}" + puts " duration : #{leg_obj.duration}" + puts " createdAt : #{leg_obj.createdAt}" + puts " updatedAt : #{leg_obj.updatedAt}" + puts " answeredAt : #{leg_obj.answeredAt}" + puts " endedAt : #{leg_obj.endedAt}" + end +rescue MessageBird::ErrorException => e + puts + puts 'An error occured while listing the calls:' + puts + + e.errors.each do |error| + puts " code : #{error.code}" + puts " description : #{error.description}" + puts " parameter : #{error.parameter}" + puts + end +end diff --git a/lib/messagebird.rb b/lib/messagebird.rb index 63f7414..dc5211b 100644 --- a/lib/messagebird.rb +++ b/lib/messagebird.rb @@ -1,5 +1,9 @@ # frozen_string_literal: true +libdir = File.dirname(__FILE__) +$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir) + +require 'messagebird/version' require 'messagebird/balance' require 'messagebird/client' require 'messagebird/contact' @@ -12,5 +16,7 @@ require 'messagebird/verify' require 'messagebird/message' require 'messagebird/voicemessage' -require 'messagebird/call' +require 'messagebird/voice/call' +require 'messagebird/voice/call_leg' +require 'messagebird/voice/call_leg_recording' require 'messagebird/voice/webhook' diff --git a/lib/messagebird/base.rb b/lib/messagebird/base.rb index 0887f42..cbcaa67 100644 --- a/lib/messagebird/base.rb +++ b/lib/messagebird/base.rb @@ -5,14 +5,19 @@ module MessageBird class Base - def initialize(json) - json.each do |k, v| - m = k.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase # convert came case to snake case - - send("#{m}=", v) if respond_to?(:"#{m}=") + # takes each element from the given hash and apply it to ourselves through an assignment method + def map_hash_elements_to_self(hash) + hash.each do |key, value| + method_name = key.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase # convert came case to snake case + method_name += '=' + send(method_name, value) if respond_to?(method_name) end end + def initialize(json) + map_hash_elements_to_self(json) + end + def value_to_time(value) value ? Time.parse(value) : nil end diff --git a/lib/messagebird/call.rb b/lib/messagebird/call.rb deleted file mode 100644 index af6e431..0000000 --- a/lib/messagebird/call.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -require 'messagebird/base' -require 'messagebird/call/webhook' - -module MessageBird - class Call < MessageBird::Base - attr_accessor :id, :status, :source, :destination, :created_at, :updated_at, :endedAt, :call_flow - attr_reader :webhook - - def initialize(json) - params = json.include?('data') ? json['data'].first : json - super(params) - end - - def webhook=(webhook) - @webhook = CallWebhook.new(webhook) - end - end -end diff --git a/lib/messagebird/call/list.rb b/lib/messagebird/call/list.rb deleted file mode 100644 index 7dbf8de..0000000 --- a/lib/messagebird/call/list.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -require 'messagebird/list' - -module MessageBird - class CallList < List - PER_PAGE = 20 - CURRENT_PAGE = 1 - - attr_accessor :per_page, :current_page, :page_count, :total_count - - def data=(value) - # Call List API retruns data object instead of items - # to make it consistence with the rest of the SDK we shall - # propagate it to items= method - self.items = value - end - - def pagination=(value) - value.each do |k, v| - m = k.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase - send("#{m}=", v) if respond_to?(:"#{m}=") - end - end - end -end diff --git a/lib/messagebird/call/webhook.rb b/lib/messagebird/call/webhook.rb deleted file mode 100644 index b944134..0000000 --- a/lib/messagebird/call/webhook.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -module MessageBird - class CallWebhook < MessageBird::Base - attr_accessor :url, :token - end -end diff --git a/lib/messagebird/client.rb b/lib/messagebird/client.rb index fa480ab..c379293 100644 --- a/lib/messagebird/client.rb +++ b/lib/messagebird/client.rb @@ -22,8 +22,11 @@ require 'messagebird/voice/list' require 'messagebird/voice/webhook' require 'messagebird/voicemessage' -require 'messagebird/call' -require 'messagebird/call/list' +require 'messagebird/voice_client' +require 'messagebird/voice/call' +require 'messagebird/voice/call_leg' +require 'messagebird/voice/call_leg_recording' +require 'messagebird/voice/list' module MessageBird class ErrorException < StandardError @@ -251,36 +254,19 @@ def voice_message_create(recipients, body, params = {}) end def voice_webhook_create(url, params = {}) - list = VoiceList.new(VoiceWebhook, voice_request( - :post, - 'webhooks', - params.merge(url: url) - )) - - list.items[0] + Voice::Webhook.new(voice_request(:post, 'webhooks', params.merge(url: url))) end def voice_webhooks_list(per_page = VoiceList::PER_PAGE, page = VoiceList::CURRENT_PAGE) - VoiceList.new(VoiceWebhook, voice_request(:get, "webhooks?perPage=#{per_page}&page=#{page}")) + Voice::List.new(Voice::Webhook, voice_request(:get, "webhooks?perPage=#{per_page}&page=#{page}")) end def voice_webhook_update(id, params = {}) - list = VoiceList.new(VoiceWebhook, voice_request( - :put, - "webhooks/#{id}", - params - )) - - list.items[0] + Voice::Webhook.new(voice_request(:put, "webhooks/#{id}", params)) end def voice_webhook(id) - list = VoiceList.new(VoiceWebhook, voice_request( - :get, - "webhooks/#{id}" - )) - - list.items[0] + Voice::Webhook.new(voice_request(:get, "webhooks/#{id}")) end def voice_webhook_delete(id) @@ -291,23 +277,35 @@ def call_create(source, destination, call_flow = {}, webhook = {}, params = {}) params = params.merge(callFlow: call_flow.to_json) unless call_flow.empty? params = params.merge(webhook: webhook.to_json) unless webhook.empty? - Call.new(request( - :post, - 'calls', - params.merge(source: source, destination: destination) - )) + Voice::Call.new(voice_request(:post, 'calls', params.merge(source: source, destination: destination))) end - def call_list(per_page = CallList::PER_PAGE, page = CallList::CURRENT_PAGE) - CallList.new(Call, request(:get, "calls?perPage=#{per_page}&page=#{page}")) + def call_list(per_page = Voice::List::PER_PAGE, page = Voice::List::CURRENT_PAGE) + Voice::List.new(Voice::Call, voice_request(:get, "calls?perPage=#{per_page}¤tPage=#{page}")) end def call_view(id) - Call.new(request(:get, "calls/#{id}")) + Voice::Call.new(voice_request(:get, "calls/#{id}")) end def call_delete(id) - request(:delete, "calls/#{id}") + voice_request(:delete, "calls/#{id}") + end + + def call_leg_list(call_id, per_page = Voice::List::PER_PAGE, current_page = Voice::List::CURRENT_PAGE) + Voice::List.new(Voice::CallLeg, voice_request(:get, "calls/#{call_id}/legs?perPage=#{per_page}¤tPage=#{current_page}")) + end + + def call_leg_recording_view(call_id, leg_id, recording_id) + Voice::CallLegRecording.new(voice_request(:get, "calls/#{call_id}/legs/#{leg_id}/recordings/#{recording_id}")) + end + + def call_leg_recording_list(call_id, leg_id) + Voice::List.new(Voice::CallLegRecording, voice_request(:get, "calls/#{call_id}/legs/#{leg_id}/recordings")) + end + + def call_leg_recording_download(recording_uri) + @voice_client.request_block(:get, recording_uri, {}, &Proc.new) end def lookup(phone_number, params = {}) diff --git a/lib/messagebird/http_client.rb b/lib/messagebird/http_client.rb index 7699e32..2920f3b 100644 --- a/lib/messagebird/http_client.rb +++ b/lib/messagebird/http_client.rb @@ -21,15 +21,18 @@ def endpoint ENDPOINT end - def request(method, path, params = {}, check_json = true) - uri = URI.join(endpoint, path) - - # Set up the HTTP object. + def build_http_client(uri) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true http.set_debug_output($stdout) unless ENV['DEBUG_MB_HTTP_CLIENT'].nil? + http + end + + def request(method, path, params = {}, check_json = true) + uri = URI.join(endpoint, path) + http = build_http_client(uri) request = build_request(method, uri, params) # Execute the request and fetch the response. @@ -41,6 +44,14 @@ def request(method, path, params = {}, check_json = true) response.body end + def request_block(method, path, params = {}) + uri = URI.join(endpoint, path) + http = build_http_client(uri) + request = build_request(method, uri, params) + + http.request(request, &Proc.new) + end + def prepare_request(request, params = {}) request.set_form_data(params) request diff --git a/lib/messagebird/voice/base.rb b/lib/messagebird/voice/base.rb new file mode 100644 index 0000000..c0dc534 --- /dev/null +++ b/lib/messagebird/voice/base.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module MessageBird + module Voice + class Base < MessageBird::Base + def initialize(json) + params = json.include?('data') ? json['data'].first : json + super(params) + handle_links(json['_links']) + end + + # intentional empty method, objects may not want to deal with _links + def handle_links(json) end + end + end +end diff --git a/lib/messagebird/voice/call.rb b/lib/messagebird/voice/call.rb new file mode 100644 index 0000000..5705851 --- /dev/null +++ b/lib/messagebird/voice/call.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require 'messagebird/voice/base' +require 'messagebird/voice/webhook' + +module MessageBird + module Voice + class Call < MessageBird::Base + attr_accessor :id, :status, :source, :destination, :created_at, :updated_at, :ended_at, :call_flow + attr_reader :webhook + + def initialize(json) + params = json.include?('data') ? json['data'].first : json + super(params) + end + + def webhook=(webhook) + @webhook = Voice::Webhook.new(webhook) + end + end + end +end diff --git a/lib/messagebird/voice/call_leg.rb b/lib/messagebird/voice/call_leg.rb new file mode 100644 index 0000000..6e52d2a --- /dev/null +++ b/lib/messagebird/voice/call_leg.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require 'messagebird/voice/base' + +module MessageBird + module Voice + class CallLeg < MessageBird::Voice::Base + attr_accessor :id, :call_id, :source, :destination, :status, :direction, :cost, :currency, :duration, :created_at, :updated_at, :answered_at, :ended_at + end + end +end diff --git a/lib/messagebird/voice/call_leg_recording.rb b/lib/messagebird/voice/call_leg_recording.rb new file mode 100644 index 0000000..4006a2a --- /dev/null +++ b/lib/messagebird/voice/call_leg_recording.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +require 'messagebird/voice/base' + +module MessageBird + module Voice + class CallLegRecording < MessageBird::Voice::Base + # default attributes from the API + attr_accessor :id, :format, :type, :leg_id, :status, :duration + attr_accessor :created_at, :updated_at + + # further processed attributes for convenience + attr_accessor :_links, :uri + # Grab the URI to the downloadable file and provide it as a direct attribute + def handle_links(links_object) + @uri = links_object['file'] + end + end + end +end diff --git a/lib/messagebird/voice/list.rb b/lib/messagebird/voice/list.rb index dd61bd4..9cda249 100644 --- a/lib/messagebird/voice/list.rb +++ b/lib/messagebird/voice/list.rb @@ -3,20 +3,21 @@ require 'messagebird/list' module MessageBird - class VoiceList < List - attr_accessor :perPage, :currentPage, :pageCount, :totalCount - PER_PAGE = 20 - CURRENT_PAGE = 1 - def data=(value) - # Call List API retruns data object instead of items - # to make it consistence with the rest of the SDK we shall - # propagate it to items= method - self.items = value - end + module Voice + class List < List + attr_accessor :per_page, :current_page, :page_count, :total_count + PER_PAGE = 20 + CURRENT_PAGE = 1 + def data=(value) + # Call List API retruns data object instead of items + # to make it consistence with the rest of the SDK we shall + # propagate it to items= method + self.items = value.nil? ? [] : value + end - def pagination=(value) - value.each do |k, v| - send(:"#{k}=", v) if respond_to?(:"#{k}=") + # map the pagination data to root level properties + def pagination=(value) + map_hash_elements_to_self(value) end end end diff --git a/lib/messagebird/voice/webhook.rb b/lib/messagebird/voice/webhook.rb index 79293c2..5243467 100644 --- a/lib/messagebird/voice/webhook.rb +++ b/lib/messagebird/voice/webhook.rb @@ -1,9 +1,11 @@ # frozen_string_literal: true -require 'messagebird/base' +require 'messagebird/voice/base' module MessageBird - class VoiceWebhook < MessageBird::Base - attr_accessor :id, :url, :token, :createdAt, :updatedAt + module Voice + class Webhook < MessageBird::Voice::Base + attr_accessor :id, :url, :token, :created_at, :updated_at + end end end diff --git a/lib/messagebird/voice_client.rb b/lib/messagebird/voice_client.rb new file mode 100644 index 0000000..bd216fa --- /dev/null +++ b/lib/messagebird/voice_client.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'net/https' +require 'uri' +require 'json' +require 'messagebird/http_client' + +module MessageBird + class VoiceClient < HttpClient + attr_reader :endpoint + + BASE_ENDPOINT = 'https://voice.messagebird.com/' + + def initialize(access_key) + super(access_key) + @endpoint = BASE_ENDPOINT + end + + def prepare_request(request, params = {}) + request['Content-Type'] = 'application/json' + request.body = params.to_json + request + end + end +end diff --git a/spec/call_spec.rb b/spec/call_spec.rb index 98050cf..528798a 100644 --- a/spec/call_spec.rb +++ b/spec/call_spec.rb @@ -1,12 +1,16 @@ # frozen_string_literal: true -require 'messagebird/call' +require 'messagebird/voice/call' describe 'Call' do let(:source) { '31621234567' } let(:destination) { '31621234568' } let(:call_id) { '21025ed1-cc1d-4554-ac05-043fa6c84e00' } + let(:leg_id) { '30c42b27-dce6-4f72-b9c1-01f78ebc1008' } + let(:recording_id) { '3f7b2a0b-3f42-4b6c-a492-22cf35df98f6' } + let(:http_client) { double(MessageBird::HttpClient) } - let(:client) { MessageBird::Client.new('', http_client) } + let(:voice_client) { double(MessageBird::VoiceClient) } + let(:client) { MessageBird::Client.new('', http_client, nil, voice_client) } let(:webhook) { { url: 'https://example.com', token: 'token_to_sign_the_call_events_with' } } let(:call_flow) do { @@ -25,7 +29,7 @@ end it 'create a call' do - expect(http_client) + expect(voice_client) .to receive(:request) .with(:post, 'calls', source: source, destination: destination, callFlow: call_flow.to_json) .and_return('{"data":[{"id":"' + call_id + '","status":"queued","source":"' + source + '","destination":"' + destination + '","createdAt":"2019-10-11T13:02:19Z","updatedAt":"2019-10-11T13:02:19Z","endedAt":null}],"_links":{"self":"/calls/' + call_id + '"},"pagination":{"total_count":0,"pageCount":0,"currentPage":0,"perPage":0}}') @@ -34,7 +38,7 @@ end it 'create a call with webhook' do - expect(http_client) + expect(voice_client) .to receive(:request) .with(:post, 'calls', source: source, destination: destination, callFlow: call_flow.to_json, webhook: webhook.to_json) .and_return('{"data":[{"id":"' + call_id + '","status":"queued","source":"' + source + '","destination":"' + destination + '","createdAt":"2019-10-11T13:02:19Z","updatedAt":"2019-10-11T13:02:19Z","endedAt":null, "webhook":' + webhook.to_json + '}],"_links":{"self":"/calls/' + call_id + '"},"pagination":{"total_count":0,"pageCount":0,"currentPage":0,"perPage":0}}') @@ -44,11 +48,11 @@ end it 'list all calls' do - expect(http_client) + expect(voice_client) .to receive(:request) - .with(:get, 'calls?perPage=20&page=1', {}) - .and_return('{ "data": [ { "id": "f1aa71c0-8f2a-4fe8-b5ef-9a330454ef58", "status": "ended", "source": "' + source + '", "destination": "31612345678", "createdAt": "2017-02-16T10:52:00Z", "updatedAt": "2017-02-16T10:59:04Z", "endedAt": "2017-02-16T10:59:04Z", "_links": { "self": "/calls/f1aa71c0-8f2a-4fe8-b5ef-9a330454ef58" } }, { "id": "ac07a602-dbc1-11e6-bf26-cec0c932ce01", "status": "ended", "source": "' + source + '", "destination": "31612345678", "createdAt": "2017-01-16T07:51:56Z", "updatedAt": "2017-01-16T07:55:56Z", "endedAt": "2017-01-16T07:55:56Z", "webhook": ' + webhook.to_json + ',"_links": { "self": "/calls/ac07a602-dbc1-11e6-bf26-cec0c932ce01" } } ], "_links": { "self": "/calls?page=1" }, "pagination": { "total_count": 2, "pageCount": 1, "currentPage": 1, "perPage": 10 } } -') + .with(:get, 'calls?perPage=20¤tPage=1', {}) + .and_return('{ "data": [ { "id": "f1aa71c0-8f2a-4fe8-b5ef-9a330454ef58", "status": "ended", "source": "' + source + '", "destination": "31612345678", "createdAt": "2017-02-16T10:52:00Z", "updatedAt": "2017-02-16T10:59:04Z", "endedAt": "2017-02-16T10:59:04Z", "_links": { "self": "/calls/f1aa71c0-8f2a-4fe8-b5ef-9a330454ef58" } }, { "id": "ac07a602-dbc1-11e6-bf26-cec0c932ce01", "status": "ended", "source": "' + source + '", "destination": "31612345678", "createdAt": "2017-01-16T07:51:56Z", "updatedAt": "2017-01-16T07:55:56Z", "endedAt": "2017-01-16T07:55:56Z", "webhook": ' + webhook.to_json + ',"_links": { "self": "/calls/ac07a602-dbc1-11e6-bf26-cec0c932ce01" } } ], "_links": { "self": "/calls?page=1" }, "pagination": { "total_count": 2, "pageCount": 1, "currentPage": 1, "perPage": 10 } }') + list = client.call_list expect(list.items).not_to be_nil expect(list.items.first.source).to eq source @@ -56,7 +60,7 @@ end it 'view a call' do - expect(http_client) + expect(voice_client) .to receive(:request) .with(:get, "calls/#{call_id}", {}) .and_return('{ @@ -80,10 +84,145 @@ end it 'delete a call' do - expect(http_client) + expect(voice_client) .to receive(:request) .with(:delete, 'calls/call-id', {}) .and_return('') client.call_delete('call-id') end + + it 'list call legs' do + expect(voice_client) + .to receive(:request) + .with(:get, "calls/#{call_id}/legs?perPage=#{MessageBird::Voice::List::PER_PAGE}¤tPage=#{MessageBird::Voice::List::CURRENT_PAGE}", {}) + .and_return(' + { + "data": [ + { + "id": "' + leg_id + '", + "callId": "' + call_id + '", + "source": "' + source + '", + "destination": "' + destination + '", + "service": 1, + "status": "hangup", + "direction": "outgoing", + "cost": 0.0021670, + "currency": "EUR", + "duration": 10, + "createdAt": "2019-12-03T14:50:47Z", + "updatedAt": "2019-12-03T14:51:00Z", + "answeredAt": "2019-12-03T14:50:50Z", + "endedAt": "2019-12-03T14:51:00Z", + "_links": { + "self": "/calls/' + call_id + '/legs/' + leg_id + '" + } + } + ], + "_links": { + "self": "/calls/' + call_id + '/legs?page=1" + }, + "pagination": { + "totalCount": 1, + "pageCount": 1, + "currentPage": 1, + "perPage": 10 + } + }') + + legs = client.call_leg_list(call_id) + expect(legs[0].id).to eq leg_id + end + + it 'list call leg recordings' do + expect(voice_client) + .to receive(:request) + .with(:get, "calls/#{call_id}/legs/#{leg_id}/recordings", {}) + .and_return(' + { + "data": [ + { + "id": "' + recording_id + '", + "format": "wav", + "legId": "' + leg_id + '", + "status": "done", + "duration": 5, + "type": "ivr", + "createdAt": "2019-12-03T14:50:53Z", + "updatedAt": "2019-12-03T14:51:00Z", + "deletedAt": null, + "_links": { + "file": "/calls/' + call_id + '/legs/' + leg_id + '/recordings/' + recording_id + '.wav", + "self": "/calls/' + call_id + '/legs/' + leg_id + '/recordings/' + recording_id + '" + } + } + ], + "_links": { + "self": "/calls/' + call_id + '/legs/' + leg_id + '/recordings?page=1" + }, + "pagination": { + "totalCount": 1, + "pageCount": 1, + "currentPage": 1, + "perPage": 10 + } + }') + + records = client.call_leg_recording_list(call_id, leg_id) + expect(records[0].uri).to eq '/calls/' + call_id + '/legs/' + leg_id + '/recordings/' + recording_id + '.wav' + end + + it 'view a call recording' do + expect(voice_client) + .to receive(:request) + .with(:get, "calls/#{call_id}/legs/#{leg_id}/recordings/#{recording_id}", {}) + .and_return(' + { + "data": [ + { + "id": "' + recording_id + '", + "format": "wav", + "legId": "' + leg_id + '", + "status": "done", + "duration": 12, + "type": "call", + "createdAt": "2019-12-03T14:50:47Z", + "updatedAt": "2019-12-03T14:51:01Z", + "deletedAt": null + } + ], + "_links": { + "file": "/calls/' + call_id + '/legs/' + leg_id + '/recordings/' + recording_id + '.wav", + "self": "/calls/' + call_id + '/legs/' + leg_id + '/recordings/' + recording_id + '" + }, + "pagination": { + "totalCount": 0, + "pageCount": 0, + "currentPage": 0, + "perPage": 0 + } + }') + + recording = client.call_leg_recording_view(call_id, leg_id, recording_id) + expect(recording.uri).to eq '/calls/' + call_id + '/legs/' + leg_id + '/recordings/' + recording_id + '.wav' + end + + it 'download a call recording' do + mock_response = double(Net::HTTPResponse) + recording_uri = '/calls/' + call_id + '/legs/' + leg_id + '/recordings/' + recording_id + '.wav' + + expect(voice_client) + .to receive(:request_block) + .with(:get, recording_uri, {}) + .and_yield(mock_response) + + expect(mock_response) + .to receive(:read_body) + .once + .and_return('bytes go here') + + client.call_leg_recording_download(recording_uri) do |response| + expect(response.read_body) + .to eq 'bytes go here' + end + end end