adobe_doc_api 0.2.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 561ccbe710cbc9856655dc3d4235846dc2c55bacbc6d44794cc76282846b87b1
4
- data.tar.gz: 7df931d666bb7cd7007b7c870504b996a77103e80a09ba5e97c21e9b96f8e8c8
3
+ metadata.gz: 88a17a7824cbc56df0cc3b1a4fe8ce43e51ac80d2f49c8aeb2bf3bd3d3afc4b6
4
+ data.tar.gz: 4ab99d5fd436027b5a8dfa58610969ec6955cd592474e55ac0285def3c4f62ce
5
5
  SHA512:
6
- metadata.gz: cc3925566f5027e07062cfd437d65898df2e688d33b39b6977bdf1d9954688e1d8677cb72d81b1ff4142082c022d258590166499380e37572af147da9c12cf85
7
- data.tar.gz: 8500d15211572b7377e7e2710ca0d6c926555df58e3980972561f6b3843f483381d1d2fe70e69487c8f2edbe71a1953a8372b6f4eed38f872742871577dd9cb3
6
+ metadata.gz: a0298bd962026cc2c072239d0a8dda4fbca883b94389f40daa5efc843a2256b239a52bb3c21b4900c3098338b10f78e47d22c52745527b1df739ea80c46bcd3e
7
+ data.tar.gz: e8c44532b30fe23d98076fa67f5ce0b49d9def18f5593142fbed19f75410025d5461d7f87604a48f07f0b1a458f19b4f64283b49bfb77f666b288ba2ae6e5122
data/CHANGELOG.md CHANGED
@@ -1,6 +1,9 @@
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
+
1
5
  ## [0.2.1] - 2023-06-20
2
6
  - Updates to Adobe PDF Services API
3
- - Removed JWT token authentication
4
7
 
5
8
  ## [0.1.4] - 2021-12-30
6
9
  - Fix issue with parsing file boundary that included \r\n
data/README.md CHANGED
@@ -23,9 +23,7 @@ Or install it yourself as:
23
23
  AdobeDocApi.configure do |config|
24
24
  config.client_id = nil
25
25
  config.client_secret = nil
26
- config.org_id = nil
27
- config.tech_account_id = nil
28
- config.private_key_path = nil
26
+ config.scopes = nil
29
27
  end
30
28
  ```
31
29
  ### Recommended configuration if using Rails 6+
@@ -33,9 +31,7 @@ end
33
31
  AdobeDocApi.configure do |config|
34
32
  config.client_id = Rails.application.credentials.dig(:adobe_doc, :client_id)
35
33
  config.client_secret = Rails.application.credentials.dig(:adobe_doc, :client_secret)
36
- config.org_id = Rails.application.credentials.dig(:adobe_doc, :org_id)
37
- config.tech_account_id = Rails.application.credentials.dig(:adobe_doc, :tech_account_id)
38
- config.private_key_path = Rails.application.credentials.dig(:adobe_doc, :private_key_path)
34
+ config.scopes = Rails.application.credentials.dig(:adobe_doc, :scopes)
39
35
  end
40
36
  ```
41
37
  ## Usage
@@ -51,16 +47,10 @@ client.submit(json: json_data, template: template_path, output: output_path)
51
47
  ```
52
48
  ### Usage without configuration
53
49
  ```ruby
