rev-api 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +20 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +3 -0
  6. data/Gemfile.lock +42 -0
  7. data/LICENSE +191 -0
  8. data/README.md +124 -0
  9. data/Rakefile +14 -0
  10. data/examples/cli.rb +200 -0
  11. data/lib/rev-api.rb +26 -0
  12. data/lib/rev-api/api.rb +311 -0
  13. data/lib/rev-api/api_serializable.rb +30 -0
  14. data/lib/rev-api/exceptions.rb +108 -0
  15. data/lib/rev-api/http_client.rb +97 -0
  16. data/lib/rev-api/models/order.rb +113 -0
  17. data/lib/rev-api/models/order_request.rb +183 -0
  18. data/lib/rev-api/version.rb +3 -0
  19. data/rev-api.gemspec +33 -0
  20. data/spec/fixtures/api_cassettes/cancel_order.yml +38 -0
  21. data/spec/fixtures/api_cassettes/cancel_order_not_allowed.yml +40 -0
  22. data/spec/fixtures/api_cassettes/get_attachment_content.yml +399 -0
  23. data/spec/fixtures/api_cassettes/get_attachment_content_as_pdf.yml +399 -0
  24. data/spec/fixtures/api_cassettes/get_attachment_content_as_text.yml +65 -0
  25. data/spec/fixtures/api_cassettes/get_attachment_content_as_youtube_transcript.yml +66 -0
  26. data/spec/fixtures/api_cassettes/get_attachment_content_unacceptable_representation.yml +42 -0
  27. data/spec/fixtures/api_cassettes/get_attachment_content_with_invalid_id.yml +42 -0
  28. data/spec/fixtures/api_cassettes/get_attachment_metadata.yml +42 -0
  29. data/spec/fixtures/api_cassettes/get_attachment_with_invalid_id.yml +40 -0
  30. data/spec/fixtures/api_cassettes/get_orders.yml +122 -0
  31. data/spec/fixtures/api_cassettes/get_tc_order.yml +44 -0
  32. data/spec/fixtures/api_cassettes/get_third_page_of_orders.yml +58 -0
  33. data/spec/fixtures/api_cassettes/get_tr_order.yml +44 -0
  34. data/spec/fixtures/api_cassettes/link_input.yml +44 -0
  35. data/spec/fixtures/api_cassettes/link_input_with_all_attributes.yml +44 -0
  36. data/spec/fixtures/api_cassettes/not_found_order.yml +42 -0
  37. data/spec/fixtures/api_cassettes/submit_tc_order_with_account_balance.yml +45 -0
  38. data/spec/fixtures/api_cassettes/submit_tc_order_with_cc_and_all_attributes.yml +46 -0
  39. data/spec/fixtures/api_cassettes/submit_tc_order_with_invalid_request.yml +45 -0
  40. data/spec/fixtures/api_cassettes/submit_tc_order_with_saved_cc.yml +45 -0
  41. data/spec/fixtures/api_cassettes/submit_tr_order.yml +44 -0
  42. data/spec/fixtures/api_cassettes/unauthorized.yml +42 -0
  43. data/spec/fixtures/api_cassettes/upload_input.yml +130 -0
  44. data/spec/fixtures/api_cassettes/upload_input_with_invalid_content_type.yml +131 -0
  45. data/spec/fixtures/sourcedocument.png +0 -0
  46. data/spec/lib/rev/api_spec.rb +24 -0
  47. data/spec/lib/rev/cancel_order_spec.rb +25 -0
  48. data/spec/lib/rev/get_attachment_content_spec.rb +79 -0
  49. data/spec/lib/rev/get_attachment_metadata_spec.rb +33 -0
  50. data/spec/lib/rev/get_order_spec.rb +68 -0
  51. data/spec/lib/rev/get_orders_spec.rb +39 -0
  52. data/spec/lib/rev/http_client_spec.rb +32 -0
  53. data/spec/lib/rev/post_inputs_spec.rb +75 -0
  54. data/spec/lib/rev/post_order_spec.rb +207 -0
  55. data/spec/spec_helper.rb +31 -0
  56. metadata +248 -0
