adobe_doc_api 0.1.3 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4e5a77582f1fc5d80a10d049be384c0abf2dbe2b4206522128e536a8787517de
4
- data.tar.gz: 5373eb84624217386db5663be8b8c829dcd9b98128a5a634c9467185ce3e6f3d
3
+ metadata.gz: 561ccbe710cbc9856655dc3d4235846dc2c55bacbc6d44794cc76282846b87b1
4
+ data.tar.gz: 7df931d666bb7cd7007b7c870504b996a77103e80a09ba5e97c21e9b96f8e8c8
5
5
  SHA512:
6
- metadata.gz: 9b0b0dd6eff1e19d986ef5e52e0b2409b88ecba9bac484948ed7366a485b062f94c7c11f81160735f714e08c5a24a38b6baca8cbebd15148c9562e8b360f7fdc
7
- data.tar.gz: aa00f4f6446199a46dab1b0101cbc3acd71ab44692375b83695e7062eccacab12b549298528a80f45e9c80b46ddc42217339a36d7d612aa91c39c3e86070d71c
6
+ metadata.gz: cc3925566f5027e07062cfd437d65898df2e688d33b39b6977bdf1d9954688e1d8677cb72d81b1ff4142082c022d258590166499380e37572af147da9c12cf85
7
+ data.tar.gz: 8500d15211572b7377e7e2710ca0d6c926555df58e3980972561f6b3843f483381d1d2fe70e69487c8f2edbe71a1953a8372b6f4eed38f872742871577dd9cb3
data/CHANGELOG.md CHANGED
@@ -1,4 +1,9 @@
1
- ## [Unreleased]
1
+ ## [0.2.1] - 2023-06-20
2
+ - Updates to Adobe PDF Services API
3
+ - Removed JWT token authentication
4
+
5
+ ## [0.1.4] - 2021-12-30
6
+ - Fix issue with parsing file boundary that included \r\n
2
7
 
3
8
  ## [0.1.3] - 2021-12-30
4
9
  - Added ability to configure AdobeDocApi to provide better customization
data/Gemfile.lock ADDED
@@ -0,0 +1,57 @@
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
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # AdobeDocApi
2
2
 
3
- This is still a work in progress. Use at your own risk.
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,35 +18,46 @@ 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
- config.client_id = nil
26
- config.client_secret = nil
27
- config.org_id = nil
28
- config.tech_account_id = nil
29
- config.private_key_path = nil
24
+ config.client_id = nil
25
+ config.client_secret = nil
26
+ config.org_id = nil
27
+ config.tech_account_id = nil
28
+ config.private_key_path = nil
29
+ end
30
+ ```
31
+ ### Recommended configuration if using Rails 6+
32
+ ```ruby
33
+ AdobeDocApi.configure do |config|
34
+ config.client_id = Rails.application.credentials.dig(:adobe_doc, :client_id)
35
+ 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)
30
39
  end
31
40
  ```
32
-
33
41
  ## Usage
34
42
 
35
43
  ```ruby
36
- key_path = "../full_path_to/private.key"
37
44
  template_path = "../full_path_to/disclosure.docx"
38
45
  output_path = "../full_path_to_output/output.docx"
39
46
  json_data = { 'DocTag': 'Value', 'DocTag2': 'Value2'}
40
47
 
41
48
  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
49
  client.submit(json: json_data, template: template_path, output: output_path)
47
50
  # returns true or false if file was saved to output_path
