adobe_doc_api 0.1.4 → 0.3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -1
- data/README.md +19 -18
- data/lib/adobe_doc_api/client.rb +140 -100
- data/lib/adobe_doc_api/configuration.rb +3 -5
- data/lib/adobe_doc_api/version.rb +1 -1
- metadata +7 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 88a17a7824cbc56df0cc3b1a4fe8ce43e51ac80d2f49c8aeb2bf3bd3d3afc4b6
|
4
|
+
data.tar.gz: 4ab99d5fd436027b5a8dfa58610969ec6955cd592474e55ac0285def3c4f62ce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a0298bd962026cc2c072239d0a8dda4fbca883b94389f40daa5efc843a2256b239a52bb3c21b4900c3098338b10f78e47d22c52745527b1df739ea80c46bcd3e
|
7
|
+
data.tar.gz: e8c44532b30fe23d98076fa67f5ce0b49d9def18f5593142fbed19f75410025d5461d7f87604a48f07f0b1a458f19b4f64283b49bfb77f666b288ba2ae6e5122
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,9 @@
|
|
1
|
-
## [
|
1
|
+
## [0.3.0] - 2023-06-20
|
2
|
+
- Migrated authentication from JWT to OAuth server-to-server
|
3
|
+
- Updated configuration to accept OAuth scopes
|
4
|
+
|
5
|
+
## [0.2.1] - 2023-06-20
|
6
|
+
- Updates to Adobe PDF Services API
|
2
7
|
|
3
8
|
## [0.1.4] - 2021-12-30
|
4
9
|
- Fix issue with parsing file boundary that included \r\n
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# AdobeDocApi
|
2
2
|
|
3
|
-
This is still a work in progress
|
3
|
+
This is still a work in progress and breaking changes may be made, but I will do my best to update the README when features have been changed.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
@@ -18,38 +18,39 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
$ gem install adobe_doc_api
|
20
20
|
|
21
|
-
## Configuration
|
22
|
-
* Configuration can be overridden if you need by passing the values to AdobeDocApi::Client.new
|
21
|
+
## Configuration
|
23
22
|
```ruby
|
24
23
|
AdobeDocApi.configure do |config|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
24
|
+
config.client_id = nil
|
25
|
+
config.client_secret = nil
|
26
|
+
config.scopes = nil
|
27
|
+
end
|
28
|
+
```
|
29
|
+
### Recommended configuration if using Rails 6+
|
30
|
+
```ruby
|
31
|
+
AdobeDocApi.configure do |config|
|
32
|
+
config.client_id = Rails.application.credentials.dig(:adobe_doc, :client_id)
|
33
|
+
config.client_secret = Rails.application.credentials.dig(:adobe_doc, :client_secret)
|
34
|
+
config.scopes = Rails.application.credentials.dig(:adobe_doc, :scopes)
|
30
35
|
end
|
31
36
|
```
|
32
|
-
|
33
37
|
## Usage
|
34
38
|
|
35
39
|
```ruby
|
36
|
-
key_path = "../full_path_to/private.key"
|
37
40
|
template_path = "../full_path_to/disclosure.docx"
|
38
41
|
output_path = "../full_path_to_output/output.docx"
|
39
42
|
json_data = { 'DocTag': 'Value', 'DocTag2': 'Value2'}
|
40
43
|
|
41
44
|
client = AdobeDocApi::Client.new
|
42
|
-
|
43
|
-
# Without configuration you must pass these values
|
44
|
-
# client = AdobeDocApi::Client.new(private_key: key_path, client_id: ENV['adobe_client_id'], client_secret: ENV['adobe_client_secret']org_id: ENV['adobe_org_id'], tech_account_id: ENV['adobe_tech_account_id'], access_token: nil)
|
45
|
-
|
46
45
|
client.submit(json: json_data, template: template_path, output: output_path)
|
47
46
|
# returns true or false if file was saved to output_path
|
48
47
|
```
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
48
|
+
### Usage without configuration
|
49
|
+
```ruby
|
50
|
+
client = AdobeDocApi::Client.new(client_id: adobe_client_id,
|
51
|
+
client_secret: adobe_client_secret,
|
52
|
+
scopes: adobe_scopes)
|
53
|
+
```
|
53
54
|
|
54
55
|
## Contributing
|
55
56
|
|
data/lib/adobe_doc_api/client.rb
CHANGED
@@ -1,136 +1,176 @@
|
|
1
|
-
require "
|
2
|
-
require "
|
3
|
-
require "jwt"
|
4
|
-
require "openssl"
|
1
|
+
require "net/http"
|
2
|
+
require "json"
|
5
3
|
|
6
4
|
module AdobeDocApi
|
7
5
|
class Client
|
8
|
-
|
9
|
-
API_ENDPOINT_URL = "https://
|
6
|
+
OAUTH_URL = "https://ims-na1.adobelogin.com/ims/token/v3".freeze
|
7
|
+
API_ENDPOINT_URL = "https://pdf-services-ue1.adobe.io/operation/documentgeneration"
|
8
|
+
attr_reader :location_url, :raw_response, :client_id, :client_secret, :scopes
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
def initialize(private_key: nil, client_id: nil, client_secret: nil, org_id: nil, tech_account_id: nil, access_token: nil)
|
14
|
-
# TODO Need to validate if any params are missing and return error
|
10
|
+
def initialize(client_id: nil, client_secret: nil, scopes: nil)
|
15
11
|
@client_id = client_id || AdobeDocApi.configuration.client_id
|
16
12
|
@client_secret = client_secret || AdobeDocApi.configuration.client_secret
|
17
|
-
@
|
18
|
-
@tech_account_id = tech_account_id || AdobeDocApi.configuration.tech_account_id
|
19
|
-
@private_key_path = private_key || AdobeDocApi.configuration.private_key_path
|
13
|
+
@scopes = scopes || AdobeDocApi.configuration.scopes
|
20
14
|
@location_url = nil
|
21
15
|
@output_file_path = nil
|
22
16
|
@raw_response = nil
|
23
|
-
@access_token =
|
17
|
+
@access_token = get_access_token
|
24
18
|
end
|
25
19
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
"exp" => (Time.now.utc + 60).to_i
|
33
|
-
}
|
20
|
+
def submit(json:, template:, output:)
|
21
|
+
@output = output
|
22
|
+
@asset_id, upload_uri = upload_presigned_uri
|
23
|
+
upload_asset(upload_uri, template: template)
|
24
|
+
document_generation(json: json)
|
25
|
+
end
|
34
26
|
|
35
|
-
|
27
|
+
private
|
36
28
|
|
37
|
-
|
29
|
+
def get_access_token
|
30
|
+
url = URI(OAUTH_URL)
|
31
|
+
https = Net::HTTP.new(url.host, url.port)
|
32
|
+
https.use_ssl = true
|
33
|
+
request = Net::HTTP::Post.new(url)
|
34
|
+
request["Content-Type"] = "application/x-www-form-urlencoded"
|
35
|
+
request.body = "grant_type=client_credentials&client_id=#{@client_id}&client_secret=#{@client_secret}&scope=#{@scopes}"
|
36
|
+
response = https.request(request)
|
37
|
+
if response.code.to_i != 200
|
38
|
+
raise Error.new(status_code: response.code, msg: "Failed to get access token: #{response.body}")
|
39
|
+
else
|
40
|
+
puts "Access token retrieved successfully"
|
41
|
+
JSON.parse(response.body)["access_token"]
|
42
|
+
end
|
43
|
+
end
|
38
44
|
|
39
|
-
|
40
|
-
|
45
|
+
def upload_presigned_uri
|
46
|
+
|
47
|
+
url = URI("https://pdf-services-ue1.adobe.io/assets")
|
48
|
+
https = Net::HTTP.new(url.host, url.port)
|
49
|
+
https.use_ssl = true
|
50
|
+
request = Net::HTTP::Post.new(url)
|
51
|
+
request["Content-Type"] = "application/json"
|
52
|
+
request["X-API-Key"] = @client_id
|
53
|
+
request["Authorization"] = "bearer #{@access_token}"
|
54
|
+
request.body ='{"mediaType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}'
|
55
|
+
response = https.request(request)
|
56
|
+
|
57
|
+
if response.code.to_i != 200
|
58
|
+
raise Error.new(status_code: response.code, msg: "Failed to create asset: #{response.body}")
|
59
|
+
else
|
60
|
+
puts "Asset created successfully"
|
61
|
+
response_body = JSON.parse(response.body)
|
62
|
+
asset_id = response_body["assetID"]
|
63
|
+
upload_uri = response_body["uploadUri"]
|
64
|
+
return asset_id, upload_uri
|
41
65
|
end
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
def upload_asset(upload_uri, template:)
|
70
|
+
|
71
|
+
# Upload the template to the presigned URI
|
72
|
+
url = URI(upload_uri)
|
73
|
+
https = Net::HTTP.new(url.host, url.port)
|
74
|
+
https.use_ssl = true
|
75
|
+
request = Net::HTTP::Put.new(url)
|
76
|
+
request["Content-Type"] = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
|
77
|
+
request.body = File.read(template)
|
78
|
+
response = https.request(request)
|
79
|
+
if response.code.to_i != 200
|
80
|
+
raise Error.new(status_code: response.code, msg: "Failed to upload template: #{response.body}")
|
81
|
+
else
|
82
|
+
puts "Template uploaded successfully"
|
46
83
|
end
|
47
84
|
|
48
|
-
return response.body["access_token"]
|
49
85
|
end
|
50
86
|
|
51
|
-
def
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
params: {
|
65
|
-
"cpf:inline": {
|
66
|
-
outputFormat: File.extname(@output).delete("."),
|
67
|
-
jsonDataForMerge: json
|
68
|
-
}
|
69
|
-
}
|
70
|
-
},
|
71
|
-
"cpf:outputs": {
|
72
|
-
documentOut: {
|
73
|
-
"dc:format": output_format.to_s,
|
74
|
-
"cpf:location": "multipartLabel"
|
75
|
-
}
|
76
|
-
}
|
87
|
+
def document_generation(json:)
|
88
|
+
# Document Generation
|
89
|
+
url = URI("https://pdf-services-ue1.adobe.io/operation/documentgeneration")
|
90
|
+
https = Net::HTTP.new(url.host, url.port)
|
91
|
+
https.use_ssl = true
|
92
|
+
request = Net::HTTP::Post.new(url)
|
93
|
+
request["Content-Type"] = "application/json"
|
94
|
+
request["X-API-Key"] = @client_id
|
95
|
+
request["Authorization"] = "Bearer #{@access_token}"
|
96
|
+
|
97
|
+
request.body = {"assetID": @asset_id,
|
98
|
+
"outputFormat": "docx",
|
99
|
+
"jsonDataForMerge": json
|
77
100
|
}.to_json
|
78
101
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
102
|
+
response = https.request(request)
|
103
|
+
|
104
|
+
if response.code.to_i != 201
|
105
|
+
raise Error.new(status_code: response.code, msg: "Failed to submit document generation request: #{response.body}")
|
106
|
+
else
|
107
|
+
status_url = response.header["location"]
|
108
|
+
puts "Document Generation submitted successfully"
|
85
109
|
end
|
86
110
|
|
87
|
-
|
88
|
-
|
89
|
-
res = connection.post("/ops/:create", payload)
|
90
|
-
status_code = res.body["cpf:status"]["status"].to_i
|
91
|
-
@location_url = res.headers["location"]
|
92
|
-
raise Error.new(status_code: status_code, msg: res.body["cpf:status"]) unless status_code == 202
|
93
|
-
poll_for_file(@location_url)
|
111
|
+
# Start polling for the status of the document generation
|
112
|
+
poll_status(status_url)
|
94
113
|
end
|
95
114
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
connection = Faraday.new do |conn|
|
100
|
-
conn.request :authorization, "Bearer", @access_token
|
101
|
-
conn.headers["x-api-key"] = @client_id
|
102
|
-
end
|
103
|
-
counter = 0
|
115
|
+
def poll_status(status_url, timeout: 30)
|
116
|
+
# Poll for the generated document
|
117
|
+
download_uri = nil
|
104
118
|
loop do
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
119
|
+
timeout -= 1
|
120
|
+
break if timeout <= 0
|
121
|
+
|
122
|
+
# Wait for 5 seconds before checking the status
|
123
|
+
url = URI(status_url)
|
124
|
+
https = Net::HTTP.new(url.host, url.port)
|
125
|
+
https.use_ssl = true
|
126
|
+
request = Net::HTTP::Get.new(url)
|
127
|
+
request["Content-Type"] = "application/json"
|
128
|
+
request["X-API-Key"] = @client_id
|
129
|
+
request["Authorization"] = "Bearer #{@access_token}"
|
130
|
+
response = https.request(request)
|
131
|
+
|
132
|
+
if response.code.to_i != 200
|
133
|
+
raise Error.new(status_code: response.code, msg: "Failed to check document generation status: #{response.body}")
|
134
|
+
end
|
135
|
+
|
136
|
+
response_body = JSON.parse(response.body)
|
137
|
+
puts "Current status: #{response_body['status']}"
|
138
|
+
if response_body["status"] == "done"
|
139
|
+
download_uri = response_body["asset"]["downloadUri"]
|
140
|
+
break
|
141
|
+
elsif response_body["status"] == "failed"
|
142
|
+
raise Error.new(status_code: response.code, msg: "Document generation failed: #{response.body}")
|
111
143
|
else
|
112
|
-
|
113
|
-
raise Error.new(status_code: status["status"], msg: status) if status["status"] != 202
|
144
|
+
puts "Document generation in progress..."
|
114
145
|
end
|
115
|
-
|
116
|
-
rescue => e
|
117
|
-
# Raise other exceptions
|
118
|
-
raise(e)
|
146
|
+
sleep 1
|
119
147
|
end
|
120
|
-
end
|
121
148
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
rescue
|
128
|
-
line_index << i
|
149
|
+
# If the download URI is available, proceed to download the document
|
150
|
+
if download_uri
|
151
|
+
download_output(download_uri: download_uri)
|
152
|
+
else
|
153
|
+
raise Error.new(status_code: response.code, msg: "Document generation not completed: #{response.body}")
|
129
154
|
end
|
130
155
|
|
131
|
-
return true if File.open(@output, "wb") { |f| f.write lines.map.with_index { |l, i| lines.at(i) if line_index.include?(i) }.compact.join("\r\n")}
|
132
|
-
false
|
133
156
|
end
|
134
157
|
|
158
|
+
def download_output(download_uri:)
|
159
|
+
# Finally, download the generated document
|
160
|
+
url = URI(download_uri)
|
161
|
+
https = Net::HTTP.new(url.host, url.port)
|
162
|
+
https.use_ssl = true
|
163
|
+
request = Net::HTTP::Get.new(url)
|
164
|
+
response = https.request(request)
|
165
|
+
if response.code.to_i != 200
|
166
|
+
raise Error.new(status_code: response.code, msg: "Failed to download document: #{response.body}")
|
167
|
+
else
|
168
|
+
if File.open(@output, "wb") { |f| f.write response.body }
|
169
|
+
puts "Document saved successfully to #{@output}"
|
170
|
+
return true
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
135
174
|
end
|
175
|
+
|
136
176
|
end
|
@@ -1,13 +1,11 @@
|
|
1
1
|
module AdobeDocApi
|
2
2
|
class Configuration
|
3
|
-
attr_accessor :client_id, :client_secret, :
|
3
|
+
attr_accessor :client_id, :client_secret, :scopes
|
4
4
|
|
5
5
|
def initialize
|
6
6
|
@client_id = nil
|
7
|
-
@
|
8
|
-
@
|
9
|
-
@tech_account_id = nil
|
10
|
-
@private_key_path = nil
|
7
|
+
@client_secret = nil
|
8
|
+
@scopes = nil
|
11
9
|
end
|
12
10
|
end
|
13
11
|
end
|
metadata
CHANGED
@@ -1,71 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: adobe_doc_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Sonnier
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-06-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: json
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '2.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: faraday_middleware
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '1.2'
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '1.2'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: jwt
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: 2.3.0
|
48
|
-
type: :runtime
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: 2.3.0
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: openssl
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: 2.2.1
|
62
|
-
type: :runtime
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: 2.2.1
|
26
|
+
version: '2.0'
|
69
27
|
description: Ruby interface for Adobe PDF Services API Document Generation
|
70
28
|
email:
|
71
29
|
- christopher.sonnier@gmail.com
|
@@ -101,14 +59,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
101
59
|
requirements:
|
102
60
|
- - ">="
|
103
61
|
- !ruby/object:Gem::Version
|
104
|
-
version:
|
62
|
+
version: 3.0.0
|
105
63
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
64
|
requirements:
|
107
65
|
- - ">="
|
108
66
|
- !ruby/object:Gem::Version
|
109
67
|
version: '0'
|
110
68
|
requirements: []
|
111
|
-
rubygems_version: 3.
|
69
|
+
rubygems_version: 3.4.10
|
112
70
|
signing_key:
|
113
71
|
specification_version: 4
|
114
72
|
summary: Ruby interface for Adobe PDF Services API Document Generation
|