adobe_pdfservices_ruby 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +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
|