preservation-client 2.2.0 → 3.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: a2b61bc152d52b868d7274c7e29753dca42e4547f04c836766922bad0eca4ed9
4
- data.tar.gz: 36f04a3919075d95729a6b74108f4acb9c5bb68f6625e4fc0e6b5a19f16fc52d
3
+ metadata.gz: 295c6b5719f6730587b25339215cb69a2a0577c83bb703cc0bc17bb0372b64e3
4
+ data.tar.gz: 26c60ca8f89488ed4d8e9ee301fb1632727ddb852ddaf4f2db796cf97f0a51f3
5
5
  SHA512:
6
- metadata.gz: 7750ce3cd4ef6df3ffe47dfb8b1f693894dff7dc9ad776ade1d703447c8dc52ce00464ac780d9870c93dfbf5dddbe9bd5b7a6977aeebb80876112aa31e5773b4
7
- data.tar.gz: 3a280db80ba0163894c8510238af78337866e853f09d3a528e097046d7f7c44d5f8f69805d5d67e993eafb76fc0cff9f3d53ca63ed1549941b3d72ceb7ff69fb
6
+ metadata.gz: 9d715a4987ea8c1091ba263eed8975feb66ab15e58669011860376a43ce7c80f7bbf771701f4416e9309fe7fb1dfa08e7986c0d7bf556bab939eab419e4c3fae
7
+ data.tar.gz: 2f27d27f5c0c02b0a9fb18943e5c25228e6e6d0f5ca24e190da9d7de20146f8f80d437f1351f659a627178ea52933c185aea811dcad6eff82586d6977ff6e733
@@ -1,4 +1,12 @@
1
1
  ## Why was this change made?
2
2
 
3
3
 
4
- ## Was the documentation (README, API, wiki, consul, etc.) updated?
4
+
5
+ ## How was this change tested?
6
+
7
+
8
+
9
+ ## Which documentation and/or configurations were updated?
10
+
11
+
12
+
@@ -24,6 +24,5 @@ Style/Documentation:
24
24
  Exclude:
25
25
  - 'spec/**/*'
26
26
 
27
-
28
27
  Style/WordArray:
29
28
  Enabled: false
@@ -1,11 +1,15 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2019-12-03 15:41:39 -0800 using RuboCop version 0.74.0.
3
+ # on 2020-01-27 18:06:55 -0800 using RuboCop version 0.77.0.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
- # Offense count: 3
9
+ # Offense count: 2
10
10
  Metrics/AbcSize:
11
11
  Max: 34
12
+
13
+ # Offense count: 1
14
+ Metrics/CyclomaticComplexity:
15
+ Max: 7
@@ -3,12 +3,16 @@ cache: bundler
3
3
  rvm:
4
4
  - 2.5.3
5
5
  - 2.6.4
6
+ - 2.7.1
6
7
 
7
8
  env:
8
- - "RAILS_VERSION=5.2.3"
9
- - "RAILS_VERSION=6.0.0"
9
+ jobs:
10
+ - RAILS_VERSION=5.2.3
11
+ - RAILS_VERSION=6.0.0
12
+ global:
13
+ - CC_TEST_REPORTER_ID=02e8afad8d0b699828dd69b6f45b598e7317b2d9828ea23380c3a97113068a0c
10
14
 
11
- before_install: gem install bundler -v 2.0.2
15
+ before_install: gem install bundler -v 2.1.2
12
16
 
13
17
  before_script:
14
18
  - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
data/README.md CHANGED
@@ -37,7 +37,7 @@ end
37
37
  private
38
38
 
39
39
  def client
40
- @client ||= Preservation::Client.configure(url: Settings.preservation_catalog.url)
40
+ @client ||= Preservation::Client.configure(url: Settings.preservation_catalog.url, token: Settings.preservation_catalog.token)
41
41
  end
42
42
  ```
43
43
 
@@ -47,7 +47,7 @@ OR
47
47
  require 'preservation/client'
48
48
 
49
49
  def initialize
50
- Preservation::Client.configure(url: Settings.preservation_catalog.url)
50
+ Preservation::Client.configure(url: Settings.preservation_catalog.url, token: Settings.preservation_catalog.token)
51
51
  end
52
52
 
53
53
  def do_the_thing
@@ -55,7 +55,9 @@ def do_the_thing
55
55
  end
56
56
  ```
57
57
 
58
- Note that the client may **not** be used without first having been configured, and the `url` keyword is **required**.
58
+ Note that the client may **not** be used without first having been configured, and both the `url` and `token` keywords are **required**.
59
+
60
+ See https://github.com/sul-dlss/preservation_catalog#api for info on obtaining a valid API token.
59
61
 
60
62
  Note that the preservation service is behind a firewall.
61
63
 