@@ -0,0 +1,68 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe 'GET /orders/{order_num}' do
4
+ let(:client) { Rev.new('welcome', 'AAAAAu/YjZ3phXU5FsF35yIcgiA=', 'www.revtrunk.com') }
5
+
6
+ describe 'Transcription' do
7
+ before do
8
+ VCR.insert_cassette 'get_tc_order'
9
+ end
10
+
11
+ it 'must get an order by given order number' do
12
+ client.get_order('TC0233908691').wont_be_nil
13
+
14
+ assert_requested :get, /.*\/api\/v1\/orders\/TC0233908691/, :times => 1
15
+ end
16
+
17
+ describe 'loaded order' do
18
+ let(:order) { client.get_order('TC0233908691') }
19
+
20
+ it 'must have basic attributes' do
21
+ order.order_number.must_equal 'TC0233908691'
22
+ order.price.must_equal 10.0
23
+ order.status.must_equal 'Finding Transcriptionist'
24
+ order.client_ref.must_equal 'XC123'
25
+ end
26
+
27
+ it 'must have comments' do
28
+ order.comments.size.must_equal 1
29
+ order.comments.first.by.must_equal 'Admin Admin'
30
+ order.comments.first.text.must_be_empty
31
+ order.comments.first.timestamp.day.must_equal 6
32
+ order.comments.first.timestamp.month.must_equal 9
33
+ order.comments.first.timestamp.year.must_equal 2013
34
+ end
35
+
36
+ it 'must have attachments' do
37
+ order.attachments.size.must_equal 1
38
+ order.attachments.first.kind.must_equal 'media'
39
+ end
40
+
41
+ it 'must have transcription info' do
42
+ order.transcription.total_length.must_equal 10
43
+ order.transcription.verbatim.must_equal false
44
+ order.transcription.timestamps.must_equal false
45
+ end
46
+ end
47
+ end
48
+
49
+ describe 'Translation' do
50
+ before do
51
+ VCR.insert_cassette 'get_tr_order'
52
+ end
53
+
54
+ describe 'loaded order' do
55
+ let(:order) { client.get_order('TR0116711100') }
56
+
57
+ it 'must have translation info' do
58
+ order.translation.total_word_count.must_equal 2
59
+ order.translation.source_language_code.must_equal 'cs'
60
+ order.translation.destination_language_code.must_equal 'en'
61
+ end
62
+ end
63
+ end
64
+
65
+ after do
66
+ VCR.eject_cassette
67
+ end
68
+ end
@@ -0,0 +1,39 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe 'GET /orders' do
4
+ let(:client) { Rev.new('welcome', 'AAAAAu/YjZ3phXU5FsF35yIcgiA=', 'www.revtrunk.com') }
5
+
6
+ describe 'GET /orders without page number' do
7
+ it 'must get first page of existing orders' do
8
+ VCR.insert_cassette 'get_orders'
9
+
10
+ page = client.get_orders_page
11
+
12
+ assert_requested :get, /.*\/api\/v1\/orders\?page=0/, :times => 1
13
+
14
+ page.orders.must_be_instance_of Array
15
+ page.results_per_page.must_equal 8
16
+ page.orders.size.must_equal 8
17
+ page.page.must_equal 0
18
+ page.total_count.must_equal 77
19
+ end
20
+ end
21
+
22
+ describe 'GET /orders?page={pagenum}' do
23
+ it 'must load any page' do
24
+ VCR.insert_cassette 'get_third_page_of_orders'
25
+
26
+ page = client.get_orders_page(2)
27
+
28
+ assert_requested :get, /.*\/api\/v1\/orders\?page=2/, :times => 1
29
+
30
+ page.orders.size.must_equal 8
31
+ page.page.must_equal 2
32
+ page.orders.first.order_number.must_equal 'TC0229215557'
33
+ end
34
+ end
35
+
36
+ after do
37
+ VCR.eject_cassette
38
+ end
39
+ end
@@ -0,0 +1,32 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe Rev::HttpClient do
4
+ it 'must support predefined production host' do
5
+ client = Rev::HttpClient.new('foo', 'bar', Rev::Api::PRODUCTION_HOST)
6
+ Rev::HttpClient.base_uri.must_equal 'https://www.rev.com/api/v1'
7
+ end
8
+
9
+ it 'must support predefined sandbox host' do
10
+ client = Rev::HttpClient.new('foo', 'bar', Rev::Api::SANDBOX_HOST)
11
+ Rev::HttpClient.base_uri.must_equal 'https://api-sandbox.rev.com/api/v1'
12
+ end
13
+
14
+ it 'must support custom host for development purposes' do
15
+ client = Rev::HttpClient.new('foo', 'bar', 'localhost')
16
+ Rev::HttpClient.base_uri.must_equal 'https://localhost/api/v1'
17
+ end
18
+
19
+ it 'must include authorization and User-Agent headers for any request' do
20
+ host = 'www.example.com'
21
+ stub_request(:any, host)
22
+
23
+ client = Rev::HttpClient.new('foo', 'bar', host)
24
+ client.get('/orders')
25
+
26
+ assert_requested :get, "https://#{host}/api/v1/orders", :headers => {
27
+ 'Authorization' => "Rev foo:bar",
28
+ 'User-Agent' => Rev::HttpClient::USER_AGENT
29
+ }
30
+ end
31
+ end
32
+
@@ -0,0 +1,75 @@
1
+ require_relative '../../spec_helper'
2
+ require 'base64'
3
+
4
+ describe 'POST /inputs' do
5
+ let(:client) { Rev.new('welcome', 'AAAAAu/YjZ3phXU5FsF35yIcgiA=', 'www.revtrunk.com') }
6
+
7
+ it 'must link external file with explicit content-type and file' do
8
+ VCR.insert_cassette 'link_input_with_all_attributes'
9
+
10
+ link = 'http://www.rev.com/content/img/rev/rev_logo_colored_top.png'
11
+ filename = 'sourcedocument.png'
12
+ content_type = 'image/png'
13
+ new_input_location = client.create_input_from_link(link, filename, content_type)
14
+
15
+ new_input_location.must_match 'urn:foxtranslate:inputmedia:'
16
+ expected_body = {
17
+ 'url' => link,
18
+ 'filename' => filename,
19
+ 'content_type' => content_type
20
+ }
21
+ assert_requested(:post, /.*\/inputs/, :times => 1) do |req|
22
+ req.headers['Content-Type'] == 'application/json'
23
+ actual_body = JSON.load req.body
24
+ actual_body.must_equal expected_body
25
+ end
26
+ end
27
+
28
+ it 'must link external file without content-type and filename' do
29
+ VCR.insert_cassette 'link_input'
30
+
31
+ link = 'http://www.rev.com/content/img/rev/rev_logo_colored_top.png'
32
+ new_input_location = client.create_input_from_link(link)
33
+
34
+ new_input_location.must_match 'urn:foxtranslate:inputmedia:'
35
+ expected_body = { 'url' => link }
36
+ assert_requested(:post, /.*\/inputs/, :times => 1) do |req|
37
+ req.headers['Content-Type'] == 'application/json'
38
+ actual_body = JSON.load req.body
39
+ actual_body.must_equal expected_body
40
+ end
41
+ end
42
+
43
+ it 'must upload source file directly' do
44
+ VCR.insert_cassette 'upload_input'
45
+
46
+ filename = './spec/fixtures/sourcedocument.png'
47
+ content_type = 'image/png'
48
+
49
+ new_input_location = client.upload_input(filename, content_type)
50
+
51
+ new_input_location.must_match 'urn:foxtranslate:inputmedia:'
52
+ expected_body = File.read(filename)
53
+ assert_requested(:post, /.*\/inputs/, :times => 1) do |req|
54
+ req.headers['Content-Type'] == content_type
55
+ req.headers['Content-Disposition'] == 'attachment; filename="sourcedocument.png'
56
+ req.body.must_equal expected_body
57
+ end
58
+ end
59
+
60
+ it 'must raise BadRequestError on failure' do
61
+ VCR.insert_cassette 'upload_input_with_invalid_content_type'
62
+
63
+ filename = './spec/fixtures/sourcedocument.png'
64
+ content_type = 'trololo'
65
+
66
+ action = lambda { client.upload_input(filename, content_type) }
67
+ exception = action.must_raise Rev::BadRequestError
68
+ exception.message.must_match '10001: The content-type explicitly specified in the request is not supported for input media'
69
+ exception.code.must_equal Rev::InputRequestErrorCodes::UNSUPPORTED_CONTENT_TYPE
70
+ end
71
+
72
+ after do
73
+ VCR.eject_cassette
74
+ end
75
+ end
@@ -0,0 +1,207 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe 'POST /orders' do
4
+ let(:client) { Rev.new('welcome', 'AAAAAu/YjZ3phXU5FsF35yIcgiA=', 'www.revtrunk.com') }
5
+
6
+ # some defaults we use often
7
+ let(:billing_address) { Rev::BillingAddress.new(
8
+ :street => '123 Pine Lane',
9
+ :street2 => 'Apt D',
10
+ :city => 'MyTown',
11
+ :state => 'MN',
12
+ :zip => '12345',
13
+ :country_alpha2 => 'US'
14
+ )}
15
+
16
+ let(:credit_card) { Rev::CreditCard.new(
17
+ :number => '4111111111111111',
18
+ :expiration_month => 9,
19
+ :expiration_year => 2023,
20
+ :cardholder => 'Joe Smith',
21
+ :billing_address => billing_address
22
+ )}
23
+ let(:cc_payment) { Rev::Payment.new(Rev::Payment::TYPES[:credit_card], credit_card) }
24
+ let(:saved_cc_payment) { Rev::Payment.new(Rev::Payment::TYPES[:credit_card], :saved_id => 1) }
25
+ let(:balance_payment) { Rev::Payment.new(Rev::Payment::TYPES[:balance]) }
26
+ let(:transcription_inputs) {
27
+ inputs = []
28
+ inputs << Rev::Input.new(:external_link => 'http://www.youtube.com/watch?v=UF8uR6Z6KLc')
29
+ inputs << Rev::Input.new(:audio_length => 15, :external_link => 'https://vimeo.com/7976699')
30
+ }
31
+ let(:translation_inputs) {
32
+ inputs = []
33
+ inputs << Rev::Input.new(:word_length => 1000, :uri => 'urn:foxtranslate:inputmedia:SnVwbG9hZHMvMjAxMy0wOS0xNy9lMzk4MWIzNS0wNzM1LTRlMDAtODY1NC1jNWY4ZjE4MzdlMTIvc291cmNlZG9jdW1lbnQucG5n')
34
+ }
35
+ let(:transcription_options) { Rev::TranscriptionOptions.new(transcription_inputs,
36
+ :verbatim => true, :timestamps => true) }
37
+ let(:translation_options) { Rev::TranslationOptions.new(translation_inputs,
38
+ :source_language_code => 'es', :destination_language_code => 'en') }
39
+
40
+ it 'must submit order using Credit Card including all attributes' do
41
+ VCR.insert_cassette 'submit_tc_order_with_cc_and_all_attributes'
42
+
43
+ request = Rev::OrderRequest.new(
44
+ cc_payment,
45
+ :transcription_options => transcription_options,
46
+ :client_ref => 'XB432423',
47
+ :comment => 'Please work quickly',
48
+ :notification => Rev::Notification.new('http://www.example.com', Rev::Notification::LEVELS[:detailed])
49
+ )
50
+
51
+ new_order_num = client.submit_order(request)
52
+
53
+ new_order_num.must_equal 'TC0520815415'
54
+ expected_body = {
55
+ 'payment' => {
56
+ 'type' => 'CreditCard',
57
+ 'credit_card' => {
58
+ 'number' => '4111111111111111',
59
+ 'expiration_month' => 9,
60
+ 'expiration_year' => 2023,
61
+ 'cardholder' => 'Joe Smith',
62
+ 'billing_address' => {
63
+ 'street' => '123 Pine Lane',
64
+ 'street2' => 'Apt D',
65
+ 'city' => 'MyTown',
66
+ 'state' => 'MN',
67
+ 'zip' => '12345',
68
+ 'country_alpha2' => 'US'
69
+ }
70
+ }
71
+ },
72
+ 'transcription_options' => {
73
+ 'inputs'=> [
74
+ { 'external_link' => 'http://www.youtube.com/watch?v=UF8uR6Z6KLc' },
75
+ { 'audio_length' => 15, 'external_link' => 'https://vimeo.com/7976699' }
76
+ ],
77
+ 'verbatim' => true,
78
+ 'timestamps' => true
79
+ },
80
+ 'client_ref' => 'XB432423',
81
+ 'comment' => 'Please work quickly',
82
+ 'notification' => {
83
+ 'url' => 'http://www.example.com',
84
+ 'level' => 'Detailed'
85
+ }
86
+ }
87
+ assert_requested(:post, /.*\/orders/, :times => 1) do |req|
88
+ req.headers['Content-Type'] == 'application/json'
89
+ actual_body = JSON.load req.body
90
+ actual_body.must_equal expected_body
91
+ end
92
+ end
93
+
94
+ it 'must place order using saved credit card' do
95
+ VCR.insert_cassette 'submit_tc_order_with_saved_cc'
96
+
97
+ request = Rev::OrderRequest.new(
98
+ saved_cc_payment,
99
+ :transcription_options => transcription_options
100
+ )
101
+
102
+ new_order_num = client.submit_order(request)
103
+
104
+ new_order_num.must_equal 'TC0370955571'
105
+ expected_body = {
106
+ 'payment' => {
107
+ 'type' => 'CreditCard',
108
+ 'credit_card' => {
109
+ 'saved_id' => 1
110
+ }
111
+ },
112
+ 'transcription_options' => {
113
+ 'inputs' => [
114
+ { 'external_link' => 'http://www.youtube.com/watch?v=UF8uR6Z6KLc' },
115
+ { 'external_link' => 'https://vimeo.com/7976699', 'audio_length'=>15 }
116
+ ],
117
+ 'verbatim'=>true,
118
+ 'timestamps'=>true
119
+ }
120
+ }
121
+ assert_requested(:post, /.*\/orders/, :times => 1) do |req|
122
+ req.headers['Content-Type'] == 'application/json'
123
+ actual_body = JSON.load req.body
124
+ actual_body.must_equal expected_body
125
+ end
126
+ end
127
+
128
+ it 'must place order using account balance' do
129
+ VCR.insert_cassette 'submit_tc_order_with_account_balance'
130
+
131
+ request = Rev::OrderRequest.new(
132
+ balance_payment,
133
+ :transcription_options => transcription_options
134
+ )
135
+
136
+ new_order_num = client.submit_order(request)
137
+
138
+ new_order_num.must_equal 'TC0406615008'
139
+ expected_body = {
140
+ 'payment' => {
141
+ 'type' => 'AccountBalance'
142
+ },
143
+ 'transcription_options' => {
144
+ 'inputs' => [
145
+ { 'external_link' => 'http://www.youtube.com/watch?v=UF8uR6Z6KLc' },
146
+ { 'external_link' => 'https://vimeo.com/7976699', 'audio_length' => 15 }
147
+ ],
148
+ 'verbatim' => true,
149
+ 'timestamps' => true
150
+ }
151
+ }
152
+ assert_requested(:post, /.*\/orders/, :times => 1) do |req|
153
+ req.headers['Content-Type'] == 'application/json'
154
+ actual_body = JSON.load req.body
155
+ actual_body.must_equal expected_body
156
+ end
157
+ end
158
+
159
+ it 'must raise BadRequest error in case of request validation failure' do
160
+ VCR.insert_cassette 'submit_tc_order_with_invalid_request'
161
+
162
+ # example - missing transcription options
163
+ request = Rev::OrderRequest.new(
164
+ balance_payment
165
+ )
166
+
167
+ action = lambda { client.submit_order(request) }
168
+ exception = action.must_raise Rev::BadRequestError
169
+ exception.message.must_match '10004: You must specify either translation or transcription options in an order'
170
+ exception.code.must_equal Rev::OrderRequestErrorCodes::TC_OR_TR_OPTIONS_NOT_SPECIFIED
171
+ end
172
+
173
+ it 'must submit translation order with translation options' do
174
+ VCR.insert_cassette 'submit_tr_order'
175
+
176
+ request = Rev::OrderRequest.new(
177
+ balance_payment,
178
+ :translation_options => translation_options
179
+ )
180
+
181
+ new_order_num = client.submit_order(request)
182
+
183
+ new_order_num.must_equal 'TR0235803277'
184
+ expected_body = {
185
+ 'payment' => {
186
+ 'type' => 'AccountBalance'
187
+ },
188
+ 'translation_options' => {
189
+ 'inputs'=> [
190
+ { 'word_length' => 1000, 'uri' => 'urn:foxtranslate:inputmedia:SnVwbG9hZHMvMjAxMy0wOS0xNy9lMzk4MWIzNS0wNzM1LTRlMDAtODY1NC1jNWY4ZjE4MzdlMTIvc291cmNlZG9jdW1lbnQucG5n' },
191
+ ],
192
+ 'source_language_code' => 'es',
193
+ 'destination_language_code' => 'en'
194
+ }
195
+ }
196
+ assert_requested(:post, /.*\/orders/, :times => 1) do |req|
197
+ req.headers['Content-Type'] == 'application/json'
198
+ actual_body = JSON.load req.body
199
+ actual_body.must_equal expected_body
200
+ end
201
+ end
202
+
203
+ after do
204
+ VCR.eject_cassette
205
+ end
206
+
207
+ end
@@ -0,0 +1,31 @@
1
+ require_relative '../lib/rev-api'
2
+
3
+ #dependencies
4
+ require 'minitest/autorun'
5
+ require 'webmock/minitest'
6
+ require 'vcr'
7
+ require 'turn'
8
+
9
+ module MiniTest
10
+ class Spec
11
+ class << self
12
+ def xit(desc='anonymous')
13
+ it(name) { skip 'DISABLED' }
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ Turn.config do |c|
20
+ c.format = :outline
21
+ c.trace = false
22
+ c.natural = true
23
+ end
24
+
25
+
26
+ VCR.configure do |c|
27
+ c.cassette_library_dir = 'spec/fixtures/api_cassettes'
28
+ c.default_cassette_options = { :record => :once, :allow_unused_http_interactions => false, :match_requests_on => [:method, :uri, :headers] }
29
+ c.hook_into :webmock
30
+ c.ignore_hosts 'www.example.com' # used to stub requests manually, see http_client_spec
31
+ end