voiceml 0.7.1.1
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 +7 -0
- data/LICENSE +21 -0
- data/README.md +265 -0
- data/lib/voiceml/client.rb +83 -0
- data/lib/voiceml/errors.rb +75 -0
- data/lib/voiceml/models/applications.rb +46 -0
- data/lib/voiceml/models/calls.rb +48 -0
- data/lib/voiceml/models/common.rb +64 -0
- data/lib/voiceml/models/conferences.rb +85 -0
- data/lib/voiceml/models/diagnostics.rb +56 -0
- data/lib/voiceml/models/incoming_phone_numbers.rb +59 -0
- data/lib/voiceml/models/messages.rb +56 -0
- data/lib/voiceml/models/payments.rb +96 -0
- data/lib/voiceml/models/queues.rb +82 -0
- data/lib/voiceml/models/recordings.rb +59 -0
- data/lib/voiceml/models/siprec.rb +44 -0
- data/lib/voiceml/models/streams.rb +44 -0
- data/lib/voiceml/models/transcriptions.rb +44 -0
- data/lib/voiceml/resources/applications.rb +62 -0
- data/lib/voiceml/resources/base.rb +38 -0
- data/lib/voiceml/resources/calls.rb +414 -0
- data/lib/voiceml/resources/conferences.rb +178 -0
- data/lib/voiceml/resources/diagnostics.rb +64 -0
- data/lib/voiceml/resources/incoming_phone_numbers.rb +162 -0
- data/lib/voiceml/resources/messages.rb +101 -0
- data/lib/voiceml/resources/notifications.rb +32 -0
- data/lib/voiceml/resources/queues.rb +120 -0
- data/lib/voiceml/resources/recordings.rb +89 -0
- data/lib/voiceml/transport.rb +296 -0
- data/lib/voiceml/version.rb +5 -0
- data/lib/voiceml.rb +27 -0
- metadata +118 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
require_relative '../models/incoming_phone_numbers'
|
|
5
|
+
|
|
6
|
+
module VoiceML
|
|
7
|
+
# Operations on `/IncomingPhoneNumbers` — tenant-scoped DID lookup and routing.
|
|
8
|
+
#
|
|
9
|
+
# Twilio-compatible: `sid` is the canonical `PN`-prefixed identifier, `phone_number` is the
|
|
10
|
+
# E.164 form. The standard lookup-by-number pattern (`list(phone_number: '+1...')`
|
|
11
|
+
# returning a 0-or-1-row envelope, then `get(sid)`) is supported.
|
|
12
|
+
class IncomingPhoneNumbersResource < BaseResource
|
|
13
|
+
LIST_FIELDS = {
|
|
14
|
+
'PhoneNumber' => :phone_number,
|
|
15
|
+
'Page' => :page,
|
|
16
|
+
'PageSize' => :page_size,
|
|
17
|
+
'PageToken' => :page_token
|
|
18
|
+
}.freeze
|
|
19
|
+
|
|
20
|
+
CREATE_FIELDS = {
|
|
21
|
+
'PhoneNumber' => :phone_number,
|
|
22
|
+
'VoiceUrl' => :voice_url,
|
|
23
|
+
'VoiceMethod' => :voice_method,
|
|
24
|
+
'VoiceFallbackUrl' => :voice_fallback_url,
|
|
25
|
+
'VoiceFallbackMethod' => :voice_fallback_method,
|
|
26
|
+
'FriendlyName' => :friendly_name
|
|
27
|
+
}.freeze
|
|
28
|
+
|
|
29
|
+
UPDATE_FIELDS = {
|
|
30
|
+
'VoiceUrl' => :voice_url,
|
|
31
|
+
'VoiceMethod' => :voice_method,
|
|
32
|
+
'VoiceFallbackUrl' => :voice_fallback_url,
|
|
33
|
+
'VoiceFallbackMethod' => :voice_fallback_method,
|
|
34
|
+
'FriendlyName' => :friendly_name
|
|
35
|
+
}.freeze
|
|
36
|
+
|
|
37
|
+
LIST_TYPED_FIELDS = {
|
|
38
|
+
'PhoneNumber' => :phone_number,
|
|
39
|
+
'FriendlyName' => :friendly_name,
|
|
40
|
+
'Beta' => :beta,
|
|
41
|
+
'Origin' => :origin,
|
|
42
|
+
'Page' => :page,
|
|
43
|
+
'PageSize' => :page_size,
|
|
44
|
+
'PageToken' => :page_token
|
|
45
|
+
}.freeze
|
|
46
|
+
|
|
47
|
+
# List DIDs assigned to the authenticated tenant.
|
|
48
|
+
#
|
|
49
|
+
# @param phone_number [String, nil] exact-match E.164 filter. Returns a 0-or-1-row
|
|
50
|
+
# envelope when set — the standard twilio-ruby lookup pattern.
|
|
51
|
+
# @param page [Integer, nil] 0-indexed page number.
|
|
52
|
+
# @param page_size [Integer, nil] page size (server-bounded).
|
|
53
|
+
# @return [VoiceML::IncomingPhoneNumberList]
|
|
54
|
+
def list(phone_number: nil, page: nil, page_size: nil)
|
|
55
|
+
kwargs = { phone_number: phone_number, page: page, page_size: page_size }
|
|
56
|
+
IncomingPhoneNumberList.from_hash(
|
|
57
|
+
@transport.request(:get, path('IncomingPhoneNumbers'),
|
|
58
|
+
params: form_params(LIST_FIELDS, kwargs))
|
|
59
|
+
)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Assign a DID to the authenticated tenant. Idempotent re-POSTing the same
|
|
63
|
+
# `phone_number:` rebinds the voice routing (matches Twilio update semantics).
|
|
64
|
+
#
|
|
65
|
+
# @param phone_number [String] required. E.164 — leading `+`, 7-15 digits.
|
|
66
|
+
# @param voice_url [String, nil] inbound-voice handler URL.
|
|
67
|
+
# @param voice_method [String, nil] HTTP method for `voice_url` (`GET`/`POST`).
|
|
68
|
+
# @param voice_fallback_url [String, nil] fallback handler URL.
|
|
69
|
+
# @param voice_fallback_method [String, nil] HTTP method for `voice_fallback_url`.
|
|
70
|
+
# @param friendly_name [String, nil] display label (server may ignore in v0.5.x).
|
|
71
|
+
# @return [VoiceML::IncomingPhoneNumber]
|
|
72
|
+
def create(phone_number:, voice_url: nil, voice_method: nil,
|
|
73
|
+
voice_fallback_url: nil, voice_fallback_method: nil,
|
|
74
|
+
friendly_name: nil)
|
|
75
|
+
kwargs = {
|
|
76
|
+
phone_number: phone_number,
|
|
77
|
+
voice_url: voice_url, voice_method: voice_method,
|
|
78
|
+
voice_fallback_url: voice_fallback_url,
|
|
79
|
+
voice_fallback_method: voice_fallback_method,
|
|
80
|
+
friendly_name: friendly_name
|
|
81
|
+
}
|
|
82
|
+
IncomingPhoneNumber.from_hash(
|
|
83
|
+
@transport.request(:post, path('IncomingPhoneNumbers'),
|
|
84
|
+
form: form_params(CREATE_FIELDS, kwargs))
|
|
85
|
+
)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Fetch a single DID by its `PN`-prefixed sid.
|
|
89
|
+
# @return [VoiceML::IncomingPhoneNumber]
|
|
90
|
+
def get(sid)
|
|
91
|
+
IncomingPhoneNumber.from_hash(
|
|
92
|
+
@transport.request(:get, path('IncomingPhoneNumbers', sid))
|
|
93
|
+
)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Update voice routing on an assigned DID. Only set fields are touched.
|
|
97
|
+
#
|
|
98
|
+
# @param sid [String] the `PN`-prefixed identifier.
|
|
99
|
+
# @param opts [Hash] any of `voice_url:`, `voice_method:`, `voice_fallback_url:`,
|
|
100
|
+
# `voice_fallback_method:`, `friendly_name:`.
|
|
101
|
+
# @return [VoiceML::IncomingPhoneNumber]
|
|
102
|
+
def update(sid, **opts)
|
|
103
|
+
IncomingPhoneNumber.from_hash(
|
|
104
|
+
@transport.request(:post, path('IncomingPhoneNumbers', sid),
|
|
105
|
+
form: form_params(UPDATE_FIELDS, opts))
|
|
106
|
+
)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Release a DID from the authenticated tenant. Idempotent — 204 even if already gone.
|
|
110
|
+
# @return [nil]
|
|
111
|
+
def delete(sid)
|
|
112
|
+
@transport.request(:delete, path('IncomingPhoneNumbers', sid))
|
|
113
|
+
nil
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# @return [VoiceML::IncomingPhoneNumberList]
|
|
117
|
+
def list_local(**kwargs)
|
|
118
|
+
list_typed('Local', kwargs)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# @return [VoiceML::IncomingPhoneNumber]
|
|
122
|
+
def create_local(**kwargs)
|
|
123
|
+
create_typed('Local', kwargs)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# @return [VoiceML::IncomingPhoneNumberList]
|
|
127
|
+
def list_mobile(**kwargs)
|
|
128
|
+
list_typed('Mobile', kwargs)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# @return [VoiceML::IncomingPhoneNumber]
|
|
132
|
+
def create_mobile(**kwargs)
|
|
133
|
+
create_typed('Mobile', kwargs)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# @return [VoiceML::IncomingPhoneNumberList]
|
|
137
|
+
def list_toll_free(**kwargs)
|
|
138
|
+
list_typed('TollFree', kwargs)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# @return [VoiceML::IncomingPhoneNumber]
|
|
142
|
+
def create_toll_free(**kwargs)
|
|
143
|
+
create_typed('TollFree', kwargs)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
private
|
|
147
|
+
|
|
148
|
+
def list_typed(kind, kwargs)
|
|
149
|
+
IncomingPhoneNumberList.from_hash(
|
|
150
|
+
@transport.request(:get, path('IncomingPhoneNumbers', kind),
|
|
151
|
+
params: form_params(LIST_TYPED_FIELDS, kwargs))
|
|
152
|
+
)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def create_typed(kind, kwargs)
|
|
156
|
+
IncomingPhoneNumber.from_hash(
|
|
157
|
+
@transport.request(:post, path('IncomingPhoneNumbers', kind),
|
|
158
|
+
form: form_params(CREATE_FIELDS, kwargs))
|
|
159
|
+
)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
require_relative '../models/messages'
|
|
5
|
+
|
|
6
|
+
module VoiceML
|
|
7
|
+
# Operations on `/Messages` — VoiceTel's Twilio-compatible SMS surface,
|
|
8
|
+
# backed by the SDK 2.2 gateway. Outbound-only today (no MMS, no inbound
|
|
9
|
+
# webhook delivery).
|
|
10
|
+
#
|
|
11
|
+
# All methods accept idiomatic snake_case keyword arguments — they're
|
|
12
|
+
# translated to the PascalCase wire names internally.
|
|
13
|
+
class MessagesResource < BaseResource
|
|
14
|
+
CREATE_FIELDS = {
|
|
15
|
+
'To' => :to,
|
|
16
|
+
'Body' => :body,
|
|
17
|
+
'From' => :from,
|
|
18
|
+
'MessagingServiceSid' => :messaging_service_sid,
|
|
19
|
+
'StatusCallback' => :status_callback
|
|
20
|
+
}.freeze
|
|
21
|
+
|
|
22
|
+
LIST_FIELDS = {
|
|
23
|
+
'To' => :to,
|
|
24
|
+
'From' => :from,
|
|
25
|
+
'DateSent' => :date_sent,
|
|
26
|
+
'DateSent<' => :date_sent_lt,
|
|
27
|
+
'DateSent>' => :date_sent_gt,
|
|
28
|
+
'Page' => :page,
|
|
29
|
+
'PageSize' => :page_size,
|
|
30
|
+
'PageToken' => :page_token
|
|
31
|
+
}.freeze
|
|
32
|
+
|
|
33
|
+
UPDATE_FIELDS = {
|
|
34
|
+
'Body' => :body,
|
|
35
|
+
'Status' => :status
|
|
36
|
+
}.freeze
|
|
37
|
+
|
|
38
|
+
# Dispatch an outbound SMS. `to:` and `body:` are required; `from:` falls
|
|
39
|
+
# back to the tenant's configured default sender when omitted.
|
|
40
|
+
#
|
|
41
|
+
# @return [VoiceML::Message]
|
|
42
|
+
def create(**kwargs)
|
|
43
|
+
data = @transport.request(:post, path('Messages'), form: form_params(CREATE_FIELDS, kwargs))
|
|
44
|
+
Message.from_hash(data)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Retrieve a previously-sent Message by sid.
|
|
48
|
+
#
|
|
49
|
+
# @return [VoiceML::Message]
|
|
50
|
+
def fetch(sid)
|
|
51
|
+
Message.from_hash(@transport.request(:get, path('Messages', sid)))
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Return a single page of Messages, narrowed by the Twilio-documented filter
|
|
55
|
+
# set (To, From, DateSent eq/gt/lt) plus pagination.
|
|
56
|
+
#
|
|
57
|
+
# @return [VoiceML::MessageList]
|
|
58
|
+
def list(**kwargs)
|
|
59
|
+
MessageList.from_hash(
|
|
60
|
+
@transport.request(:get, path('Messages'), params: form_params(LIST_FIELDS, kwargs))
|
|
61
|
+
)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Walk every page of /Messages and yield each Message. Returns an Enumerator
|
|
65
|
+
# when called without a block.
|
|
66
|
+
#
|
|
67
|
+
# @yield [VoiceML::Message]
|
|
68
|
+
# @return [Enumerator<VoiceML::Message>] when no block given
|
|
69
|
+
def each(**kwargs, &block)
|
|
70
|
+
return enum_for(:each, **kwargs) unless block
|
|
71
|
+
|
|
72
|
+
page_num = kwargs.delete(:page) || 0
|
|
73
|
+
loop do
|
|
74
|
+
chunk = list(**kwargs, page: page_num)
|
|
75
|
+
chunk.messages.each(&block)
|
|
76
|
+
break if chunk.next_page_uri.nil? || chunk.next_page_uri.empty? || chunk.messages.empty?
|
|
77
|
+
|
|
78
|
+
page_num += 1
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Mutate an existing Message — redact `body:` to empty string, or attempt
|
|
83
|
+
# `status: "canceled"`. Cancellation returns 21610 today because the gateway
|
|
84
|
+
# is fire-and-forget.
|
|
85
|
+
#
|
|
86
|
+
# @return [VoiceML::Message]
|
|
87
|
+
def update(sid, **kwargs)
|
|
88
|
+
data = @transport.request(:post, path('Messages', sid),
|
|
89
|
+
form: form_params(UPDATE_FIELDS, kwargs))
|
|
90
|
+
Message.from_hash(data)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Remove a Message resource from the account's store.
|
|
94
|
+
#
|
|
95
|
+
# @return [nil]
|
|
96
|
+
def delete(sid)
|
|
97
|
+
@transport.request(:delete, path('Messages', sid))
|
|
98
|
+
nil
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
require_relative '../models/diagnostics'
|
|
5
|
+
|
|
6
|
+
module VoiceML
|
|
7
|
+
# Account-scoped `/Notifications` compat stubs (always empty list; fetch returns 404).
|
|
8
|
+
class NotificationsResource < BaseResource
|
|
9
|
+
LIST_FIELDS = {
|
|
10
|
+
'Page' => :page,
|
|
11
|
+
'PageSize' => :page_size,
|
|
12
|
+
'PageToken' => :page_token,
|
|
13
|
+
'Log' => :log,
|
|
14
|
+
'MessageDate' => :message_date,
|
|
15
|
+
'MessageDate<' => :message_date_lt,
|
|
16
|
+
'MessageDate>' => :message_date_gt
|
|
17
|
+
}.freeze
|
|
18
|
+
|
|
19
|
+
# @return [VoiceML::NotificationsList]
|
|
20
|
+
def list(**kwargs)
|
|
21
|
+
NotificationsList.from_hash(
|
|
22
|
+
@transport.request(:get, path('Notifications'),
|
|
23
|
+
params: form_params(LIST_FIELDS, kwargs))
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# @return [Hash]
|
|
28
|
+
def get(notification_sid)
|
|
29
|
+
@transport.request(:get, path('Notifications', notification_sid))
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
require_relative '../models/queues'
|
|
5
|
+
|
|
6
|
+
module VoiceML
|
|
7
|
+
# Operations on `/Queues` and their members.
|
|
8
|
+
class QueuesResource < BaseResource
|
|
9
|
+
QUEUE_FIELDS = {
|
|
10
|
+
'FriendlyName' => :friendly_name,
|
|
11
|
+
'MaxSize' => :max_size
|
|
12
|
+
}.freeze
|
|
13
|
+
|
|
14
|
+
DEQUEUE_FIELDS = {
|
|
15
|
+
'Url' => :url,
|
|
16
|
+
'Method' => :method
|
|
17
|
+
}.freeze
|
|
18
|
+
|
|
19
|
+
LIST_PAGE_FIELDS = {
|
|
20
|
+
'Page' => :page,
|
|
21
|
+
'PageSize' => :page_size,
|
|
22
|
+
'PageToken' => :page_token
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
25
|
+
LIST_MEMBERS_FIELDS = {
|
|
26
|
+
'Page' => :page,
|
|
27
|
+
'PageSize' => :page_size,
|
|
28
|
+
'PageToken' => :page_token
|
|
29
|
+
}.freeze
|
|
30
|
+
|
|
31
|
+
# @return [VoiceML::Queue]
|
|
32
|
+
def create(**kwargs)
|
|
33
|
+
Queue.from_hash(
|
|
34
|
+
@transport.request(:post, path('Queues'), form: form_params(QUEUE_FIELDS, kwargs))
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @return [VoiceML::QueueList]
|
|
39
|
+
def list(**kwargs)
|
|
40
|
+
QueueList.from_hash(
|
|
41
|
+
@transport.request(:get, path('Queues'), params: form_params(LIST_PAGE_FIELDS, kwargs))
|
|
42
|
+
)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @yield [VoiceML::Queue]
|
|
46
|
+
# @return [Enumerator<VoiceML::Queue>] when no block given
|
|
47
|
+
def each(**kwargs, &block)
|
|
48
|
+
return enum_for(:each, **kwargs) unless block
|
|
49
|
+
|
|
50
|
+
page_num = kwargs.delete(:page) || 0
|
|
51
|
+
loop do
|
|
52
|
+
chunk = list(**kwargs, page: page_num)
|
|
53
|
+
chunk.queues.each(&block)
|
|
54
|
+
break if chunk.next_page_uri.nil? || chunk.next_page_uri.empty? || chunk.queues.empty?
|
|
55
|
+
page_num += 1
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @return [VoiceML::Queue]
|
|
60
|
+
def get(queue_sid)
|
|
61
|
+
Queue.from_hash(@transport.request(:get, path('Queues', queue_sid)))
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# @return [VoiceML::Queue]
|
|
65
|
+
def update(queue_sid, **kwargs)
|
|
66
|
+
Queue.from_hash(
|
|
67
|
+
@transport.request(:post, path('Queues', queue_sid),
|
|
68
|
+
form: form_params(QUEUE_FIELDS, kwargs))
|
|
69
|
+
)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# @return [nil]
|
|
73
|
+
def delete(queue_sid)
|
|
74
|
+
@transport.request(:delete, path('Queues', queue_sid))
|
|
75
|
+
nil
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# --- Members ---
|
|
79
|
+
|
|
80
|
+
# @return [VoiceML::QueueMemberList]
|
|
81
|
+
def list_members(queue_sid, **kwargs)
|
|
82
|
+
QueueMemberList.from_hash(
|
|
83
|
+
@transport.request(:get, path('Queues', queue_sid, 'Members'),
|
|
84
|
+
params: form_params(LIST_MEMBERS_FIELDS, kwargs))
|
|
85
|
+
)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# @return [VoiceML::QueueMember]
|
|
89
|
+
def peek_front(queue_sid)
|
|
90
|
+
QueueMember.from_hash(
|
|
91
|
+
@transport.request(:get, path('Queues', queue_sid, 'Members', 'Front'))
|
|
92
|
+
)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Dequeue the front-of-queue member to a TwiML URL.
|
|
96
|
+
# @return [VoiceML::QueueMember]
|
|
97
|
+
def dequeue_front(queue_sid, **kwargs)
|
|
98
|
+
QueueMember.from_hash(
|
|
99
|
+
@transport.request(:post, path('Queues', queue_sid, 'Members', 'Front'),
|
|
100
|
+
form: form_params(DEQUEUE_FIELDS, kwargs))
|
|
101
|
+
)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# @return [VoiceML::QueueMember]
|
|
105
|
+
def get_member(queue_sid, call_sid)
|
|
106
|
+
QueueMember.from_hash(
|
|
107
|
+
@transport.request(:get, path('Queues', queue_sid, 'Members', call_sid))
|
|
108
|
+
)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Dequeue a specific member by CallSid.
|
|
112
|
+
# @return [VoiceML::QueueMember]
|
|
113
|
+
def dequeue_member(queue_sid, call_sid, **kwargs)
|
|
114
|
+
QueueMember.from_hash(
|
|
115
|
+
@transport.request(:post, path('Queues', queue_sid, 'Members', call_sid),
|
|
116
|
+
form: form_params(DEQUEUE_FIELDS, kwargs))
|
|
117
|
+
)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base'
|
|
4
|
+
require_relative '../models/recordings'
|
|
5
|
+
|
|
6
|
+
module VoiceML
|
|
7
|
+
# Account-scoped `/Recordings` operations.
|
|
8
|
+
#
|
|
9
|
+
# Per-call recording start/stop/list lives on {VoiceML::CallsResource} — this resource
|
|
10
|
+
# handles the account-wide list, single-recording fetch (both metadata and audio),
|
|
11
|
+
# and delete.
|
|
12
|
+
class RecordingsResource < BaseResource
|
|
13
|
+
LIST_FIELDS = {
|
|
14
|
+
'DateCreated' => :date_created,
|
|
15
|
+
'DateCreated<' => :date_created_lt,
|
|
16
|
+
'DateCreated>' => :date_created_gt,
|
|
17
|
+
'CallSid' => :call_sid,
|
|
18
|
+
'ConferenceSid' => :conference_sid,
|
|
19
|
+
'IncludeSoftDeleted' => :include_soft_deleted,
|
|
20
|
+
'Page' => :page,
|
|
21
|
+
'PageSize' => :page_size,
|
|
22
|
+
'PageToken' => :page_token
|
|
23
|
+
}.freeze
|
|
24
|
+
|
|
25
|
+
GET_FIELDS = {
|
|
26
|
+
'IncludeSoftDeleted' => :include_soft_deleted
|
|
27
|
+
}.freeze
|
|
28
|
+
|
|
29
|
+
# @return [VoiceML::RecordingList]
|
|
30
|
+
def list(**kwargs)
|
|
31
|
+
RecordingList.from_hash(
|
|
32
|
+
@transport.request(:get, path('Recordings'), params: form_params(LIST_FIELDS, kwargs))
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @yield [VoiceML::Recording]
|
|
37
|
+
# @return [Enumerator<VoiceML::Recording>] when no block given
|
|
38
|
+
def each(**kwargs, &block)
|
|
39
|
+
return enum_for(:each, **kwargs) unless block
|
|
40
|
+
|
|
41
|
+
page_num = kwargs.delete(:page) || 0
|
|
42
|
+
loop do
|
|
43
|
+
chunk = list(**kwargs, page: page_num)
|
|
44
|
+
chunk.recordings.each(&block)
|
|
45
|
+
break if chunk.next_page_uri.nil? || chunk.next_page_uri.empty? || chunk.recordings.empty?
|
|
46
|
+
page_num += 1
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Fetch the metadata JSON for a recording.
|
|
51
|
+
# @return [VoiceML::Recording]
|
|
52
|
+
def get(recording_sid, **kwargs)
|
|
53
|
+
params = form_params(GET_FIELDS, kwargs)
|
|
54
|
+
Recording.from_hash(
|
|
55
|
+
@transport.request(:get, path('Recordings', recording_sid), params: params.empty? ? nil : params)
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Fetch the WAV audio for a recording.
|
|
60
|
+
#
|
|
61
|
+
# Three server delivery shapes are flattened into one result by following any 302
|
|
62
|
+
# redirect to S3:
|
|
63
|
+
# - `200 OK` — local file present.
|
|
64
|
+
# - `302 Found` — archived to S3; the SDK follows the presigned URL.
|
|
65
|
+
# - `410 Gone` — local file gone AND no S3 key. Raises `VoiceML::GoneError`.
|
|
66
|
+
#
|
|
67
|
+
# @return [VoiceML::RecordingAudio]
|
|
68
|
+
def get_audio(recording_sid)
|
|
69
|
+
status, content, headers = @transport.fetch_bytes(
|
|
70
|
+
"#{path('Recordings', recording_sid, suffix: '')}.wav"
|
|
71
|
+
)
|
|
72
|
+
content_type = headers['content-type']
|
|
73
|
+
content_type = content_type.first if content_type.is_a?(Array)
|
|
74
|
+
x_amz_id = headers['x-amz-id-2']
|
|
75
|
+
RecordingAudio.new(
|
|
76
|
+
sid: recording_sid,
|
|
77
|
+
content: content,
|
|
78
|
+
content_type: content_type || 'application/octet-stream',
|
|
79
|
+
via_redirect: status == 200 && !x_amz_id.nil?
|
|
80
|
+
)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# @return [nil]
|
|
84
|
+
def delete(recording_sid)
|
|
85
|
+
@transport.request(:delete, path('Recordings', recording_sid))
|
|
86
|
+
nil
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|