54
- client = AdobeDocApi::Client.new(private_key: key_path,
55
- client_id: adobe_client_id,
56
- client_secret: adobe_client_secret,
57
- org_id: adobe_org_id,
58
- tech_account_id: adobe_tech_account_id,
59
- access_token: nil)
50
+ client = AdobeDocApi::Client.new(client_id: adobe_client_id,
51
+ client_secret: adobe_client_secret,
52
+ scopes: adobe_scopes)
60
53
  ```
61
- ## Todo
62
- - [x] Add multipart parsing to improve saving the file from the response
63
- - [ ] Add documentation
64
54
 
65
55
  ## Contributing
66
56
 
@@ -1,130 +1,176 @@
1
- require "faraday"
2
- require "faraday_middleware"
3
- require "jwt"
4
- require "openssl"
1
+ require "net/http"
2
+ require "json"
5
3
 
6
4
  module AdobeDocApi
7
5
  class Client
8
- JWT_URL = "https://ims-na1.adobelogin.com/ims/exchange/jwt/".freeze
9
- API_ENDPOINT_URL = "https://cpf-ue1.adobe.io".freeze
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
- attr_reader :access_token, :location_url, :raw_response, :client_id, :client_secret, :org_id, :tech_account_id
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
- @org_id = org_id || AdobeDocApi.configuration.org_id
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 = access_token || get_access_token(@private_key_path)
17
+ @access_token = get_access_token
24
18
  end
25
19
 
26
- def get_access_token(private_key)
27
- # TODO: JWT token deprecated and will stop working Jan 1, 2024.
28
- # jwt_payload = {
29
- # "iss" => @org_id,
30
- # "sub" => @tech_account_id,
31
- # "https://ims-na1.adobelogin.com/s/ent_documentcloud_sdk" => true,
32
- # "aud" => "https://ims-na1.adobelogin.com/c/#{@client_id}",
33
- # "exp" => (Time.now.utc + 60).to_i
34
- # }
35
- #
36
- # rsa_private = OpenSSL::PKey::RSA.new File.read(private_key)
37
- #
38
- # jwt_token = JWT.encode jwt_payload, rsa_private, "RS256"
39
- #
40
- connection = Faraday.new do |conn|
41
- conn.response :json, content_type: "application/json"
42
- end
43
- # response = connection.post JWT_URL do |req|
44
- # req.params["client_id"] = @client_id
45
- # req.params["client_secret"] = @client_secret
46
- # req.params["jwt_token"] = jwt_token
47
- # end
48
- scopes = "openid, DCAPI, AdobeID"
49
-
50
- response = connection.post "https://ims-na1.adobelogin.com/ims/token/v3" do |req|
51
- req.params["client_id"] = @client_id
52
- req.body = "client_secret=#{@client_secret}&grant_type=client_credentials&scope=#{scopes}"
53
- end
54
- return response.body["access_token"]
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)
55
25
  end
56
26
 
57
- def get_asset_id
58
- # Create new asset ID to get upload pre-signed Uri
59
- connection = Faraday.new do |conn|
60
- conn.request :authorization, "Bearer", @access_token
61
- conn.headers["x-api-key"] = @client_id
62
- conn.headers["Content-Type"] = ""
63
- conn.response :json, content_type: "application/json"
64
- end
65
- response = connection.post "https://pdf-services.adobe.io/assets" do |req|
66
- req.body = {mediaType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}.to_json
67
- req.headers["Content-Type"] = "application/json"
27
+ private
28
+
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"]
68
42
  end
69
- # Return pre-signed uploadUri and assedID
70
- return response.body["assetID"], response.body["uploadUri"]
71
43
  end
72
44
 
73
- def submit(json:, template:, output:)
74
- asset_id, upload_uri = get_asset_id
45
+ def upload_presigned_uri
75
46
 
76
- # Upload template to asset created earlier.
77
- response = Faraday.put upload_uri do |req|
78
- req.headers["Content-Type"] = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
79
- req.body = File.binread(template)
80
- end
81
- raise("Failed to upload template.") if response.status.to_i != 200
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)
82
56
 
83
- # Post JSON Data for Merge to documentGeneration
84
- content_request = {
85
- assetID: asset_id,
86
- outputFormat: File.extname(output).delete("."),
87
- jsonDataForMerge: json
88
- }.to_json
89
- payload = content_request
90
- connection = Faraday.new do |conn|
91
- conn.request :authorization, "Bearer", @access_token
92
- conn.headers["x-api-key"] = @client_id
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
93
65
  end
94
- res = connection.post "https://pdf-services-ue1.adobe.io/operation/documentgeneration" do |req|
95
- req.body = payload
96
- req.headers["Content-Type"] = "application/json"
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"
97
83
  end
98
- # TODO need to check status of response
99
- # Begin polling for status of file
100
- poll_for_file(res.headers["location"], output)
84
+
101
85
  end
102
86
 
103
- private
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}"
104
96
 
105
- def poll_for_file(url, output)
106
- connection = Faraday.new do |conn|
107
- conn.request :authorization, "Bearer", @access_token
108
- conn.headers["x-api-key"] = @client_id
97
+ request.body = {"assetID": @asset_id,
98
+ "outputFormat": "docx",
99
+ "jsonDataForMerge": json
100
+ }.to_json
101
+
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"
109
109
  end
110
- counter = 0
110
+
111
+ # Start polling for the status of the document generation
112
+ poll_status(status_url)
113
+ end
114
+
115
+ def poll_status(status_url, timeout: 30)
116
+ # Poll for the generated document
117
+ download_uri = nil
111
118
  loop do
112
- sleep(6)
113
- response = connection.get(url)
114
- counter += 1
115
- if JSON.parse(response.body)["status"] == "done"
116
- file_response = Faraday.get JSON.parse(response.body)["asset"]["downloadUri"]
117
- return true if File.open(output, "wb") { |f| f.write file_response.body}
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}")
118
143
  else
119
- status = JSON.parse(response.body)["status"]
120
- raise Error.new(status_code: status["status"], msg: status) if status["status"] != 202
144
+ puts "Document generation in progress..."
121
145
  end
122
- break if counter > 10
123
- rescue => e
124
- # Raise other exceptions
125
- raise(e)
146
+ sleep 1
147
+ end
148
+
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}")
126
154
  end
155
+
127
156
  end
128
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
129
174
  end
175
+
130
176
  end
@@ -1,13 +1,11 @@
1
1
  module AdobeDocApi
2
2
  class Configuration
3
- attr_accessor :client_id, :client_secret, :org_id, :tech_account_id, :private_key_path
3
+ attr_accessor :client_id, :client_secret, :scopes
4
4
 
5
5
  def initialize
6
6
  @client_id = nil
7
- @client_sercret = nil
8
- @org_id = nil
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AdobeDocApi
4
- VERSION = "0.2.1"
4
+ VERSION = "0.3.0"
5
5
  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.2.1
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: 2023-06-20 00:00:00.000000000 Z
11
+ date: 2025-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: faraday
14
+ name: json
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.8'
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: '1.8'
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
@@ -76,7 +34,6 @@ files:
76
34
  - CHANGELOG.md
77
35
  - CODE_OF_CONDUCT.md
78
36
  - Gemfile
79
- - Gemfile.lock
80
37
  - LICENSE.txt
81
38
  - README.md
82
39
  - Rakefile
@@ -102,14 +59,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
102
59
  requirements:
103
60
  - - ">="
104
61
  - !ruby/object:Gem::Version
105
- version: 2.6.0
62
+ version: 3.0.0
106
63
  required_rubygems_version: !ruby/object:Gem::Requirement
107
64
  requirements:
108
65
  - - ">="
109
66
  - !ruby/object:Gem::Version
110
67
  version: '0'
111
68
  requirements: []
112
- rubygems_version: 3.2.32
69
+ rubygems_version: 3.4.10
113
70
  signing_key:
114
71
  specification_version: 4
115
72
  summary: Ruby interface for Adobe PDF Services API Document Generation
data/Gemfile.lock DELETED
@@ -1,57 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- adobe_doc_api (0.2.0)
5
- faraday (~> 1.8)
6
- faraday_middleware (~> 1.2)
7
- jwt (~> 2.3.0)
8
- openssl (~> 2.2.1)
9
-
10
- GEM
11
- remote: https://rubygems.org/
12
- specs:
13
- faraday (1.10.3)
14
- faraday-em_http (~> 1.0)
15
- faraday-em_synchrony (~> 1.0)
16
- faraday-excon (~> 1.1)
17
- faraday-httpclient (~> 1.0)
18
- faraday-multipart (~> 1.0)
19
- faraday-net_http (~> 1.0)
20
- faraday-net_http_persistent (~> 1.0)
21
- faraday-patron (~> 1.0)
22
- faraday-rack (~> 1.0)
23
- faraday-retry (~> 1.0)
24
- ruby2_keywords (>= 0.0.4)
25
- faraday-em_http (1.0.0)
26
- faraday-em_synchrony (1.0.0)
27
- faraday-excon (1.1.0)
28
- faraday-httpclient (1.0.1)
29
- faraday-multipart (1.0.4)
30
- multipart-post (~> 2)
31
- faraday-net_http (1.0.1)
32
- faraday-net_http_persistent (1.2.0)
33
- faraday-patron (1.0.0)
34
- faraday-rack (1.0.0)
35
- faraday-retry (1.0.3)
36
- faraday_middleware (1.2.0)
37
- faraday (~> 1.0)
38
- ipaddr (1.2.5)
39
- jwt (2.3.0)
40
- minitest (5.15.0)
41
- multipart-post (2.3.0)
42
- openssl (2.2.3)
43
- ipaddr
44
- rake (13.0.6)
45
- ruby2_keywords (0.0.5)
46
-
47
- PLATFORMS
48
- x86_64-darwin-19
49
- x86_64-linux
50
-
51
- DEPENDENCIES
52
- adobe_doc_api!
53
- minitest (~> 5.0)
54
- rake (~> 13.0)
55
-
56
- BUNDLED WITH
57
- 2.2.32