@@ -86,6 +88,10 @@ Note that the preservation service is behind a firewall.
86
88
  - `client.objects.metadata(druid: 'oo000oo0000', filepath: 'identityMetadata.xml', version: '8')` - returns contents of identityMetadata.xml in version 8 of Moab object
87
89
  - `client.objects.signature_catalog('oo000oo0000')` - returns latest Moab::SignatureCatalog from Moab
88
90
 
91
+ ### Retrieve the primary moab storage location
92
+
93
+ - `client.objects.primary_moab_location(druid: 'ooo000oo0000')` - returns the path to the storage location for the primary moab
94
+
89
95
  ### Get difference information between passed contentMetadata.xml and files in the Moab
90
96
 
91
97
  - `client.objects.content_inventory_diff(druid: 'oo000oo0000', content_metadata: '<contentMetadata>...</contentMetadata>')` - returns Moab::FileInventoryDifference containing differences between passed content metadata and latest version for subset 'all'
@@ -17,16 +17,22 @@ module Preservation
17
17
  class Client
18
18
  class Error < StandardError; end
19
19
 
20
- # Error that is raised when the remote server returns a 404 Not Found
20
+ # Error raised when server returns 404 Not Found
21
21
  class NotFoundError < Error; end
22
22
 
23
- # Error that is raised when the remote server returns some unexpected response
24
- # e.g. 4xx or 5xx status
23
+ # Error raised when server returns 423 Locked
24
+ class LockedError < Error; end
25
+
26
+ # Error raised when server returns an unexpected response
27
+ # e.g., 4xx or 5xx status not otherwise handled
25
28
  class UnexpectedResponseError < Error; end
26
29
 
30
+ # Error raised when Faraday gem fails to connect, e.g., on SSL errors or
31
+ # timeouts
27
32
  class ConnectionFailedError < Error; end
28
33
 
29
34
  DEFAULT_API_VERSION = 'v1'
35
+ TOKEN_HEADER = 'Authorization'
30
36
 
31
37
  include Singleton
32
38
 
@@ -42,8 +48,10 @@ module Preservation
42
48
 
43
49
  class << self
44
50
  # @param [String] url
45
- def configure(url:)
51
+ # @param [String] token a bearer token for HTTP authentication
52
+ def configure(url:, token:)
46
53
  instance.url = url
54
+ instance.token = token
47
55
 
48
56
  # Force connection to be re-established when `.configure` is called
49
57
  instance.connection = nil
@@ -54,7 +62,7 @@ module Preservation
54
62
  delegate :objects, :update, to: :instance
55
63
  end
56
64
 
57
- attr_writer :url, :connection
65
+ attr_writer :url, :connection, :token
58
66
  delegate :update, to: :catalog
59
67
 
60
68
  private
@@ -63,6 +71,10 @@ module Preservation
63
71
  @url || raise(Error, 'url has not yet been configured')
64
72
  end
65
73
 
74
+ def token
75
+ @token || raise(Error, 'auth token has not been configured')
76
+ end
77
+
66
78
  def connection
67
79
  @connection ||= Faraday.new(url) do |builder|
68
80
  builder.use ErrorFaradayMiddleware
@@ -70,6 +82,7 @@ module Preservation
70
82
  builder.use Faraday::Response::RaiseError # raise exceptions on 40x, 50x responses
71
83
  builder.adapter Faraday.default_adapter
72
84
  builder.headers[:user_agent] = user_agent
85
+ builder.headers[TOKEN_HEADER] = "Bearer #{token}"
73
86
  end
74
87
  end
75
88
 
@@ -50,8 +50,9 @@ module Preservation
50
50
  # @param [String] druid - with or without prefix: 'druid:ab123cd4567' OR 'ab123cd4567'
51
51
  # @param [String] filepath - the path of the file relative to the moab content directory
52
52
  # @param [String] version - the version of the file requested (defaults to nil for latest version)
53
- def content(druid:, filepath:, version: nil)
54
- file(druid, 'content', filepath, version)
53
+ # @param [Proc] on_data a block, if provided is called to do streaming responses
54
+ def content(druid:, filepath:, version: nil, on_data: nil)
55
+ file(druid, 'content', filepath, version, on_data: on_data)
55
56
  end
56
57
 
57
58
  # retrieve a manifest file from a Moab object
@@ -70,6 +71,15 @@ module Preservation
70
71
  file(druid, 'metadata', filepath, version)
71
72
  end
72
73
 
