rev-api 2.1.0 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 +100 -100
- data/lib/rev-api/http_client.rb +97 -97
- data/lib/rev-api/models/order.rb +138 -138
- data/lib/rev-api/models/order_request.rb +222 -228
- 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 +58 -58
- data/spec/fixtures/api_cassettes/get_tr_order.yml +44 -44
- 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/submit_tr_order.yml +44 -44
- 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 +67 -67
- data/spec/lib/rev/get_orders_spec.rb +61 -61
- data/spec/lib/rev/http_client_spec.rb +32 -32
- data/spec/lib/rev/models/order_request_spec.rb +6 -14
- 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 +195 -195
- data/spec/spec_helper.rb +49 -49
- metadata +39 -82
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
|
-
# translation, 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
|
-
# finished translation or a source file for an order.
|
115
|
-
# For transcript and translation 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
|
-
# finished translation or a source file for an order.
|
150
|
-
# For transcript and translation 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
|
-
# or translation 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
|
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
|
+
# translation, 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
|
+
# finished translation or a source file for an order.
|
115
|
+
# For transcript and translation 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
|
+
# finished translation or a source file for an order.
|
150
|
+
# For transcript and translation 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
|
+
# or translation 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
|