adobe_pdfservices_ruby 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rubocop.yml +13 -0
- data/.vscode/extensions.json +7 -0
- data/.vscode/settings.json +13 -0
- data/CHANGELOG.md +14 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +79 -0
- data/LICENSE.txt +21 -0
- data/README.md +88 -0
- data/Rakefile +16 -0
- data/adobe_pdfservices_ruby.gemspec +38 -0
- data/lib/adobe_pdfservices_ruby.rb +37 -0
- data/lib/pdfservices/api.rb +72 -0
- data/lib/pdfservices/asset.rb +74 -0
- data/lib/pdfservices/client.rb +69 -0
- data/lib/pdfservices/errors.rb +16 -0
- data/lib/pdfservices/operations/base.rb +81 -0
- data/lib/pdfservices/operations/document_generation/external.rb +99 -0
- data/lib/pdfservices/operations/document_generation/internal.rb +75 -0
- data/lib/pdfservices/operations/document_generation.rb +30 -0
- data/lib/pdfservices/operations/extract_pdf.rb +83 -0
- data/lib/pdfservices/operations/html_to_pdf/external.rb +96 -0
- data/lib/pdfservices/operations/html_to_pdf/internal.rb +69 -0
- data/lib/pdfservices/operations/html_to_pdf.rb +30 -0
- data/lib/pdfservices/operations/internal_external_operation.rb +40 -0
- data/lib/pdfservices/operations/ocr/external.rb +109 -0
- data/lib/pdfservices/operations/ocr/internal.rb +48 -0
- data/lib/pdfservices/operations/ocr.rb +28 -0
- data/lib/pdfservices/version.rb +5 -0
- metadata +120 -0
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PdfServices
|
4
|
+
module Base
|
5
|
+
class Operation
|
6
|
+
BASE_ENDPOINT = 'https://pdf-services-ue1.adobe.io/operation/'
|
7
|
+
ASSETS_ENDPOINT = 'https://pdf-services-ue1.adobe.io/assets/'
|
8
|
+
STATUS = {
|
9
|
+
in_progress: 'in progress',
|
10
|
+
done: 'done',
|
11
|
+
failed: 'failed'
|
12
|
+
}.freeze
|
13
|
+
|
14
|
+
def initialize(api)
|
15
|
+
@api = api
|
16
|
+
end
|
17
|
+
|
18
|
+
def upload_asset(asset)
|
19
|
+
asset = File.open(asset, 'rb') if asset.is_a?(String)
|
20
|
+
Asset.new(@api).upload(asset)
|
21
|
+
end
|
22
|
+
|
23
|
+
def poll_document_result(url, original_asset, &block)
|
24
|
+
response = @api.get(url)
|
25
|
+
json_response = JSON.parse(response.body.to_s)
|
26
|
+
handle_polling_result(url, json_response, original_asset, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def handle_polling_result(url, json_response, original_asset, &block)
|
32
|
+
case json_response['status']
|
33
|
+
when STATUS[:in_progress]
|
34
|
+
handle_in_progress(url, json_response, original_asset, &block)
|
35
|
+
when STATUS[:done]
|
36
|
+
handle_done(json_response, original_asset, &block)
|
37
|
+
when STATUS[:failed]
|
38
|
+
handle_failed(json_response, original_asset, &block)
|
39
|
+
else
|
40
|
+
handle_unexpected_status(json_response, original_asset, &block)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def handle_in_progress(url, json_response, original_asset, &block)
|
45
|
+
block.call(json_response['status'], nil) if block_given?
|
46
|
+
sleep(1) # Consider a more sophisticated retry strategy
|
47
|
+
poll_document_result(url, original_asset, &block)
|
48
|
+
end
|
49
|
+
|
50
|
+
def handle_done(json_response, original_asset, &block)
|
51
|
+
return block.call(json_response['status'], handle_polling_done(json_response, original_asset)) if block_given?
|
52
|
+
|
53
|
+
handle_polling_done(json_response, original_asset)
|
54
|
+
end
|
55
|
+
|
56
|
+
def handle_failed(json_response, original_asset, &block)
|
57
|
+
block.call(json_response['status'], nil) if block_given?
|
58
|
+
handle_polling_failed(json_response, original_asset)
|
59
|
+
end
|
60
|
+
|
61
|
+
def handle_unexpected_status(json_response, original_asset, &block)
|
62
|
+
block.call(json_response['status'], nil) if block_given?
|
63
|
+
handle_polling_unexpected_status(json_response, original_asset)
|
64
|
+
end
|
65
|
+
|
66
|
+
def handle_polling_done(_json_response, original_asset)
|
67
|
+
original_asset.delete
|
68
|
+
end
|
69
|
+
|
70
|
+
def handle_polling_failed(json_response, original_asset)
|
71
|
+
original_asset.delete
|
72
|
+
raise PollingError, "Document extraction failed: #{json_response['error']}"
|
73
|
+
end
|
74
|
+
|
75
|
+
def handle_polling_unexpected_status(json_response, original_asset)
|
76
|
+
original_asset.delete
|
77
|
+
raise PollingError, "Unexpected status: #{json_response['status']}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PdfServices
|
4
|
+
module DocumentGeneration
|
5
|
+
class External < Operation
|
6
|
+
EXTERNAL_OPTIONS = %i[input output params download_from_external].freeze
|
7
|
+
INPUT_KEYS = %i[uri storage].freeze
|
8
|
+
OUTPUT_KEYS = %i[uri storage].freeze
|
9
|
+
PARAMS_KEYS = %i[output_format json_data_for_merge fragments].freeze
|
10
|
+
STORAGE_OPTIONS = %i[S3 SHAREPOINT DROPBOX BLOB].freeze
|
11
|
+
|
12
|
+
def initialize(api)
|
13
|
+
super
|
14
|
+
@download_from_external = false
|
15
|
+
@download_uri = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def execute(template_path, options = {})
|
19
|
+
validate_options(options)
|
20
|
+
asset = upload_asset(template_path)
|
21
|
+
|
22
|
+
@download_from_external = options[:download_from_external] || false
|
23
|
+
|
24
|
+
@download_uri = options[:output][:uri] if @download_from_external
|
25
|
+
|
26
|
+
response = @api.post(OPERATION_ENDPOINT,
|
27
|
+
body: request_body(asset.id, options),
|
28
|
+
headers: request_headers)
|
29
|
+
handle_response(response, asset.id)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def request_body(asset_id, options)
|
35
|
+
{
|
36
|
+
assetID: asset_id,
|
37
|
+
input: camelize_keys(options[:input]),
|
38
|
+
output: camelize_keys(options[:output]),
|
39
|
+
params: camelize_keys(options[:params])
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
def handle_polling_done(response, original_asset)
|
44
|
+
file = @api.get(@download_uri).body if @download_from_external
|
45
|
+
super
|
46
|
+
file || true
|
47
|
+
end
|
48
|
+
|
49
|
+
def validate_options(options)
|
50
|
+
raise ArgumentError, 'Options must be a hash' unless options.is_a?(Hash)
|
51
|
+
|
52
|
+
validate_required_keys(options)
|
53
|
+
validate_input_options(options[:input])
|
54
|
+
validate_output_options(options[:output])
|
55
|
+
validate_params_options(options[:params])
|
56
|
+
end
|
57
|
+
|
58
|
+
def validate_required_keys(options)
|
59
|
+
required_keys = EXTERNAL_OPTIONS - %i[download_from_external]
|
60
|
+
required_keys.each do |key|
|
61
|
+
raise ArgumentError, "Missing required key: #{key}" unless options.key?(key)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def validate_input_options(input_options)
|
66
|
+
raise ArgumentError, 'Input options must be a hash' unless input_options.is_a?(Hash)
|
67
|
+
|
68
|
+
required_input_keys = INPUT_KEYS
|
69
|
+
required_input_keys.each do |key|
|
70
|
+
raise ArgumentError, "Missing required input key: #{key}" unless input_options.key?(key)
|
71
|
+
end
|
72
|
+
validate_storage_options(input_options[:storage])
|
73
|
+
end
|
74
|
+
|
75
|
+
def validate_output_options(output_options)
|
76
|
+
raise ArgumentError, 'Output options must be a hash' unless output_options.is_a?(Hash)
|
77
|
+
|
78
|
+
required_output_keys = OUTPUT_KEYS - %i[uri]
|
79
|
+
required_output_keys.each do |key|
|
80
|
+
raise ArgumentError, "Missing required output key: #{key}" unless output_options.key?(key)
|
81
|
+
end
|
82
|
+
validate_storage_options(output_options[:storage])
|
83
|
+
end
|
84
|
+
|
85
|
+
def validate_storage_option(storage_option)
|
86
|
+
raise ArgumentError, "Invalid storage option: #{storage_option}" unless STORAGE_OPTIONS.include?(storage_option)
|
87
|
+
end
|
88
|
+
|
89
|
+
def validate_params_options(params_options)
|
90
|
+
raise ArgumentError, 'Params options must be a hash' unless params_options.is_a?(Hash)
|
91
|
+
|
92
|
+
required_params_keys = PARAMS_KEYS - %i[output_format fragments]
|
93
|
+
required_params_keys.each do |key|
|
94
|
+
raise ArgumentError, "Missing required params key: #{key}" unless params_options.key?(key)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PdfServices
|
4
|
+
module DocumentGeneration
|
5
|
+
class Internal < Operation
|
6
|
+
INTERNAL_OPTIONS = %i[output_format json_data_for_merge fragments notifiers].freeze
|
7
|
+
|
8
|
+
def execute(template_path, options = {})
|
9
|
+
validate_options(options)
|
10
|
+
asset = upload_asset(template_path)
|
11
|
+
|
12
|
+
response = @api.post(OPERATION_ENDPOINT,
|
13
|
+
body: request_body(asset.id, options),
|
14
|
+
headers: request_headers)
|
15
|
+
|
16
|
+
handle_response(response, asset.id)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def request_body(asset_id, options)
|
22
|
+
body = {
|
23
|
+
assetID: asset_id,
|
24
|
+
outputFormat: options.fetch(:output_format, 'pdf'),
|
25
|
+
jsonDataForMerge: options.fetch(:json_data_for_merge, {})
|
26
|
+
}
|
27
|
+
body[:fragments] = options[:fragments] if options[:fragments]
|
28
|
+
body[:notifiers] = options[:notifiers] if options[:notifiers]
|
29
|
+
body
|
30
|
+
end
|
31
|
+
|
32
|
+
def validate_options(options)
|
33
|
+
raise ArgumentError, 'Invalid options' unless options.is_a?(Hash)
|
34
|
+
|
35
|
+
validate_output_format(options[:output_format])
|
36
|
+
validate_fragments(options[:fragments])
|
37
|
+
validate_notifiers(options[:notifiers])
|
38
|
+
validate_keys(options)
|
39
|
+
validate_json_data_for_merge(options[:json_data_for_merge])
|
40
|
+
end
|
41
|
+
|
42
|
+
def validate_output_format(output_format)
|
43
|
+
raise ArgumentError, "Invalid output format: #{output_format}" unless %w[pdf docx].include?(output_format)
|
44
|
+
end
|
45
|
+
|
46
|
+
def validate_fragments(fragments)
|
47
|
+
raise ArgumentError, 'Invalid fragments, must be a hash' unless fragments.is_a?(Hash) || fragments.nil?
|
48
|
+
end
|
49
|
+
|
50
|
+
def validate_notifiers(notifiers)
|
51
|
+
return if notifiers.is_a?(Array) || notifiers.nil?
|
52
|
+
|
53
|
+
raise ArgumentError,
|
54
|
+
'Invalid notifiers, must be an array of hashes'
|
55
|
+
end
|
56
|
+
|
57
|
+
def validate_json_data_for_merge(json_data_for_merge)
|
58
|
+
raise ArgumentError, 'Invalid json_data_for_merge, must be a hash' unless json_data_for_merge.is_a?(Hash)
|
59
|
+
end
|
60
|
+
|
61
|
+
def validate_keys(options)
|
62
|
+
valid_keys = INTERNAL_OPTIONS
|
63
|
+
invalid_keys = options.keys - valid_keys
|
64
|
+
raise ArgumentError, "Invalid options: #{invalid_keys}" unless invalid_keys.empty?
|
65
|
+
end
|
66
|
+
|
67
|
+
def handle_polling_done(json_response, original_asset)
|
68
|
+
asset_id = json_response['asset']['assetID']
|
69
|
+
file = Asset.new(@api).download(asset_id).body
|
70
|
+
super
|
71
|
+
file
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PdfServices
|
4
|
+
module DocumentGeneration
|
5
|
+
class Operation < InternalExternalOperation::Operation
|
6
|
+
OPERATION_ENDPOINT = "#{BASE_ENDPOINT}documentgeneration".freeze
|
7
|
+
|
8
|
+
def request_headers
|
9
|
+
{ 'Content-Type' => 'application/json' }
|
10
|
+
end
|
11
|
+
|
12
|
+
def handle_response(response, asset_id)
|
13
|
+
unless response.status == 201
|
14
|
+
raise "Unexpected response status from document merge endpoint: #{response.status}, asset_id: #{asset_id}"
|
15
|
+
end
|
16
|
+
|
17
|
+
document_url = response.headers['location']
|
18
|
+
poll_document_result document_url, asset_id
|
19
|
+
end
|
20
|
+
|
21
|
+
def internal_class
|
22
|
+
Internal
|
23
|
+
end
|
24
|
+
|
25
|
+
def external_class
|
26
|
+
External
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PdfServices
|
4
|
+
module ExtractPdf
|
5
|
+
class Operation < Base::Operation
|
6
|
+
OPERATION_ENDPOINT = "#{BASE_ENDPOINT}extractpdf".freeze
|
7
|
+
VALID_EXTRACT_ELEMENTS = %w[tables text].freeze
|
8
|
+
TABLE_OUTPUT_FORMATS = %w[csv xlsx].freeze
|
9
|
+
RENDITIONS_EXTRACTS = %w[tables figures].freeze
|
10
|
+
|
11
|
+
def execute(source_pdf_path = nil, options = {})
|
12
|
+
validate_options(options)
|
13
|
+
@download_zip = options.delete(:download_zip) || false
|
14
|
+
asset = upload_asset(source_pdf_path)
|
15
|
+
|
16
|
+
response = @api.post(OPERATION_ENDPOINT,
|
17
|
+
body: extract_pdf_request_body(asset.id, options),
|
18
|
+
headers: extract_pdf_request_headers)
|
19
|
+
handle_extract_pdf_response(response, asset)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def extract_pdf_request_body(asset_id, options)
|
25
|
+
{
|
26
|
+
assetID: asset_id,
|
27
|
+
includeStyling: options.fetch(:include_styling, false),
|
28
|
+
getCharBounds: options.fetch(:get_char_bounds, false),
|
29
|
+
renditionsToExtract: options.fetch(:renditions_to_extract, RENDITIONS_EXTRACTS),
|
30
|
+
tableOutputFormat: options.fetch(:table_output_format, TABLE_OUTPUT_FORMATS.first),
|
31
|
+
elementsToExtract: options.fetch(:extract_elements, VALID_EXTRACT_ELEMENTS)
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def extract_pdf_request_headers
|
36
|
+
{ 'Content-Type' => 'application/json' }
|
37
|
+
end
|
38
|
+
|
39
|
+
def handle_extract_pdf_response(response, asset)
|
40
|
+
raise OperationError, "Extract PDF operation failed: #{response.body}" unless response.status == 201
|
41
|
+
|
42
|
+
polling_url = response.headers['location']
|
43
|
+
poll_document_result polling_url, asset
|
44
|
+
end
|
45
|
+
|
46
|
+
def handle_polling_done(json_response, original_asset)
|
47
|
+
file_key = @download_zip ? 'resource' : 'content'
|
48
|
+
asset_id = json_response[file_key]['assetID']
|
49
|
+
file = Asset.new(@api).download(asset_id).body
|
50
|
+
super
|
51
|
+
file
|
52
|
+
end
|
53
|
+
|
54
|
+
def validate_options(options)
|
55
|
+
validate_renditions_to_extract(options[:renditions_to_extract])
|
56
|
+
validate_table_output_format(options[:table_output_format])
|
57
|
+
validate_extract_elements(options[:extract_elements])
|
58
|
+
end
|
59
|
+
|
60
|
+
def validate_renditions_to_extract(renditions_to_extract)
|
61
|
+
renditions_to_extract ||= RENDITIONS_EXTRACTS
|
62
|
+
return if (renditions_to_extract - RENDITIONS_EXTRACTS).empty?
|
63
|
+
|
64
|
+
raise ArgumentError, "Invalid renditions_to_extract: #{renditions_to_extract}"
|
65
|
+
end
|
66
|
+
|
67
|
+
def validate_table_output_format(table_output_format)
|
68
|
+
table_output_format ||= TABLE_OUTPUT_FORMATS.first
|
69
|
+
return if TABLE_OUTPUT_FORMATS.include?(table_output_format)
|
70
|
+
|
71
|
+
raise ArgumentError, "Invalid table_output_format: #{table_output_format}"
|
72
|
+
end
|
73
|
+
|
74
|
+
def validate_extract_elements(extract_elements)
|
75
|
+
extract_elements ||= VALID_EXTRACT_ELEMENTS
|
76
|
+
invalid_elements = extract_elements - VALID_EXTRACT_ELEMENTS
|
77
|
+
return if invalid_elements.empty?
|
78
|
+
|
79
|
+
raise ArgumentError, "Invalid extract_elements: #{invalid_elements}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PdfServices
|
4
|
+
module HtmlToPdf
|
5
|
+
class External < Operation
|
6
|
+
EXTERNAL_OPTIONS = %i[input output params download_from_external].freeze
|
7
|
+
INPUT_KEYS = %i[uri storage].freeze
|
8
|
+
OUTPUT_KEYS = %i[uri storage].freeze
|
9
|
+
PARAMS_KEYS = %i[include_header_footer json page_layout].freeze
|
10
|
+
STORAGE_OPTIONS = %i[S3 SHAREPOINT DROPBOX BLOB].freeze
|
11
|
+
|
12
|
+
def initialize(api)
|
13
|
+
super
|
14
|
+
@download_from_external = false
|
15
|
+
@download_uri = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def execute(url, options = {})
|
19
|
+
@download_from_external = options[:download_from_external] || false
|
20
|
+
options[:input][:uri] = options[:input][:uri] || url
|
21
|
+
validate_options(options)
|
22
|
+
|
23
|
+
@download_uri = options[:output][:uri] if @download_from_external
|
24
|
+
|
25
|
+
response = @api.post(OPERATION_ENDPOINT,
|
26
|
+
body: request_body(asset.id, options),
|
27
|
+
headers: request_headers)
|
28
|
+
handle_response(response, asset.id)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def request_body(asset_id, options)
|
34
|
+
{
|
35
|
+
assetID: asset_id,
|
36
|
+
input: camelize_keys(options[:input]),
|
37
|
+
output: camelize_keys(options[:output]),
|
38
|
+
params: camelize_keys(options[:params])
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def handle_polling_done(_json_response, original_asset)
|
43
|
+
file = @api.get(@download_uri).body if @download_from_external
|
44
|
+
super
|
45
|
+
file || true
|
46
|
+
end
|
47
|
+
|
48
|
+
def validate_options(options)
|
49
|
+
raise ArgumentError, 'Options must be a hash' unless options.is_a?(Hash)
|
50
|
+
|
51
|
+
validate_required_keys(options)
|
52
|
+
validate_input_options(options[:input])
|
53
|
+
validate_output_options(options[:output])
|
54
|
+
end
|
55
|
+
|
56
|
+
def validate_required_keys(options)
|
57
|
+
required_keys = EXTERNAL_OPTIONS - %i[download_from_external]
|
58
|
+
required_keys.each do |key|
|
59
|
+
raise ArgumentError, "Missing required key: #{key}" unless options.key?(key)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def validate_input_options(input_options)
|
64
|
+
raise ArgumentError, 'Input options must be a hash' unless input_options.is_a?(Hash)
|
65
|
+
|
66
|
+
required_input_keys = INPUT_KEYS
|
67
|
+
required_input_keys.each do |key|
|
68
|
+
raise ArgumentError, "Missing required input key: #{key}" unless input_options.key?(key)
|
69
|
+
end
|
70
|
+
validate_storage_options(input_options[:storage])
|
71
|
+
end
|
72
|
+
|
73
|
+
def validate_output_options(output_options)
|
74
|
+
raise ArgumentError, 'Output options must be a hash' unless output_options.is_a?(Hash)
|
75
|
+
|
76
|
+
unless output_options.key?(:uri) && @download_from_external
|
77
|
+
raise ArgumentError,
|
78
|
+
'Output options must contain uri when downloading from external storage'
|
79
|
+
end
|
80
|
+
|
81
|
+
required_output_keys = OUTPUT_KEYS - %i[uri]
|
82
|
+
required_output_keys.each do |key|
|
83
|
+
raise ArgumentError, "Missing required output key: #{key}" unless output_options.key?(key)
|
84
|
+
end
|
85
|
+
validate_storage_options(output_options[:storage])
|
86
|
+
end
|
87
|
+
|
88
|
+
def validate_storage_option(storage_option)
|
89
|
+
return if STORAGE_OPTIONS.include?(storage_option)
|
90
|
+
|
91
|
+
raise ArgumentError,
|
92
|
+
"Invalid storage option: #{storage_option}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PdfServices
|
4
|
+
module HtmlToPdf
|
5
|
+
class Internal < Operation
|
6
|
+
INTERNAL_OPTIONS = %i[input_url json include_header_footer page_layout notifiers].freeze
|
7
|
+
PAGE_LAYOUT_OPTIONS = %i[page_width page_height].freeze
|
8
|
+
|
9
|
+
def execute(html_file_path, options = {})
|
10
|
+
validate_options(options)
|
11
|
+
asset = upload_asset(html_file_path)
|
12
|
+
|
13
|
+
response = @api.post(OPERATION_ENDPOINT,
|
14
|
+
body: request_body(asset.id, options),
|
15
|
+
headers: request_headers)
|
16
|
+
|
17
|
+
handle_response(response, asset.id)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def handle_polling_done(json_response, _original_asset_id)
|
23
|
+
asset_id = json_response['asset']['assetID']
|
24
|
+
Asset.new(@api).download(asset_id).body
|
25
|
+
end
|
26
|
+
|
27
|
+
def request_body(asset_id, options)
|
28
|
+
body = {
|
29
|
+
assetID: asset_id,
|
30
|
+
inputUrl: options.fetch(:input_url, ''),
|
31
|
+
pageLayout: camelize_keys(options.fetch(:page_layout, {})),
|
32
|
+
json: transform_json(options.fetch(:json, ''))
|
33
|
+
}
|
34
|
+
body[:notifiers] = options[:notifiers] if options[:notifiers]
|
35
|
+
body
|
36
|
+
end
|
37
|
+
|
38
|
+
def transform_json(json)
|
39
|
+
json.is_a?(String) ? json : json.to_json
|
40
|
+
end
|
41
|
+
|
42
|
+
def validate_options(options)
|
43
|
+
raise ArgumentError, 'Invalid options' unless options.is_a?(Hash)
|
44
|
+
|
45
|
+
options.each_key do |key|
|
46
|
+
raise ArgumentError, "Invalid option: #{key}" unless INTERNAL_OPTIONS.include?(key)
|
47
|
+
end
|
48
|
+
|
49
|
+
validate_required_keys(options)
|
50
|
+
validate_page_layout_options(options[:page_layout]) if options[:page_layout]
|
51
|
+
end
|
52
|
+
|
53
|
+
def validate_required_keys(options)
|
54
|
+
required_keys = INTERNAL_OPTIONS - %i[page_layout notifiers]
|
55
|
+
required_keys.each do |key|
|
56
|
+
raise ArgumentError, "Missing required option: #{key}" unless options.key?(key)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def validate_page_layout_options(options)
|
61
|
+
raise ArgumentError, 'Invalid page layout options' unless options.is_a?(Hash)
|
62
|
+
|
63
|
+
options.each_key do |key|
|
64
|
+
raise ArgumentError, "Invalid page layout option: #{key}" unless PAGE_LAYOUT_OPTIONS.include?(key)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PdfServices
|
4
|
+
module HtmlToPdf
|
5
|
+
class Operation < InternalExternalOperation::Operation
|
6
|
+
OPERATION_ENDPOINT = "#{BASE_ENDPOINT}htmltopdf".freeze
|
7
|
+
|
8
|
+
def request_headers
|
9
|
+
{ 'Content-Type' => 'application/json' }
|
10
|
+
end
|
11
|
+
|
12
|
+
def handle_response(response, asset_id)
|
13
|
+
unless response.status == 201
|
14
|
+
raise "Unexpected response status from document merge endpoint: #{response.status}, asset_id: #{asset_id}"
|
15
|
+
end
|
16
|
+
|
17
|
+
document_url = response.headers['location']
|
18
|
+
poll_document_result document_url, asset_id
|
19
|
+
end
|
20
|
+
|
21
|
+
def internal_class
|
22
|
+
Internal
|
23
|
+
end
|
24
|
+
|
25
|
+
def external_class
|
26
|
+
External
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module PdfServices
|
2
|
+
module InternalExternalOperation
|
3
|
+
class Operation < Base::Operation
|
4
|
+
def execute(source_file_path, options = {})
|
5
|
+
operation_class = switch_on_type(options)
|
6
|
+
operation_class.new(@api).execute(source_file_path, options)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def switch_on_type(options)
|
12
|
+
type = options[:type] || :internal
|
13
|
+
case type
|
14
|
+
when :internal
|
15
|
+
internal_class
|
16
|
+
when :external
|
17
|
+
external_class
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def internal_class
|
22
|
+
raise NotImplementedError, 'Subclasses must implement this method'
|
23
|
+
end
|
24
|
+
|
25
|
+
def external_class
|
26
|
+
raise NotImplementedError, 'Subclasses must implement this method'
|
27
|
+
end
|
28
|
+
|
29
|
+
def camelize_keys(hash)
|
30
|
+
hash.transform_keys { |key| camelize(key.to_s) }
|
31
|
+
end
|
32
|
+
|
33
|
+
def camelize(str)
|
34
|
+
caps = str.split('_').map(&:capitalize)
|
35
|
+
caps[0].downcase!
|
36
|
+
caps.join
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|