74
+ # retrieve the storage location for the primary moab of the given druid
75
+ # @param [String] druid - with or without prefix: 'druid:ab123cd4567' or 'ab123cd4567'
76
+ # @return [String] the storage location of the primary moab for the given druid
77
+ # @raise [Preservation::Client::NotFoundError] when druid is not found
78
+ # @raise [Preservation::Client::LockedError] when druid is in locked state (not available for versioning)
79
+ def primary_moab_location(druid:)
80
+ get("objects/#{druid}/primary_moab_location", {}, on_data: nil)
81
+ end
82
+
73
83
  # convenience method for retrieving latest Moab::SignatureCatalog from a Moab object,
74
84
  # @param [String] druid - with or without prefix: 'druid:ab123cd4567' OR 'ab123cd4567'
75
85
  # @return [Moab::SignatureCatalog] the manifest of all files previously ingested
@@ -83,10 +93,11 @@ module Preservation
83
93
  # @param [String] druid - with or without prefix: 'druid:ab123cd4567' OR 'ab123cd4567'
84
94
  # @param [String] category - one of 'manifest', 'metadata' or 'content'
85
95
  # @param [String] filepath - the path of the file relative to the moab category directory
86
- # @param [String] version - the version of the file requested (defaults to nil for latest version)
96
+ # @param [String] version - the version of the file requested
97
+ # @param [Proc] on_data a block, if provided is called to do streaming responses
87
98
  # @return the retrieved file
88
- def file(druid, category, filepath, version = nil)
89
- get("objects/#{druid}/file", category: category, filepath: filepath, version: version)
99
+ def file(druid, category, filepath, version, on_data: nil)
100
+ get("objects/#{druid}/file", { category: category, filepath: filepath, version: version }, on_data: on_data)
90
101
  end
91
102
  end
92
103
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Preservation
4
4
  class Client
5
- VERSION = '2.2.0'
5
+ VERSION = '3.3.0'
6
6
  end
7
7
  end
@@ -15,7 +15,7 @@ module Preservation
15
15
 
16
16
  # @param path [String] path to be appended to connection url (no leading slash)
17
17
  def get_json(path, object_id)
18
- req_url = api_version.present? ? "#{api_version}/#{path}" : path
18
+ req_url = "#{api_version}/#{path}"
19
19
  resp = connection.get do |req|
20
20
  req.url req_url
21
21
  req.headers['Content-Type'] = 'application/json'
@@ -25,46 +25,78 @@ module Preservation
25
25
 
26
26
  errmsg = ResponseErrorFormatter
27
27
  .format(response: resp, object_id: object_id, client_method_name: caller_locations.first.label)
28
- raise Preservation::Client::UnexpectedResponseError, errmsg
28
+ raise UnexpectedResponseError, errmsg
29
29
  rescue Faraday::ResourceNotFound
30
30
  errmsg = "#{object_id} not found in Preservation at #{connection.url_prefix}#{req_url}"
31
- raise Preservation::Client::NotFoundError, errmsg
31
+ raise NotFoundError, errmsg
32
32
  rescue Faraday::Error => e
33
33
  errmsg = "Preservation::Client.#{caller_locations.first.label} for #{object_id} " \
34
34
  "got #{e.response[:status]} from Preservation at #{req_url}: #{e.response[:body]}"
35
- raise Preservation::Client::UnexpectedResponseError, errmsg
35
+ raise UnexpectedResponseError, errmsg
36
36
  end
37
37
 
38
38
  # @param path [String] path to be appended to connection url (no leading slash)
39
- # @param params [Hash] optional params
40
- def get(path, params)
41
- http_response(:get, path, params)
39
+ # @param params [Hash] optional request parameters
40
+ # @param on_data [Proc] a callback to use when a streaming response is desired.
41
+ def get(path, params, on_data:)
42
+ return http_response(:get, path, params) unless on_data
43
+
44
+ connection.get("#{api_version}/#{path}", params) do |req|
45
+ req.options.on_data = on_data
46
+ end
42
47
  end
43
48
 
44
49
  # @param path [String] path to be appended to connection url (no leading slash)
45
- # @param params [Hash] optional params
50
+ # @param params [Hash] optional request parameters
46
51
  def post(path, params)
47
52
  http_response(:post, path, params)
48
53
  end
49
54
 
50
- # @param method [Symbol] :get or :post
51
55
  # @param path [String] path to be appended to connection url (no leading slash)
52
- # @param params [Hash] optional params
56
+ # @param params [Hash] optional request parameters
57
+ def patch(path, params)
58
+ http_response(:patch, path, params)
59
+ end
60
+
61
+ # @param path [String] path to be appended to connection url (no leading slash)
62
+ # @param params [Hash] optional request parameters
63
+ def put(path, params)
64
+ http_response(:put, path, params)
65
+ end
66
+
67
+ # @param path [String] path to be appended to connection url (no leading slash)
68
+ # @param params [Hash] optional request parameters
69
+ def delete(path, params)
70
+ http_response(:delete, path, params)
71
+ end
72
+
73
+ # @param method [Symbol] a symbol representing an HTTP method: :get, :post, :patch, :put, :delete
74
+ # @param path [String] path to be appended to connection url (no leading slash)
75
+ # @param params [Hash] optional request parameters
53
76
  def http_response(method, path, params)
