docraptor 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 520005260c4eb699f6ac0c8b223def5e9624e57d
4
+ data.tar.gz: 6a976eea99f53053665f0f4995b690e606c3ecc0
5
+ SHA512:
6
+ metadata.gz: eaa8cd06bd4ef88d656e7342941684c38513edeb6c33851aec486b18815c829edd436df1fea2d35adf491cd4a5afb51e04418bc10dbc6caea9b0c990a5c5a75a
7
+ data.tar.gz: 109acdcb676b246f7124371d8a5b4dcf1bb5bcf2dc2d223862a7135951c546f24ee49e150f9e564f6ab66f11ef216f3ba8c157fd3404e0166bbde90d6d785f9d
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler/setup'
2
+ require 'bundler/gem_tasks'
data/docraptor.gemspec ADDED
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "docraptor/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "docraptor"
7
+ s.version = DocRaptor::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Elijah Miller", "Matthew Gordon"]
10
+ s.email = ["elijah@expectedbehavior.com", "matt@expectedbehavior.com"]
11
+ s.homepage = "https://docraptor.com"
12
+ s.summary = %q{A wrapper for the DocRaptor HTML to PDF/XLS service.}
13
+ s.description = %q{A native client library for the DocRaptor HTML to PDF/XLS service.}
14
+ s.license = "MIT"
15
+
16
+ s.add_runtime_dependency 'typhoeus', '~> 0.2', '>= 0.2.1'
17
+ s.add_runtime_dependency 'json', '~> 1.4', '>= 1.4.6'
18
+
19
+ s.add_development_dependency 'rake', '~> 10.4', '>= 10.4.2'
20
+ s.add_development_dependency 'rspec', '~> 3.2', '>= 3.2.0'
21
+ s.add_development_dependency 'vcr', '~> 2.9', '>= 2.9.3'
22
+ s.add_development_dependency 'webmock', '~> 1.6', '>= 1.6.2'
23
+ s.add_development_dependency 'autotest', '~> 4.4', '>= 4.4.6'
24
+ s.add_development_dependency 'autotest-rails-pure', '~> 4.1', '>= 4.1.2'
25
+ s.add_development_dependency 'autotest-growl', '~> 0.2', '>= 0.2.16'
26
+ s.add_development_dependency 'autotest-fsevent', '~> 0.2', '>= 0.2.10'
27
+
28
+ s.files = `find *`.split("\n").uniq.sort.select{|f| !f.empty? }
29
+ s.test_files = `find spec/*`.split("\n")
30
+ s.executables = []
31
+ s.require_paths = ["lib"]
32
+ end
data/lib/docraptor.rb ADDED
@@ -0,0 +1,33 @@
1
+ # Common files
2
+ require 'docraptor/api_client'
3
+ require 'docraptor/api_error'
4
+ require 'docraptor/version'
5
+ require 'docraptor/configuration'
6
+
7
+ # Models
8
+ require 'docraptor/models/base_object'
9
+ require 'docraptor/models/doc'
10
+ require 'docraptor/models/prince_options'
11
+ require 'docraptor/models/async_doc'
12
+ require 'docraptor/models/async_doc_status'
13
+
14
+ # APIs
15
+ require 'docraptor/api/client_api'
16
+
17
+ module DocRaptor
18
+ class << self
19
+ # Configure sdk using block.
20
+ # DocRaptor.configure do |config|
21
+ # config.username = "xxx"
22
+ # config.password = "xxx"
23
+ # end
24
+ # If no block given, return the configuration singleton instance.
25
+ def configure
26
+ if block_given?
27
+ yield Configuration.instance
28
+ else
29
+ Configuration.instance
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,219 @@
1
+ require "uri"
2
+
3
+ module DocRaptor
4
+ class ClientApi
5
+ attr_accessor :api_client
6
+
7
+ def initialize(api_client = nil)
8
+ @api_client = api_client || Configuration.api_client
9
+ end
10
+
11
+ #
12
+ # Creates a document asynchronously.\nYou must use a callback url or the the returned status id and the status api to find out when it completes. Then use the download api to get the document.
13
+ # @param doc The document to be created.
14
+ # @param [Hash] opts the optional parameters
15
+ # @return [AsyncDoc]
16
+ def async_docs_post(doc, opts = {})
17
+ if Configuration.debugging
18
+ Configuration.logger.debug "Calling API: ClientApi#async_docs_post ..."
19
+ end
20
+
21
+ # verify the required parameter 'doc' is set
22
+ fail "Missing the required parameter 'doc' when calling async_docs_post" if doc.nil?
23
+
24
+ # resource path
25
+ path = "/async_docs".sub('{format}','json')
26
+
27
+ # query parameters
28
+ query_params = {}
29
+
30
+ # header parameters
31
+ header_params = {}
32
+
33
+ # HTTP header 'Accept' (if needed)
34
+ _header_accept = ['application/json', 'application/xml', 'application/pdf', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
35
+ _header_accept_result = @api_client.select_header_accept(_header_accept) and header_params['Accept'] = _header_accept_result
36
+
37
+ # HTTP header 'Content-Type'
38
+ _header_content_type = []
39
+ header_params['Content-Type'] = @api_client.select_header_content_type(_header_content_type)
40
+
41
+ # form parameters
42
+ form_params = {}
43
+
44
+ # http body (model)
45
+ post_body = @api_client.object_to_http_body(doc)
46
+
47
+
48
+ auth_names = ['basicAuth']
49
+ result = @api_client.call_api(:POST, path,
50
+ :header_params => header_params,
51
+ :query_params => query_params,
52
+ :form_params => form_params,
53
+ :body => post_body,
54
+ :auth_names => auth_names,
55
+ :return_type => 'AsyncDoc')
56
+ if Configuration.debugging
57
+ Configuration.logger.debug "API called: ClientApi#async_docs_post. Result: #{result.inspect}"
58
+ end
59
+ return result
60
+ end
61
+
62
+ #
63
+ # Creates a document synchronously.
64
+ # @param doc The document to be created.
65
+ # @param [Hash] opts the optional parameters
66
+ # @return [File]
67
+ def docs_post(doc, opts = {})
68
+ if Configuration.debugging
69
+ Configuration.logger.debug "Calling API: ClientApi#docs_post ..."
70
+ end
71
+
72
+ # verify the required parameter 'doc' is set
73
+ fail "Missing the required parameter 'doc' when calling docs_post" if doc.nil?
74
+
75
+ # resource path
76
+ path = "/docs".sub('{format}','json')
77
+
78
+ # query parameters
79
+ query_params = {}
80
+
81
+ # header parameters
82
+ header_params = {}
83
+
84
+ # HTTP header 'Accept' (if needed)
85
+ _header_accept = ['application/json', 'application/xml', 'application/pdf', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
86
+ _header_accept_result = @api_client.select_header_accept(_header_accept) and header_params['Accept'] = _header_accept_result
87
+
88
+ # HTTP header 'Content-Type'
89
+ _header_content_type = []
90
+ header_params['Content-Type'] = @api_client.select_header_content_type(_header_content_type)
91
+
92
+ # form parameters
93
+ form_params = {}
94
+
95
+ # http body (model)
96
+ post_body = @api_client.object_to_http_body(doc)
97
+
98
+
99
+ auth_names = ['basicAuth']
100
+ result = @api_client.call_api(:POST, path,
101
+ :header_params => header_params,
102
+ :query_params => query_params,
103
+ :form_params => form_params,
104
+ :body => post_body,
105
+ :auth_names => auth_names,
106
+ :return_type => 'File')
107
+ if Configuration.debugging
108
+ Configuration.logger.debug "API called: ClientApi#docs_post. Result: #{result.inspect}"
109
+ end
110
+ return result
111
+ end
112
+
113
+ #
114
+ # Downloads a document.
115
+ # @param id The download_id returned from status request or a callback.
116
+ # @param [Hash] opts the optional parameters
117
+ # @return [File]
118
+ def download_id_get(id, opts = {})
119
+ if Configuration.debugging
120
+ Configuration.logger.debug "Calling API: ClientApi#download_id_get ..."
121
+ end
122
+
123
+ # verify the required parameter 'id' is set
124
+ fail "Missing the required parameter 'id' when calling download_id_get" if id.nil?
125
+
126
+ # resource path
127
+ path = "/download/{id}".sub('{format}','json').sub('{' + 'id' + '}', id.to_s)
128
+
129
+ # query parameters
130
+ query_params = {}
131
+
132
+ # header parameters
133
+ header_params = {}
134
+
135
+ # HTTP header 'Accept' (if needed)
136
+ _header_accept = ['application/json', 'application/xml', 'application/pdf', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
137
+ _header_accept_result = @api_client.select_header_accept(_header_accept) and header_params['Accept'] = _header_accept_result
138
+
139
+ # HTTP header 'Content-Type'
140
+ _header_content_type = []
141
+ header_params['Content-Type'] = @api_client.select_header_content_type(_header_content_type)
142
+
143
+ # form parameters
144
+ form_params = {}
145
+
146
+ # http body (model)
147
+ post_body = nil
148
+
149
+
150
+ auth_names = ['basicAuth']
151
+ result = @api_client.call_api(:GET, path,
152
+ :header_params => header_params,
153
+ :query_params => query_params,
154
+ :form_params => form_params,
155
+ :body => post_body,
156
+ :auth_names => auth_names,
157
+ :return_type => 'File')
158
+ if Configuration.debugging
159
+ Configuration.logger.debug "API called: ClientApi#download_id_get. Result: #{result.inspect}"
160
+ end
161
+ return result
162
+ end
163
+
164
+ #
165
+ # Check on the status of an asynchronously created document.
166
+ # @param id The status_id returned when creating an asynchronous document.
167
+ # @param [Hash] opts the optional parameters
168
+ # @return [AsyncDocStatus]
169
+ def status_id_get(id, opts = {})
170
+ if Configuration.debugging
171
+ Configuration.logger.debug "Calling API: ClientApi#status_id_get ..."
172
+ end
173
+
174
+ # verify the required parameter 'id' is set
175
+ fail "Missing the required parameter 'id' when calling status_id_get" if id.nil?
176
+
177
+ # resource path
178
+ path = "/status/{id}".sub('{format}','json').sub('{' + 'id' + '}', id.to_s)
179
+
180
+ # query parameters
181
+ query_params = {}
182
+
183
+ # header parameters
184
+ header_params = {}
185
+
186
+ # HTTP header 'Accept' (if needed)
187
+ _header_accept = ['application/json', 'application/xml', 'application/pdf', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
188
+ _header_accept_result = @api_client.select_header_accept(_header_accept) and header_params['Accept'] = _header_accept_result
189
+
190
+ # HTTP header 'Content-Type'
191
+ _header_content_type = []
192
+ header_params['Content-Type'] = @api_client.select_header_content_type(_header_content_type)
193
+
194
+ # form parameters
195
+ form_params = {}
196
+
197
+ # http body (model)
198
+ post_body = nil
199
+
200
+
201
+ auth_names = ['basicAuth']
202
+ result = @api_client.call_api(:GET, path,
203
+ :header_params => header_params,
204
+ :query_params => query_params,
205
+ :form_params => form_params,
206
+ :body => post_body,
207
+ :auth_names => auth_names,
208
+ :return_type => 'AsyncDocStatus')
209
+ if Configuration.debugging
210
+ Configuration.logger.debug "API called: ClientApi#status_id_get. Result: #{result.inspect}"
211
+ end
212
+ return result
213
+ end
214
+ end
215
+ end
216
+
217
+
218
+
219
+
@@ -0,0 +1,273 @@
1
+ require 'date'
2
+ require 'json'
3
+ require 'logger'
4
+ require 'tempfile'
5
+ require 'typhoeus'
6
+ require 'uri'
7
+
8
+ module DocRaptor
9
+ class ApiClient
10
+
11
+ attr_accessor :host
12
+
13
+ # Defines the headers to be used in HTTP requests of all API calls by default.
14
+ #
15
+ # @return [Hash]
16
+ attr_accessor :default_headers
17
+
18
+ # Stores the HTTP response from the last API call using this API client.
19
+ attr_accessor :last_response
20
+
21
+ def initialize(host = nil)
22
+ @host = host || Configuration.base_url
23
+ @format = 'json'
24
+ @user_agent = "ruby-swagger-#{VERSION}"
25
+ @default_headers = {
26
+ 'Content-Type' => "application/#{@format.downcase}",
27
+ 'User-Agent' => @user_agent
28
+ }
29
+ end
30
+
31
+ def call_api(http_method, path, opts = {})
32
+ request = build_request(http_method, path, opts)
33
+ response = request.run
34
+
35
+ # record as last response
36
+ @last_response = response
37
+
38
+ if Configuration.debugging
39
+ Configuration.logger.debug "HTTP response body ~BEGIN~\n#{response.body}\n~END~\n"
40
+ end
41
+
42
+ unless response.success?
43
+ fail ApiError.new(:code => response.code,
44
+ :response_headers => response.headers,
45
+ :response_body => response.body),
46
+ response.status_message
47
+ end
48
+
49
+ if opts[:return_type]
50
+ deserialize(response, opts[:return_type])
51
+ else
52
+ nil
53
+ end
54
+ end
55
+
56
+ def build_request(http_method, path, opts = {})
57
+ url = build_request_url(path)
58
+ http_method = http_method.to_sym.downcase
59
+
60
+ header_params = @default_headers.merge(opts[:header_params] || {})
61
+ query_params = opts[:query_params] || {}
62
+ form_params = opts[:form_params] || {}
63
+
64
+
65
+ update_params_for_auth! header_params, query_params, opts[:auth_names]
66
+
67
+
68
+ req_opts = {
69
+ :method => http_method,
70
+ :headers => header_params,
71
+ :params => query_params,
72
+ :ssl_verifypeer => Configuration.verify_ssl,
73
+ :sslcert => Configuration.cert_file,
74
+ :sslkey => Configuration.key_file,
75
+ :cainfo => Configuration.ssl_ca_cert,
76
+ :verbose => Configuration.debugging
77
+ }
78
+
79
+ if [:post, :patch, :put, :delete].include?(http_method)
80
+ req_body = build_request_body(header_params, form_params, opts[:body])
81
+ req_opts.update :body => req_body
82
+ if Configuration.debugging
83
+ Configuration.logger.debug "HTTP request body param ~BEGIN~\n#{req_body}\n~END~\n"
84
+ end
85
+ end
86
+
87
+ Typhoeus::Request.new(url, req_opts)
88
+ end
89
+
90
+ # Deserialize the response to the given return type.
91
+ #
92
+ # @param [String] return_type some examples: "User", "Array[User]", "Hash[String,Integer]"
93
+ def deserialize(response, return_type)
94
+ body = response.body
95
+ return nil if body.nil? || body.empty?
96
+
97
+ # handle file downloading - save response body into a tmp file and return the File instance
98
+ return download_file(response) if return_type == 'File'
99
+
100
+ # ensuring a default content type
101
+ content_type = response.headers['Content-Type'] || 'application/json'
102
+
103
+ unless content_type.start_with?('application/json')
104
+ fail "Content-Type is not supported: #{content_type}"
105
+ end
106
+
107
+ begin
108
+ data = JSON.parse("[#{body}]", :symbolize_names => true)[0]
109
+ rescue JSON::ParserError => e
110
+ if %w(String Date DateTime).include?(return_type)
111
+ data = body
112
+ else
113
+ raise e
114
+ end
115
+ end
116
+
117
+ convert_to_type data, return_type
118
+ end
119
+
120
+ # Convert data to the given return type.
121
+ def convert_to_type(data, return_type)
122
+ return nil if data.nil?
123
+ case return_type
124
+ when 'String'
125
+ data.to_s
126
+ when 'Integer'
127
+ data.to_i
128
+ when 'Float'
129
+ data.to_f
130
+ when 'BOOLEAN'
131
+ data == true
132
+ when 'DateTime'
133
+ # parse date time (expecting ISO 8601 format)
134
+ DateTime.parse data
135
+ when 'Date'
136
+ # parse date time (expecting ISO 8601 format)
137
+ Date.parse data
138
+ when 'Object'
139
+ # generic object, return directly
140
+ data
141
+ when /\AArray<(.+)>\z/
142
+ # e.g. Array<Pet>
143
+ sub_type = $1
144
+ data.map {|item| convert_to_type(item, sub_type) }
145
+ when /\AHash\<String, (.+)\>\z/
146
+ # e.g. Hash<String, Integer>
147
+ sub_type = $1
148
+ {}.tap do |hash|
149
+ data.each {|k, v| hash[k] = convert_to_type(v, sub_type) }
150
+ end
151
+ else
152
+ # models, e.g. Pet
153
+ DocRaptor.const_get(return_type).new.tap do |model|
154
+ model.build_from_hash data
155
+ end
156
+ end
157
+ end
158
+
159
+ # Save response body into a file in (the defined) temporary folder, using the filename
160
+ # from the "Content-Disposition" header if provided, otherwise a random filename.
161
+ #
162
+ # @see Configuration#temp_folder_path
163
+ # @return [File] the file downloaded
164
+ def download_file(response)
165
+ tmp_file = Tempfile.new '', Configuration.temp_folder_path
166
+ content_disposition = response.headers['Content-Disposition']
167
+ if content_disposition
168
+ filename = content_disposition[/filename=['"]?([^'"\s]+)['"]?/, 1]
169
+ path = File.join File.dirname(tmp_file), filename
170
+ else
171
+ path = tmp_file.path
172
+ end
173
+ # close and delete temp file
174
+ tmp_file.close!
175
+
176
+ File.open(path, 'w') { |file| file.write(response.body) }
177
+ Configuration.logger.info "File written to #{path}. Please move the file to a proper "\
178
+ "folder for further processing and delete the temp afterwards"
179
+ File.new(path)
180
+ end
181
+
182
+ def build_request_url(path)
183
+ # Add leading and trailing slashes to path
184
+ path = "/#{path}".gsub(/\/+/, '/')
185
+ URI.encode(host + path)
186
+ end
187
+
188
+ def build_request_body(header_params, form_params, body)
189
+ # http form
190
+ if header_params['Content-Type'] == 'application/x-www-form-urlencoded' ||
191
+ header_params['Content-Type'] == 'multipart/form-data'
192
+ data = form_params.dup
193
+ data.each do |key, value|
194
+ data[key] = value.to_s if value && !value.is_a?(File)
195
+ end
196
+ elsif body
197
+ data = body.is_a?(String) ? body : body.to_json
198
+ else
199
+ data = nil
200
+ end
201
+ data
202
+ end
203
+
204
+ # Update hearder and query params based on authentication settings.
205
+ def update_params_for_auth!(header_params, query_params, auth_names)
206
+ Array(auth_names).each do |auth_name|
207
+ auth_setting = Configuration.auth_settings[auth_name]
208
+ next unless auth_setting
209
+ case auth_setting[:in]
210
+ when 'header' then header_params[auth_setting[:key]] = auth_setting[:value]
211
+ when 'query' then query_params[auth_setting[:key]] = auth_setting[:value]
212
+ else fail ArgumentError, 'Authentication token must be in `query` of `header`'
213
+ end
214
+ end
215
+ end
216
+
217
+ def user_agent=(user_agent)
218
+ @user_agent = user_agent
219
+ @default_headers['User-Agent'] = @user_agent
220
+ end
221
+
222
+ # Return Accept header based on an array of accepts provided.
223
+ # @param [Array] accepts array for Accept
224
+ # @return [String] the Accept header (e.g. application/json)
225
+ def select_header_accept(accepts)
226
+ if accepts.empty?
227
+ return
228
+ elsif accepts.any?{ |s| s.casecmp('application/json') == 0 }
229
+ 'application/json' # look for json data by default
230
+ else
231
+ accepts.join(',')
232
+ end
233
+ end
234
+
235
+ # Return Content-Type header based on an array of content types provided.
236
+ # @param [Array] content_types array for Content-Type
237
+ # @return [String] the Content-Type header (e.g. application/json)
238
+ def select_header_content_type(content_types)
239
+ if content_types.empty?
240
+ 'application/json' # use application/json by default
241
+ elsif content_types.any?{ |s| s.casecmp('application/json')==0 }
242
+ 'application/json' # use application/json if it's included
243
+ else
244
+ content_types[0] # otherwise, use the first one
245
+ end
246
+ end
247
+
248
+ # Convert object (array, hash, object, etc) to JSON string.
249
+ # @param [Object] model object to be converted into JSON string
250
+ # @return [String] JSON string representation of the object
251
+ def object_to_http_body(model)
252
+ return if model.nil?
253
+ _body = nil
254
+ if model.is_a?(Array)
255
+ _body = model.map{|m| object_to_hash(m) }
256
+ else
257
+ _body = object_to_hash(model)
258
+ end
259
+ _body.to_json
260
+ end
261
+
262
+ # Convert object(non-array) to hash.
263
+ # @param [Object] obj object to be converted into JSON string
264
+ # @return [String] JSON string representation of the object
265
+ def object_to_hash(obj)
266
+ if obj.respond_to?(:to_hash)
267
+ obj.to_hash
268
+ else
269
+ obj
270
+ end
271
+ end
272
+ end
273
+ end