48
51
  ```
49
-
52
+ ### Usage without configuration
53
+ ```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)
60
+ ```
50
61
  ## Todo
51
62
  - [x] Add multipart parsing to improve saving the file from the response
52
63
  - [ ] Add documentation
@@ -24,78 +24,85 @@ module AdobeDocApi
24
24
  end
25
25
 
26
26
  def get_access_token(private_key)
27
- jwt_payload = {
28
- "iss" => @org_id,
29
- "sub" => @tech_account_id,
30
- "https://ims-na1.adobelogin.com/s/ent_documentcloud_sdk" => true,
31
- "aud" => "https://ims-na1.adobelogin.com/c/#{@client_id}",
32
- "exp" => (Time.now.utc + 60).to_i
33
- }
34
-
35
- rsa_private = OpenSSL::PKey::RSA.new File.read(private_key)
36
-
37
- jwt_token = JWT.encode jwt_payload, rsa_private, "RS256"
38
-
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
+ #
39
40
  connection = Faraday.new do |conn|
40
41
  conn.response :json, content_type: "application/json"
41
42
  end
42
- response = connection.post JWT_URL do |req|
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|
43
51
  req.params["client_id"] = @client_id
44
- req.params["client_secret"] = @client_secret
45
- req.params["jwt_token"] = jwt_token
52
+ req.body = "client_secret=#{@client_secret}&grant_type=client_credentials&scope=#{scopes}"
46
53
  end
47
-
48
54
  return response.body["access_token"]
49
55
  end
50
56
 
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"
68
+ end
69
+ # Return pre-signed uploadUri and assedID
70
+ return response.body["assetID"], response.body["uploadUri"]
71
+ end
72
+
51
73
  def submit(json:, template:, output:)
52
- @output = output
53
- output_format = /docx/.match?(File.extname(@output)) ? "application/vnd.openxmlformats-officedocument.wordprocessingml.document" : "application/pdf"
74
+ asset_id, upload_uri = get_asset_id
54
75
 
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
82
+
83
+ # Post JSON Data for Merge to documentGeneration
55
84
  content_request = {
56
- "cpf:engine": {
57
- "repo:assetId": "urn:aaid:cpf:Service-52d5db6097ed436ebb96f13a4c7bf8fb"
58
- },
59
- "cpf:inputs": {
60
- documentIn: {
61
- "dc:format": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
62
- "cpf:location": "InputFile0"
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
- }
85
+ assetID: asset_id,
86
+ outputFormat: File.extname(output).delete("."),
87
+ jsonDataForMerge: json
77
88
  }.to_json
78
-
79
- connection = Faraday.new API_ENDPOINT_URL do |conn|
89
+ payload = content_request
90
+ connection = Faraday.new do |conn|
80
91
  conn.request :authorization, "Bearer", @access_token
81
92
  conn.headers["x-api-key"] = @client_id
82
- conn.request :multipart
83
- conn.request :url_encoded
84
- conn.response :json, content_type: "application/json"
85
93
  end
86
-
87
- payload = {"contentAnalyzerRequests" => content_request}
88
- payload[:InputFile0] = Faraday::FilePart.new(template, "application/vnd.openxmlformats-officedocument.wordprocessingml.document")
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)
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"
97
+ end
98
+ # TODO need to check status of response
99
+ # Begin polling for status of file
100
+ poll_for_file(res.headers["location"], output)
94
101
  end
95
102
 
96
103
  private
97
104
 
98
- def poll_for_file(url)
105
+ def poll_for_file(url, output)
99
106
  connection = Faraday.new do |conn|
100
107
  conn.request :authorization, "Bearer", @access_token
101
108
  conn.headers["x-api-key"] = @client_id
@@ -105,11 +112,11 @@ module AdobeDocApi
105
112
  sleep(6)
106
113
  response = connection.get(url)
107
114
  counter += 1
108
- if response.body.include?('"cpf:status":{"completed":true,"type":"","status":200}')
109
- @raw_response = response
110
- return write_to_file(response.body)
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}
111
118
  else
112
- status = JSON.parse(response.body)["cpf:status"]
119
+ status = JSON.parse(response.body)["status"]
113
120
  raise Error.new(status_code: status["status"], msg: status) if status["status"] != 202
114
121
  end
115
122
  break if counter > 10
@@ -119,21 +126,5 @@ module AdobeDocApi
119
126
  end
120
127
  end
121
128
 
122
- def write_to_file(response_body)
123
- line_index = []
124
- lines = response_body.split("\r\n")
125
- lines.each_with_index do |line, i|
126
- next if line.include?("--Boundary_") || line.match?(/^Content-(Type|Disposition):/) || line.empty? || JSON.parse(line.force_encoding("UTF-8").to_s)
127
- rescue
128
- line_index << i
129
- end
130
- if line_index.length == 1
131
- File.open(@output, "wb") { |f| f.write lines.at(line_index[0])}
132
- true
133
- else
134
- false
135
- end
136
- end
137
-
138
129
  end
139
130
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AdobeDocApi
4
- VERSION = "0.1.3"
4
+ VERSION = "0.2.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: adobe_doc_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Sonnier
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-12-30 00:00:00.000000000 Z
11
+ date: 2023-06-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -76,6 +76,7 @@ files:
76
76
  - CHANGELOG.md
77
77
  - CODE_OF_CONDUCT.md
78
78
  - Gemfile
79
+ - Gemfile.lock
79
80
  - LICENSE.txt
80
81
  - README.md
81
82
  - Rakefile