54
- req_url = api_version.present? ? "#{api_version}/#{path}" : path
55
- resp = connection.send(method, req_url, params)
77
+ req_url = "#{api_version}/#{path}"
78
+ resp =
79
+ case method
80
+ when :delete, :get
81
+ connection.public_send(method, req_url, params)
82
+ when :patch, :post, :put
83
+ request_json = params.to_json if params&.any?
84
+ connection.public_send(method, req_url, request_json, 'Content-Type' => 'application/json')
85
+ end
86
+
56
87
  return resp.body if resp.success?
57
88
 
58
89
  errmsg = ResponseErrorFormatter.format(response: resp, client_method_name: caller_locations.first.label)
59
- raise Preservation::Client::UnexpectedResponseError, errmsg
90
+ raise UnexpectedResponseError, errmsg
60
91
  rescue Faraday::ResourceNotFound => e
61
92
  errmsg = "Preservation::Client.#{caller_locations.first.label} " \
62
93
  "got #{e.response[:status]} from Preservation at #{req_url}: #{e.response[:body]}"
63
- raise Preservation::Client::NotFoundError, errmsg
94
+ raise NotFoundError, errmsg
64
95
  rescue Faraday::Error => e
65
96
  errmsg = "Preservation::Client.#{caller_locations.first.label} " \
66
97
  "got #{e.response[:status]} from Preservation at #{req_url}: #{e.response[:body]}"
67
- raise Preservation::Client::UnexpectedResponseError, errmsg
98
+ exception_class = e.response[:status] == 423 ? LockedError : UnexpectedResponseError
99
+ raise exception_class, errmsg
68
100
  end
69
101
  end
70
102
  end
@@ -35,9 +35,9 @@ Gem::Specification.new do |spec|
35
35
 
36
36
  spec.add_development_dependency 'bundler', '~> 2.0'
37
37
  spec.add_development_dependency 'pry-byebug'
38
- spec.add_development_dependency 'rake', '~> 10.0'
38
+ spec.add_development_dependency 'rake', '>= 12.3.3'
39
39
  spec.add_development_dependency 'rspec', '~> 3.0'
40
40
  spec.add_development_dependency 'rubocop', '~> 0.77.0'
41
- spec.add_development_dependency 'simplecov'
41
+ spec.add_development_dependency 'simplecov', '~> 0.17.0' # For CodeClimate
42
42
  spec.add_development_dependency 'webmock'
43
43
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: preservation-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 3.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Naomi Dushay
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-01-15 00:00:00.000000000 Z
11
+ date: 2020-07-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -110,16 +110,16 @@ dependencies:
110
110
  name: rake
111
111
  requirement: !ruby/object:Gem::Requirement
112
112
  requirements:
113
- - - "~>"
113
+ - - ">="
114
114
  - !ruby/object:Gem::Version
115
- version: '10.0'
115
+ version: 12.3.3
116
116
  type: :development
117
117
  prerelease: false
118
118
  version_requirements: !ruby/object:Gem::Requirement
119
119
  requirements:
120
- - - "~>"
120
+ - - ">="
121
121
  - !ruby/object:Gem::Version
122
- version: '10.0'
122
+ version: 12.3.3
123
123
  - !ruby/object:Gem::Dependency
124
124
  name: rspec
125
125
  requirement: !ruby/object:Gem::Requirement
@@ -152,16 +152,16 @@ dependencies:
152
152
  name: simplecov
153
153
  requirement: !ruby/object:Gem::Requirement
154
154
  requirements:
155
- - - ">="
155
+ - - "~>"
156
156
  - !ruby/object:Gem::Version
157
- version: '0'
157
+ version: 0.17.0
158
158
  type: :development
159
159
  prerelease: false
160
160
  version_requirements: !ruby/object:Gem::Requirement
161
161
  requirements:
162
- - - ">="
162
+ - - "~>"
163
163
  - !ruby/object:Gem::Version
164
- version: '0'
164
+ version: 0.17.0
165
165
  - !ruby/object:Gem::Dependency
166
166
  name: webmock
167
167
  requirement: !ruby/object:Gem::Requirement
@@ -225,7 +225,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
225
225
  - !ruby/object:Gem::Version
226
226
  version: '0'
227
227
  requirements: []
228
- rubygems_version: 3.0.3
228
+ rubygems_version: 3.0.6
229
229
  signing_key:
230
230
  specification_version: 4
231
231
  summary: A thin client for getting info from SDR preservation.