rev-api 2.2.0 → 2.2.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 +4 -4
- data/.coveralls.yml +1 -1
- data/.gitignore +21 -21
- data/.ruby-gemset +1 -1
- data/.ruby-version +1 -1
- data/.travis.yml +8 -8
- data/Gemfile +3 -3
- data/LICENSE +191 -191
- data/README.md +132 -132
- data/Rakefile +13 -13
- data/examples/cli.rb +270 -270
- data/lib/rev-api.rb +25 -25
- data/lib/rev-api/api.rb +326 -326
- data/lib/rev-api/api_serializable.rb +30 -30
- data/lib/rev-api/exceptions.rb +97 -100
- data/lib/rev-api/http_client.rb +97 -97
- data/lib/rev-api/models/order.rb +130 -138
- data/lib/rev-api/models/order_request.rb +194 -222
- data/lib/rev-api/version.rb +3 -3
- data/rev-api.gemspec +34 -34
- data/spec/fixtures/api_cassettes/cancel_order.yml +38 -38
- data/spec/fixtures/api_cassettes/cancel_order_not_allowed.yml +40 -40
- data/spec/fixtures/api_cassettes/get_attachment_content.yml +399 -399
- data/spec/fixtures/api_cassettes/get_attachment_content_as_pdf.yml +399 -399
- data/spec/fixtures/api_cassettes/get_attachment_content_as_text.yml +65 -65
- data/spec/fixtures/api_cassettes/get_attachment_content_as_youtube_transcript.yml +66 -66
- data/spec/fixtures/api_cassettes/get_attachment_content_unacceptable_representation.yml +42 -42
- data/spec/fixtures/api_cassettes/get_attachment_content_with_invalid_id.yml +42 -42
- data/spec/fixtures/api_cassettes/get_attachment_metadata.yml +42 -42
- data/spec/fixtures/api_cassettes/get_attachment_with_invalid_id.yml +40 -40
- data/spec/fixtures/api_cassettes/get_orders.yml +122 -122
- data/spec/fixtures/api_cassettes/get_orders_with_clientRef.yml +41 -41
- data/spec/fixtures/api_cassettes/get_tc_order.yml +44 -44
- data/spec/fixtures/api_cassettes/get_third_page_of_orders.yml +52 -58
- data/spec/fixtures/api_cassettes/link_input.yml +44 -44
- data/spec/fixtures/api_cassettes/link_input_with_all_attributes.yml +44 -44
- data/spec/fixtures/api_cassettes/link_input_with_spaces_in_filename.yml +45 -45
- data/spec/fixtures/api_cassettes/not_found_order.yml +42 -42
- data/spec/fixtures/api_cassettes/submit_cp_order.yml +45 -45
- data/spec/fixtures/api_cassettes/submit_su_order.yml +45 -45
- data/spec/fixtures/api_cassettes/submit_tc_order_with_account_balance.yml +45 -45
- data/spec/fixtures/api_cassettes/submit_tc_order_with_invalid_request.yml +45 -45
- data/spec/fixtures/api_cassettes/submit_tc_order_without_specifying_payment.yml +45 -45
- data/spec/fixtures/api_cassettes/unauthorized.yml +42 -42
- data/spec/fixtures/api_cassettes/upload_input.yml +90 -90
- data/spec/fixtures/api_cassettes/upload_input_with_invalid_content_type.yml +91 -91
- data/spec/lib/rev/api_spec.rb +24 -24
- data/spec/lib/rev/cancel_order_spec.rb +24 -24
- data/spec/lib/rev/exceptions_spec.rb +8 -8
- data/spec/lib/rev/get_attachment_content_spec.rb +79 -79
- data/spec/lib/rev/get_attachment_metadata_spec.rb +33 -33
- data/spec/lib/rev/get_order_spec.rb +52 -68
- data/spec/lib/rev/get_orders_spec.rb +62 -62
- data/spec/lib/rev/http_client_spec.rb +32 -32
- data/spec/lib/rev/models/order_request_spec.rb +0 -7
- data/spec/lib/rev/models/order_spec.rb +58 -58
- data/spec/lib/rev/post_inputs_spec.rb +94 -94
- data/spec/lib/rev/post_order_spec.rb +163 -195
- data/spec/spec_helper.rb +49 -49
- metadata +38 -41
- data/spec/fixtures/api_cassettes/get_tr_order.yml +0 -44
- data/spec/fixtures/api_cassettes/submit_tr_order.yml +0 -44
data/lib/rev-api.rb
CHANGED
@@ -1,26 +1,26 @@
|
|
1
|
-
require 'httparty'
|
2
|
-
|
3
|
-
# These three are the only classes that should be accessed directly
|
4
|
-
require 'rev-api/api'
|
5
|
-
|
6
|
-
module Rev
|
7
|
-
class << self
|
8
|
-
# Alias for Rev::Api.new
|
9
|
-
#
|
10
|
-
# @return [Rev::Api]
|
11
|
-
def new(client_api_key, user_api_key, host)
|
12
|
-
Rev::Api.new(client_api_key, user_api_key, host)
|
13
|
-
end
|
14
|
-
|
15
|
-
# Delegate to Rev::Api
|
16
|
-
#
|
17
|
-
def method_missing(method, *args, &block)
|
18
|
-
return super unless new.respond_to?(method)
|
19
|
-
new.send(method, *args, &block)
|
20
|
-
end
|
21
|
-
|
22
|
-
def respond_to?(method, include_private = false)
|
23
|
-
new.respond_to?(method, include_private) || super(method, include_private)
|
24
|
-
end
|
25
|
-
end
|
1
|
+
require 'httparty'
|
2
|
+
|
3
|
+
# These three are the only classes that should be accessed directly
|
4
|
+
require 'rev-api/api'
|
5
|
+
|
6
|
+
module Rev
|
7
|
+
class << self
|
8
|
+
# Alias for Rev::Api.new
|
9
|
+
#
|
10
|
+
# @return [Rev::Api]
|
11
|
+
def new(client_api_key, user_api_key, host)
|
12
|
+
Rev::Api.new(client_api_key, user_api_key, host)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Delegate to Rev::Api
|
16
|
+
#
|
17
|
+
def method_missing(method, *args, &block)
|
18
|
+
return super unless new.respond_to?(method)
|
19
|
+
new.send(method, *args, &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
def respond_to?(method, include_private = false)
|
23
|
+
new.respond_to?(method, include_private) || super(method, include_private)
|
24
|
+
end
|
25
|
+
end
|
26
26
|
end
|
data/lib/rev-api/api.rb
CHANGED
@@ -1,326 +1,326 @@
|
|
1
|
-
require 'rev-api/version'
|
2
|
-
require 'rev-api/http_client'
|
3
|
-
require 'rev-api/exceptions'
|
4
|
-
require 'json'
|
5
|
-
|
6
|
-
# automatically include business logic objects
|
7
|
-
Dir[File.dirname(__FILE__) + '/models/*.rb'].each do |file|
|
8
|
-
require file
|
9
|
-
end
|
10
|
-
|
11
|
-
# Rev API Ruby SDK
|
12
|
-
module Rev
|
13
|
-
# Main point of interaction with API.
|
14
|
-
# Wraps common REST operations, returning plain objects.
|
15
|
-
# Internally utilizes JSON resource representation.
|
16
|
-
class Api
|
17
|
-
|
18
|
-
# Production host. Used by default for new Rev::Api client
|
19
|
-
PRODUCTION_HOST = 'www.rev.com'
|
20
|
-
|
21
|
-
# Sandbox domain - pass 'Rev::Api::SANDBOX_HOST' as third param
|
22
|
-
# into Rev::Api ctor
|
23
|
-
SANDBOX_HOST = 'api-sandbox.rev.com'
|
24
|
-
|
25
|
-
# @note https://www.rev.com/api/security
|
26
|
-
# @param client_api_key [String] secret key specific to each partner that wishes to use the Rev API
|
27
|
-
# @param user_api_key [String] secret key specific to a Rev user, which identifies the user account under whose privileges the requested operation executes
|
28
|
-
# @param host [String] use {Rev::Api::PRODUCTION_HOST} or {Rev::Api::SANDBOX_HOST}. Production is default value
|
29
|
-
# @return [HttpClient] client obj
|
30
|
-
def initialize(client_api_key, user_api_key, host = PRODUCTION_HOST)
|
31
|
-
@client = HttpClient.new(client_api_key, user_api_key, host)
|
32
|
-
end
|
33
|
-
|
34
|
-
# Loads single page of existing orders for current client
|
35
|
-
#
|
36
|
-
# @note https://www.rev.com/api/ordersget
|
37
|
-
# @param page [Int, nil] 0-based page number, defaults to 0
|
38
|
-
# @return [OrdersListPage] paged result containing 'orders'
|
39
|
-
def get_orders_page(page = 0)
|
40
|
-
response = @client.get("/orders?page=#{page.to_i}")
|
41
|
-
Api.verify_get_response(response)
|
42
|
-
OrdersListPage.new(Api.parse(response))
|
43
|
-
end
|
44
|
-
|
45
|
-
# Loads all orders for current client. Works by calling get_orders_page multiple times.
|
46
|
-
# Use with caution if your order list might be large.
|
47
|
-
#
|
48
|
-
# @note https://www.rev.com/api/ordersget
|
49
|
-
# @return [Array of Order] list of orders
|
50
|
-
def get_all_orders
|
51
|
-
orders = []
|
52
|
-
page = 0
|
53
|
-
loop do
|
54
|
-
orders_page = self.get_orders_page page
|
55
|
-
page += 1
|
56
|
-
orders.push *orders_page.orders
|
57
|
-
break if (page * orders_page.results_per_page >= orders_page.total_count)
|
58
|
-
end
|
59
|
-
orders
|
60
|
-
end
|
61
|
-
|
62
|
-
# Loads orders whose associated reference ID is the given client_ref
|
63
|
-
#
|
64
|
-
# @note https://www.rev.com/api/ordersget
|
65
|
-
# @param client_ref [String, nil] client reference (required)
|
66
|
-
# @param page [Int, nil] 0-based page number, defaults to 0
|
67
|
-
# @return [OrdersListPage] paged result containing 'orders' list
|
68
|
-
# @raise [ArgumentError] client_ref is nil
|
69
|
-
def get_orders_by_client_ref(client_ref, page = 0)
|
70
|
-
raise ArgumentError if client_ref.nil?
|
71
|
-
|
72
|
-
response = @client.get("/orders?clientRef=#{URI.escape(client_ref)}&page=#{page.to_i}")
|
73
|
-
Api.verify_get_response(response)
|
74
|
-
OrdersListPage.new(Api.parse(response))
|
75
|
-
end
|
76
|
-
|
77
|
-
# Returns Order given an order number.
|
78
|
-
#
|
79
|
-
# @note https://www.rev.com/api/ordersgetone
|
80
|
-
# @param number [String] order number, like 'TCXXXXXXXX'
|
81
|
-
# @return [Order] order obj
|
82
|
-
def get_order(number)
|
83
|
-
response = @client.get("/orders/#{number}")
|
84
|
-
Api.verify_get_response(response)
|
85
|
-
Order.new(Api.parse(response))
|
86
|
-
end
|
87
|
-
|
88
|
-
# Cancel an order by number. If cancellation is not allowed, Rev::Api::BadRequestError is raised.
|
89
|
-
#
|
90
|
-
# @note https://www.rev.com/api/orderscancel
|
91
|
-
# @param number [String] order number
|
92
|
-
# @return [Boolean] true on success, raised Exception from Rev::Api namespace otherwise
|
93
|
-
def cancel_order(number)
|
94
|
-
data = { :order_num => number }
|
95
|
-
response = @client.post("/orders/#{number}/cancel", data)
|
96
|
-
Api.verify_post_response(response)
|
97
|
-
end
|
98
|
-
|
99
|
-
# Get metadata about an order attachment.
|
100
|
-
# Use this method to retrieve information about an order attachment (either transcript,
|
101
|
-
#
|
102
|
-
#
|
103
|
-
# @note https://www.rev.com/api/attachmentsget
|
104
|
-
# @param id [String] attachment id, as returned in info about an order
|
105
|
-
# @return [Attachment] attachment object
|
106
|
-
def get_attachment_metadata(id)
|
107
|
-
response = @client.get("/attachments/#{id}")
|
108
|
-
Api.verify_get_response(response)
|
109
|
-
Attachment.new(Api.parse(response))
|
110
|
-
end
|
111
|
-
|
112
|
-
# Get the raw data for the attachment with given id.
|
113
|
-
# Download the contents of an attachment. Use this method to download either a finished transcript,
|
114
|
-
#
|
115
|
-
# For transcript
|
116
|
-
# representation, specified via a mime-type.
|
117
|
-
#
|
118
|
-
# See {Rev::Order::Attachment::REPRESENTATIONS} hash, which contains symbols for currently supported mime types.
|
119
|
-
# The authoritative list is in the API documentation at https://www.rev.com/api/attachmentsgetcontent
|
120
|
-
#
|
121
|
-
# If a block is given, the response is passed to the block directly, to allow progressive reading of the data.
|
122
|
-
# In this case, the block must itself check for error responses, using Api.verify_get_response.
|
123
|
-
# If no block is given, the full response is returned. In that case, if the response is an error, an appropriate
|
124
|
-
# error is raised.
|
125
|
-
#
|
126
|
-
# @param id [String] attachment id
|
127
|
-
# @param mime_type [String, nil] mime-type for the desired format in which the content should be retrieved.
|
128
|
-
# @yieldparam resp [Net::HTTP::Response] the response, ready to be read
|
129
|
-
# @return [Net::HTTP::Response] the response containing raw data
|
130
|
-
def get_attachment_content(id, mime_type = nil, &block)
|
131
|
-
headers = {}
|
132
|
-
|
133
|
-
unless mime_type.nil?
|
134
|
-
headers['Accept'] = mime_type
|
135
|
-
headers['Accept-Charset'] = 'utf-8' if mime_type.start_with? 'text/'
|
136
|
-
end
|
137
|
-
|
138
|
-
if block_given?
|
139
|
-
@client.get_binary("/attachments/#{id}/content", headers, &block)
|
140
|
-
else
|
141
|
-
response = @client.get_binary("/attachments/#{id}/content", headers)
|
142
|
-
Api.verify_get_response(response)
|
143
|
-
response
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
# Get the raw data for the attachment with given id.
|
148
|
-
# Download the contents of an attachment and save it into a file. Use this method to download either a finished transcript,
|
149
|
-
#
|
150
|
-
# For transcript
|
151
|
-
# representation, specified via a mime-type.
|
152
|
-
#
|
153
|
-
# See {Rev::Order::Attachment::REPRESENTATIONS} hash, which contains symbols for currently supported mime types.
|
154
|
-
# The authoritative list is in the API documentation at https://www.rev.com/api/attachmentsgetcontent
|
155
|
-
#
|
156
|
-
# @param id [String] attachment id
|
157
|
-
# @param path [String, nil] path to file into which the content is to be saved.
|
158
|
-
# @param mime_type [String, nil] mime-type for the desired format in which the content should be retrieved.
|
159
|
-
# @return [String] filepath content has been saved to. Might raise standard IO exception if file creation files
|
160
|
-
def save_attachment_content(id, path, mime_type = nil)
|
161
|
-
headers = {}
|
162
|
-
|
163
|
-
unless mime_type.nil?
|
164
|
-
headers['Accept'] = mime_type
|
165
|
-
headers['Accept-Charset'] = 'utf-8' if mime_type.start_with? 'text/'
|
166
|
-
end
|
167
|
-
|
168
|
-
# same simple approach as box-api does for now: return response.body as-is if path for saving is nil
|
169
|
-
File.open(path, 'wb') do |file|
|
170
|
-
response = @client.get_binary("/attachments/#{id}/content", headers) do |resp|
|
171
|
-
resp.read_body do |segment|
|
172
|
-
file.write(segment)
|
173
|
-
end
|
174
|
-
end
|
175
|
-
Api.verify_get_response(response)
|
176
|
-
end
|
177
|
-
|
178
|
-
# we don't handle IO-related exceptions
|
179
|
-
path
|
180
|
-
end
|
181
|
-
|
182
|
-
# Get the content of the attachment with given id as a string. Use this method to grab the contents of a finished transcript
|
183
|
-
#
|
184
|
-
# binary files like MP3s, which cannot be converted to a string.
|
185
|
-
#
|
186
|
-
# May raise Rev::Api::NotAcceptableError if the attachment cannot be converted into a text representation.
|
187
|
-
#
|
188
|
-
# @param id [String] attachment id
|
189
|
-
# @return [String] the content of the attachment as a string
|
190
|
-
def get_attachment_content_as_string(id)
|
191
|
-
response = self.get_attachment_content(id, Attachment::REPRESENTATIONS[:txt])
|
192
|
-
response.body
|
193
|
-
end
|
194
|
-
|
195
|
-
# Submit a new order using {Rev::OrderRequest}.
|
196
|
-
# @note https://www.rev.com/api/ordersposttranscription - for full information
|
197
|
-
#
|
198
|
-
# @param order_request [OrderRequest] object specifying payment, inputs, options and notification info.
|
199
|
-
# inputs must previously be uploaded using upload_input or create_input_from_link
|
200
|
-
# @return [String] order number for the new order
|
201
|
-
# Raises {Rev::BadRequestError} on failure (.code attr exposes API error code -
|
202
|
-
# see {Rev::OrderRequestError}).
|
203
|
-
def submit_order(order_request)
|
204
|
-
response = @client.post("/orders", order_request.to_json, { 'Content-Type' => 'application/json' })
|
205
|
-
Api.verify_post_response(response)
|
206
|
-
|
207
|
-
new_order_uri = response.headers['Location']
|
208
|
-
return new_order_uri.split('/')[-1]
|
209
|
-
end
|
210
|
-
|
211
|
-
# Upload given local file directly as source input for order.
|
212
|
-
# @note https://www.rev.com/api/inputspost
|
213
|
-
#
|
214
|
-
# @param path [String] mandatory, path to local file (relative or absolute) to upload
|
215
|
-
# @param content_type [String] mandatory, content-type of the file you're uploading
|
216
|
-
# @return [String] URI identifying newly uploaded media. This URI can be used to identify the input
|
217
|
-
# when constructing a OrderRequest object to submit an order.
|
218
|
-
# {Rev::BadRequestError} is raised on failure (.code attr exposes API error code -
|
219
|
-
# see {Rev::InputRequestError}).
|
220
|
-
def upload_input(path, content_type)
|
221
|
-
filename = Pathname.new(path).basename
|
222
|
-
headers = {
|
223
|
-
'Content-Disposition' => "attachment; filename=\"#{filename}\"",
|
224
|
-
'Content-Type' => content_type
|
225
|
-
}
|
226
|
-
|
227
|
-
File.open(path) do |data|
|
228
|
-
response = @client.post_binary("/inputs", data, headers)
|
229
|
-
Api.verify_post_response(response)
|
230
|
-
|
231
|
-
headers = HTTParty::Response::Headers.new(response.to_hash)
|
232
|
-
return headers['Location']
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
|
-
# Request creation of a source input based on an external URL which the server will attempt to download.
|
237
|
-
# @note https://www.rev.com/api/inputspost
|
238
|
-
#
|
239
|
-
# @param url [String] mandatory, URL where the media can be retrieved. Must be publicly accessible.
|
240
|
-
# HTTPS urls are ok as long as the site in question has a valid certificate
|
241
|
-
# @param filename [String, nil] optional, the filename for the media. If not specified, we will
|
242
|
-
# determine it from the URL
|
243
|
-
# @param content_type [String, nil] optional, the content type of the media to be retrieved.
|
244
|
-
# If not specified, we will try to determine it from the server response
|
245
|
-
# @return [String] URI identifying newly uploaded media. This URI can be used to identify the input
|
246
|
-
# when constructing a OrderRequest object to submit an order.
|
247
|
-
# {Rev::BadRequestError} is raised on failure (.code attr exposes API error code -
|
248
|
-
# see {Rev::InputRequestError}).
|
249
|
-
def create_input_from_link(url, filename = nil, content_type = nil)
|
250
|
-
request = { :url => url }
|
251
|
-
request[:filename] = filename unless filename.nil?
|
252
|
-
request[:content_type] = content_type unless content_type.nil?
|
253
|
-
|
254
|
-
response = @client.post("/inputs", request.to_json, { 'Content-Type' => 'application/json' })
|
255
|
-
Api.verify_post_response(response)
|
256
|
-
|
257
|
-
response.headers['Location']
|
258
|
-
end
|
259
|
-
|
260
|
-
private
|
261
|
-
# Below are utility helper methods for handling response
|
262
|
-
class << self
|
263
|
-
|
264
|
-
# Parse given response's body JSON into Hash, so that it might be
|
265
|
-
# easily mapped onto business logic object.
|
266
|
-
#
|
267
|
-
# @param response [Response] HTTParty response obj
|
268
|
-
# @return [Hash] hash of values parsed from JSON
|
269
|
-
def parse(response)
|
270
|
-
JSON.load response.body.to_s
|
271
|
-
end
|
272
|
-
|
273
|
-
# Raises exception if response is not considered as success
|
274
|
-
#
|
275
|
-
# @param response [HTTPParty::Response] HTTParty response obj. Net::HTTPResponse represented by .response
|
276
|
-
# @return [Boolean] true if response is considered as successful
|
277
|
-
def verify_get_response(response)
|
278
|
-
# HTTP response codes are handled here and propagated up to the caller, since caller should be able
|
279
|
-
# to handle all types of errors the same - using exceptions
|
280
|
-
unless response.response.instance_of? Net::HTTPOK
|
281
|
-
Api.handle_error(response)
|
282
|
-
end
|
283
|
-
|
284
|
-
true
|
285
|
-
end
|
286
|
-
|
287
|
-
# (see #verify_get_response)
|
288
|
-
def verify_post_response(response)
|
289
|
-
# see https://www.rev.com/api/errorhandling
|
290
|
-
unless response.response.instance_of?(Net::HTTPCreated) || response.response.instance_of?(Net::HTTPNoContent)
|
291
|
-
Api.handle_error(response)
|
292
|
-
end
|
293
|
-
|
294
|
-
true
|
295
|
-
end
|
296
|
-
|
297
|
-
# Given a response, raises a corresponding Exception.
|
298
|
-
# Full response is given for the sake of BadRequest reporting,
|
299
|
-
# which usually contains validation errors.
|
300
|
-
#
|
301
|
-
# @param response [Response] containing failing status to look for
|
302
|
-
def handle_error(response)
|
303
|
-
case response.response
|
304
|
-
when Net::HTTPBadRequest
|
305
|
-
# Bad request - response contains error code and details. Usually means failed validation
|
306
|
-
body = JSON.load response.body.to_s
|
307
|
-
msg = "API responded with code #{body['code']}: #{body['message']}"
|
308
|
-
msg += " Details: #{body['detail'].to_s}" if body['detail']
|
309
|
-
raise BadRequestError.new msg, body['code']
|
310
|
-
when Net::HTTPUnauthorized
|
311
|
-
raise NotAuthorizedError
|
312
|
-
when Net::HTTPForbidden
|
313
|
-
raise ForbiddenError
|
314
|
-
when Net::HTTPNotFound
|
315
|
-
raise NotFoundError
|
316
|
-
when Net::HTTPNotAcceptable
|
317
|
-
raise NotAcceptableError
|
318
|
-
when Net::HTTPServerError
|
319
|
-
raise ServerError, "Status code: #{response.code}"
|
320
|
-
else
|
321
|
-
raise UnknownError
|
322
|
-
end
|
323
|
-
end
|
324
|
-
end
|
325
|
-
end
|
326
|
-
end
|
1
|
+
require 'rev-api/version'
|
2
|
+
require 'rev-api/http_client'
|
3
|
+
require 'rev-api/exceptions'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
# automatically include business logic objects
|
7
|
+
Dir[File.dirname(__FILE__) + '/models/*.rb'].each do |file|
|
8
|
+
require file
|
9
|
+
end
|
10
|
+
|
11
|
+
# Rev API Ruby SDK
|
12
|
+
module Rev
|
13
|
+
# Main point of interaction with API.
|
14
|
+
# Wraps common REST operations, returning plain objects.
|
15
|
+
# Internally utilizes JSON resource representation.
|
16
|
+
class Api
|
17
|
+
|
18
|
+
# Production host. Used by default for new Rev::Api client
|
19
|
+
PRODUCTION_HOST = 'www.rev.com'
|
20
|
+
|
21
|
+
# Sandbox domain - pass 'Rev::Api::SANDBOX_HOST' as third param
|
22
|
+
# into Rev::Api ctor
|
23
|
+
SANDBOX_HOST = 'api-sandbox.rev.com'
|
24
|
+
|
25
|
+
# @note https://www.rev.com/api/security
|
26
|
+
# @param client_api_key [String] secret key specific to each partner that wishes to use the Rev API
|
27
|
+
# @param user_api_key [String] secret key specific to a Rev user, which identifies the user account under whose privileges the requested operation executes
|
28
|
+
# @param host [String] use {Rev::Api::PRODUCTION_HOST} or {Rev::Api::SANDBOX_HOST}. Production is default value
|
29
|
+
# @return [HttpClient] client obj
|
30
|
+
def initialize(client_api_key, user_api_key, host = PRODUCTION_HOST)
|
31
|
+
@client = HttpClient.new(client_api_key, user_api_key, host)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Loads single page of existing orders for current client
|
35
|
+
#
|
36
|
+
# @note https://www.rev.com/api/ordersget
|
37
|
+
# @param page [Int, nil] 0-based page number, defaults to 0
|
38
|
+
# @return [OrdersListPage] paged result containing 'orders'
|
39
|
+
def get_orders_page(page = 0)
|
40
|
+
response = @client.get("/orders?page=#{page.to_i}")
|
41
|
+
Api.verify_get_response(response)
|
42
|
+
OrdersListPage.new(Api.parse(response))
|
43
|
+
end
|
44
|
+
|
45
|
+
# Loads all orders for current client. Works by calling get_orders_page multiple times.
|
46
|
+
# Use with caution if your order list might be large.
|
47
|
+
#
|
48
|
+
# @note https://www.rev.com/api/ordersget
|
49
|
+
# @return [Array of Order] list of orders
|
50
|
+
def get_all_orders
|
51
|
+
orders = []
|
52
|
+
page = 0
|
53
|
+
loop do
|
54
|
+
orders_page = self.get_orders_page page
|
55
|
+
page += 1
|
56
|
+
orders.push *orders_page.orders
|
57
|
+
break if (page * orders_page.results_per_page >= orders_page.total_count)
|
58
|
+
end
|
59
|
+
orders
|
60
|
+
end
|
61
|
+
|
62
|
+
# Loads orders whose associated reference ID is the given client_ref
|
63
|
+
#
|
64
|
+
# @note https://www.rev.com/api/ordersget
|
65
|
+
# @param client_ref [String, nil] client reference (required)
|
66
|
+
# @param page [Int, nil] 0-based page number, defaults to 0
|
67
|
+
# @return [OrdersListPage] paged result containing 'orders' list
|
68
|
+
# @raise [ArgumentError] client_ref is nil
|
69
|
+
def get_orders_by_client_ref(client_ref, page = 0)
|
70
|
+
raise ArgumentError if client_ref.nil?
|
71
|
+
|
72
|
+
response = @client.get("/orders?clientRef=#{URI.escape(client_ref)}&page=#{page.to_i}")
|
73
|
+
Api.verify_get_response(response)
|
74
|
+
OrdersListPage.new(Api.parse(response))
|
75
|
+
end
|
76
|
+
|
77
|
+
# Returns Order given an order number.
|
78
|
+
#
|
79
|
+
# @note https://www.rev.com/api/ordersgetone
|
80
|
+
# @param number [String] order number, like 'TCXXXXXXXX'
|
81
|
+
# @return [Order] order obj
|
82
|
+
def get_order(number)
|
83
|
+
response = @client.get("/orders/#{number}")
|
84
|
+
Api.verify_get_response(response)
|
85
|
+
Order.new(Api.parse(response))
|
86
|
+
end
|
87
|
+
|
88
|
+
# Cancel an order by number. If cancellation is not allowed, Rev::Api::BadRequestError is raised.
|
89
|
+
#
|
90
|
+
# @note https://www.rev.com/api/orderscancel
|
91
|
+
# @param number [String] order number
|
92
|
+
# @return [Boolean] true on success, raised Exception from Rev::Api namespace otherwise
|
93
|
+
def cancel_order(number)
|
94
|
+
data = { :order_num => number }
|
95
|
+
response = @client.post("/orders/#{number}/cancel", data)
|
96
|
+
Api.verify_post_response(response)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Get metadata about an order attachment.
|
100
|
+
# Use this method to retrieve information about an order attachment (either transcript,
|
101
|
+
# caption or source file).
|
102
|
+
#
|
103
|
+
# @note https://www.rev.com/api/attachmentsget
|
104
|
+
# @param id [String] attachment id, as returned in info about an order
|
105
|
+
# @return [Attachment] attachment object
|
106
|
+
def get_attachment_metadata(id)
|
107
|
+
response = @client.get("/attachments/#{id}")
|
108
|
+
Api.verify_get_response(response)
|
109
|
+
Attachment.new(Api.parse(response))
|
110
|
+
end
|
111
|
+
|
112
|
+
# Get the raw data for the attachment with given id.
|
113
|
+
# Download the contents of an attachment. Use this method to download either a finished transcript,
|
114
|
+
# or a source file for an order.
|
115
|
+
# For transcript attachments, you may request to get the contents in a specific
|
116
|
+
# representation, specified via a mime-type.
|
117
|
+
#
|
118
|
+
# See {Rev::Order::Attachment::REPRESENTATIONS} hash, which contains symbols for currently supported mime types.
|
119
|
+
# The authoritative list is in the API documentation at https://www.rev.com/api/attachmentsgetcontent
|
120
|
+
#
|
121
|
+
# If a block is given, the response is passed to the block directly, to allow progressive reading of the data.
|
122
|
+
# In this case, the block must itself check for error responses, using Api.verify_get_response.
|
123
|
+
# If no block is given, the full response is returned. In that case, if the response is an error, an appropriate
|
124
|
+
# error is raised.
|
125
|
+
#
|
126
|
+
# @param id [String] attachment id
|
127
|
+
# @param mime_type [String, nil] mime-type for the desired format in which the content should be retrieved.
|
128
|
+
# @yieldparam resp [Net::HTTP::Response] the response, ready to be read
|
129
|
+
# @return [Net::HTTP::Response] the response containing raw data
|
130
|
+
def get_attachment_content(id, mime_type = nil, &block)
|
131
|
+
headers = {}
|
132
|
+
|
133
|
+
unless mime_type.nil?
|
134
|
+
headers['Accept'] = mime_type
|
135
|
+
headers['Accept-Charset'] = 'utf-8' if mime_type.start_with? 'text/'
|
136
|
+
end
|
137
|
+
|
138
|
+
if block_given?
|
139
|
+
@client.get_binary("/attachments/#{id}/content", headers, &block)
|
140
|
+
else
|
141
|
+
response = @client.get_binary("/attachments/#{id}/content", headers)
|
142
|
+
Api.verify_get_response(response)
|
143
|
+
response
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Get the raw data for the attachment with given id.
|
148
|
+
# Download the contents of an attachment and save it into a file. Use this method to download either a finished transcript,
|
149
|
+
# or a source file for an order.
|
150
|
+
# For transcript attachments, you may request to get the contents in a specific
|
151
|
+
# representation, specified via a mime-type.
|
152
|
+
#
|
153
|
+
# See {Rev::Order::Attachment::REPRESENTATIONS} hash, which contains symbols for currently supported mime types.
|
154
|
+
# The authoritative list is in the API documentation at https://www.rev.com/api/attachmentsgetcontent
|
155
|
+
#
|
156
|
+
# @param id [String] attachment id
|
157
|
+
# @param path [String, nil] path to file into which the content is to be saved.
|
158
|
+
# @param mime_type [String, nil] mime-type for the desired format in which the content should be retrieved.
|
159
|
+
# @return [String] filepath content has been saved to. Might raise standard IO exception if file creation files
|
160
|
+
def save_attachment_content(id, path, mime_type = nil)
|
161
|
+
headers = {}
|
162
|
+
|
163
|
+
unless mime_type.nil?
|
164
|
+
headers['Accept'] = mime_type
|
165
|
+
headers['Accept-Charset'] = 'utf-8' if mime_type.start_with? 'text/'
|
166
|
+
end
|
167
|
+
|
168
|
+
# same simple approach as box-api does for now: return response.body as-is if path for saving is nil
|
169
|
+
File.open(path, 'wb') do |file|
|
170
|
+
response = @client.get_binary("/attachments/#{id}/content", headers) do |resp|
|
171
|
+
resp.read_body do |segment|
|
172
|
+
file.write(segment)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
Api.verify_get_response(response)
|
176
|
+
end
|
177
|
+
|
178
|
+
# we don't handle IO-related exceptions
|
179
|
+
path
|
180
|
+
end
|
181
|
+
|
182
|
+
# Get the content of the attachment with given id as a string. Use this method to grab the contents of a finished transcript
|
183
|
+
# as a string. This method should generally not be used for source attachments, as those are typically
|
184
|
+
# binary files like MP3s, which cannot be converted to a string.
|
185
|
+
#
|
186
|
+
# May raise Rev::Api::NotAcceptableError if the attachment cannot be converted into a text representation.
|
187
|
+
#
|
188
|
+
# @param id [String] attachment id
|
189
|
+
# @return [String] the content of the attachment as a string
|
190
|
+
def get_attachment_content_as_string(id)
|
191
|
+
response = self.get_attachment_content(id, Attachment::REPRESENTATIONS[:txt])
|
192
|
+
response.body
|
193
|
+
end
|
194
|
+
|
195
|
+
# Submit a new order using {Rev::OrderRequest}.
|
196
|
+
# @note https://www.rev.com/api/ordersposttranscription - for full information
|
197
|
+
#
|
198
|
+
# @param order_request [OrderRequest] object specifying payment, inputs, options and notification info.
|
199
|
+
# inputs must previously be uploaded using upload_input or create_input_from_link
|
200
|
+
# @return [String] order number for the new order
|
201
|
+
# Raises {Rev::BadRequestError} on failure (.code attr exposes API error code -
|
202
|
+
# see {Rev::OrderRequestError}).
|
203
|
+
def submit_order(order_request)
|
204
|
+
response = @client.post("/orders", order_request.to_json, { 'Content-Type' => 'application/json' })
|
205
|
+
Api.verify_post_response(response)
|
206
|
+
|
207
|
+
new_order_uri = response.headers['Location']
|
208
|
+
return new_order_uri.split('/')[-1]
|
209
|
+
end
|
210
|
+
|
211
|
+
# Upload given local file directly as source input for order.
|
212
|
+
# @note https://www.rev.com/api/inputspost
|
213
|
+
#
|
214
|
+
# @param path [String] mandatory, path to local file (relative or absolute) to upload
|
215
|
+
# @param content_type [String] mandatory, content-type of the file you're uploading
|
216
|
+
# @return [String] URI identifying newly uploaded media. This URI can be used to identify the input
|
217
|
+
# when constructing a OrderRequest object to submit an order.
|
218
|
+
# {Rev::BadRequestError} is raised on failure (.code attr exposes API error code -
|
219
|
+
# see {Rev::InputRequestError}).
|
220
|
+
def upload_input(path, content_type)
|
221
|
+
filename = Pathname.new(path).basename
|
222
|
+
headers = {
|
223
|
+
'Content-Disposition' => "attachment; filename=\"#{filename}\"",
|
224
|
+
'Content-Type' => content_type
|
225
|
+
}
|
226
|
+
|
227
|
+
File.open(path) do |data|
|
228
|
+
response = @client.post_binary("/inputs", data, headers)
|
229
|
+
Api.verify_post_response(response)
|
230
|
+
|
231
|
+
headers = HTTParty::Response::Headers.new(response.to_hash)
|
232
|
+
return headers['Location']
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
# Request creation of a source input based on an external URL which the server will attempt to download.
|
237
|
+
# @note https://www.rev.com/api/inputspost
|
238
|
+
#
|
239
|
+
# @param url [String] mandatory, URL where the media can be retrieved. Must be publicly accessible.
|
240
|
+
# HTTPS urls are ok as long as the site in question has a valid certificate
|
241
|
+
# @param filename [String, nil] optional, the filename for the media. If not specified, we will
|
242
|
+
# determine it from the URL
|
243
|
+
# @param content_type [String, nil] optional, the content type of the media to be retrieved.
|
244
|
+
# If not specified, we will try to determine it from the server response
|
245
|
+
# @return [String] URI identifying newly uploaded media. This URI can be used to identify the input
|
246
|
+
# when constructing a OrderRequest object to submit an order.
|
247
|
+
# {Rev::BadRequestError} is raised on failure (.code attr exposes API error code -
|
248
|
+
# see {Rev::InputRequestError}).
|
249
|
+
def create_input_from_link(url, filename = nil, content_type = nil)
|
250
|
+
request = { :url => url }
|
251
|
+
request[:filename] = filename unless filename.nil?
|
252
|
+
request[:content_type] = content_type unless content_type.nil?
|
253
|
+
|
254
|
+
response = @client.post("/inputs", request.to_json, { 'Content-Type' => 'application/json' })
|
255
|
+
Api.verify_post_response(response)
|
256
|
+
|
257
|
+
response.headers['Location']
|
258
|
+
end
|
259
|
+
|
260
|
+
private
|
261
|
+
# Below are utility helper methods for handling response
|
262
|
+
class << self
|
263
|
+
|
264
|
+
# Parse given response's body JSON into Hash, so that it might be
|
265
|
+
# easily mapped onto business logic object.
|
266
|
+
#
|
267
|
+
# @param response [Response] HTTParty response obj
|
268
|
+
# @return [Hash] hash of values parsed from JSON
|
269
|
+
def parse(response)
|
270
|
+
JSON.load response.body.to_s
|
271
|
+
end
|
272
|
+
|
273
|
+
# Raises exception if response is not considered as success
|
274
|
+
#
|
275
|
+
# @param response [HTTPParty::Response] HTTParty response obj. Net::HTTPResponse represented by .response
|
276
|
+
# @return [Boolean] true if response is considered as successful
|
277
|
+
def verify_get_response(response)
|
278
|
+
# HTTP response codes are handled here and propagated up to the caller, since caller should be able
|
279
|
+
# to handle all types of errors the same - using exceptions
|
280
|
+
unless response.response.instance_of? Net::HTTPOK
|
281
|
+
Api.handle_error(response)
|
282
|
+
end
|
283
|
+
|
284
|
+
true
|
285
|
+
end
|
286
|
+
|
287
|
+
# (see #verify_get_response)
|
288
|
+
def verify_post_response(response)
|
289
|
+
# see https://www.rev.com/api/errorhandling
|
290
|
+
unless response.response.instance_of?(Net::HTTPCreated) || response.response.instance_of?(Net::HTTPNoContent)
|
291
|
+
Api.handle_error(response)
|
292
|
+
end
|
293
|
+
|
294
|
+
true
|
295
|
+
end
|
296
|
+
|
297
|
+
# Given a response, raises a corresponding Exception.
|
298
|
+
# Full response is given for the sake of BadRequest reporting,
|
299
|
+
# which usually contains validation errors.
|
300
|
+
#
|
301
|
+
# @param response [Response] containing failing status to look for
|
302
|
+
def handle_error(response)
|
303
|
+
case response.response
|
304
|
+
when Net::HTTPBadRequest
|
305
|
+
# Bad request - response contains error code and details. Usually means failed validation
|
306
|
+
body = JSON.load response.body.to_s
|
307
|
+
msg = "API responded with code #{body['code']}: #{body['message']}"
|
308
|
+
msg += " Details: #{body['detail'].to_s}" if body['detail']
|
309
|
+
raise BadRequestError.new msg, body['code']
|
310
|
+
when Net::HTTPUnauthorized
|
311
|
+
raise NotAuthorizedError
|
312
|
+
when Net::HTTPForbidden
|
313
|
+
raise ForbiddenError
|
314
|
+
when Net::HTTPNotFound
|
315
|
+
raise NotFoundError
|
316
|
+
when Net::HTTPNotAcceptable
|
317
|
+
raise NotAcceptableError
|
318
|
+
when Net::HTTPServerError
|
319
|
+
raise ServerError, "Status code: #{response.code}"
|
320
|
+
else
|
321
|
+
raise UnknownError
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
end
|