duracloud-client 0.1.5 → 0.2.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/.travis.yml +1 -3
- data/Gemfile +3 -0
- data/README.md +9 -5
- data/duracloud.gemspec +2 -2
- data/gemfiles/{Gemfile.activemodel-4.1 → Gemfile.activemodel-5.0} +1 -1
- data/lib/duracloud/content.rb +39 -25
- data/lib/duracloud/error.rb +1 -0
- data/lib/duracloud/properties.rb +1 -1
- data/lib/duracloud/space.rb +1 -1
- data/lib/duracloud/version.rb +1 -1
- data/spec/unit/content_spec.rb +54 -14
- metadata +15 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 45e670a025414a048dd0e4043e25a370ef6085ee
|
4
|
+
data.tar.gz: 43ec5144e26fa7fb3334652bece16f293ddf3324
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc638f78a134b5be821ceab5269ed84abe98d8f09bfa3d4122c1bf878dd1ab43d846fe8caf75c933e75fc868c9f3b80df8c7f98314702296535c7d6d10201c33
|
7
|
+
data.tar.gz: 84dbd31e44ebbc41c3f62ecbc2d9e2c1164f3ef5823818ebb88e4ec9c9051d4d6d15b6334210bf4a226f19851a1e40c3b2186dcd64a5ad568e53f2b19701a4ad
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -6,7 +6,7 @@ Ruby client for communicating with DuraCloud
|
|
6
6
|
Add this line to your application's Gemfile:
|
7
7
|
|
8
8
|
```ruby
|
9
|
-
gem 'duracloud'
|
9
|
+
gem 'duracloud-client'
|
10
10
|
```
|
11
11
|
|
12
12
|
And then execute:
|
@@ -15,7 +15,7 @@ And then execute:
|
|
15
15
|
|
16
16
|
Or install it yourself as:
|
17
17
|
|
18
|
-
$ gem install duracloud
|
18
|
+
$ gem install duracloud-client
|
19
19
|
|
20
20
|
## Usage
|
21
21
|
|
@@ -125,7 +125,7 @@ foo8
|
|
125
125
|
#### Create a new content item and store it in DuraCloud
|
126
126
|
|
127
127
|
```
|
128
|
-
>> new_content = Duracloud::Content.new("rest-api-testing", "ark:/99999/fk4zzzz")
|
128
|
+
>> new_content = Duracloud::Content.new(space_id: "rest-api-testing", content_id: "ark:/99999/fk4zzzz")
|
129
129
|
=> #<Duracloud::Content space_id="rest-api-testing", content_id="ark:/99999/fk4zzzz", store_id=(default)>
|
130
130
|
|
131
131
|
>> new_content.body = "test"
|
@@ -138,16 +138,20 @@ foo8
|
|
138
138
|
=> #<Duracloud::Content space_id="rest-api-testing", content_id="ark:/99999/fk4zzzz", store_id=(default)>
|
139
139
|
```
|
140
140
|
|
141
|
-
When storing content a `Duracloud::NotFoundError` is raised if the space does not exist.
|
141
|
+
When storing content a `Duracloud::NotFoundError` is raised if the space does not exist.
|
142
|
+
A `Duracloud::BadRequestError` is raised if the content ID is invalid.
|
143
|
+
A `Duracloud::ConflictError` is raised if the provided MD5 digest does not match the stored digest.
|
142
144
|
|
143
145
|
#### Retrieve an existing content item from DuraCloud
|
144
146
|
|
145
147
|
```
|
146
|
-
>> Duracloud::Content.find("spaceID", "contentID")
|
148
|
+
>> Duracloud::Content.find(space_id: "spaceID", content_id: "contentID")
|
147
149
|
=> #<Duracloud::Content space_id="spaceID", content_id="contentID", store_id=(default)>
|
148
150
|
```
|
149
151
|
|
150
152
|
If the space or content ID does not exist, a `Duracloud::NotFoundError` is raised.
|
153
|
+
If an MD5 digest is provided (:md5 attribute), a `Duracloud::MessageDigestError` is
|
154
|
+
raised if the content ID exists and the stored digest does not match.
|
151
155
|
|
152
156
|
#### Update the properties for a content item
|
153
157
|
|
data/duracloud.gemspec
CHANGED
@@ -18,11 +18,11 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.required_ruby_version = ">= 2.
|
21
|
+
spec.required_ruby_version = ">= 2.2"
|
22
22
|
|
23
23
|
spec.add_dependency "hashie", "~> 3.4"
|
24
24
|
spec.add_dependency "httpclient", "~> 2.7"
|
25
|
-
spec.add_dependency "activemodel", "
|
25
|
+
spec.add_dependency "activemodel", ">= 4.2", "< 6"
|
26
26
|
spec.add_dependency "nokogiri", "~> 1.6"
|
27
27
|
|
28
28
|
spec.add_development_dependency "webmock", "~> 2.0"
|
data/lib/duracloud/content.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require "stringio"
|
2
1
|
require "active_model"
|
3
2
|
|
4
3
|
module Duracloud
|
@@ -6,6 +5,7 @@ module Duracloud
|
|
6
5
|
# A piece of content in DuraCloud
|
7
6
|
#
|
8
7
|
class Content
|
8
|
+
include ActiveModel::Model
|
9
9
|
include ActiveModel::Dirty
|
10
10
|
include Persistence
|
11
11
|
include HasProperties
|
@@ -15,39 +15,31 @@ module Duracloud
|
|
15
15
|
after_save :changes_applied
|
16
16
|
|
17
17
|
# Does the content exist in DuraCloud?
|
18
|
-
# @see .new for arguments
|
19
18
|
# @return [Boolean] whether the content exists
|
20
|
-
|
21
|
-
|
19
|
+
# @raise [Duracloud::MessageDigestError] the provided digest in the :md5 attribute
|
20
|
+
# does not match the stored value
|
21
|
+
def self.exist?(params={})
|
22
|
+
find(params) && true
|
22
23
|
rescue NotFoundError
|
23
24
|
false
|
24
25
|
end
|
25
26
|
|
26
27
|
# Find content in DuraCloud.
|
27
|
-
# @see .new for arguments
|
28
28
|
# @return [Duraclound::Content] the content
|
29
29
|
# @raise [Duracloud::NotFoundError] the space, content, or store does not exist.
|
30
|
-
|
31
|
-
|
30
|
+
# @raise [Duracloud::MessageDigestError] the provided digest in the :md5 attribute
|
31
|
+
# does not match the stored value
|
32
|
+
def self.find(params={})
|
33
|
+
new(params).tap do |content|
|
34
|
+
content.load_properties
|
35
|
+
end
|
32
36
|
end
|
33
37
|
|
34
|
-
|
38
|
+
attr_accessor :space_id, :content_id, :store_id
|
35
39
|
alias_method :id, :content_id
|
40
|
+
validates_presence_of :space_id, :content_id
|
36
41
|
|
37
|
-
define_attribute_methods :content_type, :body
|
38
|
-
|
39
|
-
# @param space_id [String] The space ID (required)
|
40
|
-
# @param content_id [String] The content ID (required)
|
41
|
-
# @param store_id [String] the store ID (optional)
|
42
|
-
# @example
|
43
|
-
# new("myspace", "mycontent.txt")
|
44
|
-
def initialize(space_id, content_id, store_id = nil)
|
45
|
-
@content_id = content_id
|
46
|
-
@space_id = space_id
|
47
|
-
@store_id = store_id
|
48
|
-
@body, @content_type = nil, nil
|
49
|
-
yield self if block_given?
|
50
|
-
end
|
42
|
+
define_attribute_methods :content_type, :body, :md5
|
51
43
|
|
52
44
|
# Return the space associated with this content.
|
53
45
|
# @return [Duracloud::Space] the space.
|
@@ -66,13 +58,15 @@ module Duracloud
|
|
66
58
|
# @raise [Duracloud::NotFoundError] the content does not exist in DuraCloud.
|
67
59
|
def load_body
|
68
60
|
response = Client.get_content(*args, **query)
|
61
|
+
set_md5!(response)
|
69
62
|
@body = response.body # don't use setter b/c marks as dirty
|
70
63
|
persisted!
|
71
64
|
end
|
72
65
|
|
73
66
|
def load_properties
|
74
67
|
super do |response|
|
75
|
-
# don't mark content_type as changed
|
68
|
+
# don't mark content_type or md5 as changed
|
69
|
+
set_md5!(response)
|
76
70
|
@content_type = response.content_type
|
77
71
|
end
|
78
72
|
end
|
@@ -104,8 +98,28 @@ module Duracloud
|
|
104
98
|
@content_type
|
105
99
|
end
|
106
100
|
|
101
|
+
def md5=(val)
|
102
|
+
md5_will_change! unless val == @md5
|
103
|
+
@md5 = val
|
104
|
+
end
|
105
|
+
|
106
|
+
def md5
|
107
|
+
@md5
|
108
|
+
end
|
109
|
+
|
107
110
|
private
|
108
111
|
|
112
|
+
def set_md5!(response)
|
113
|
+
if md5
|
114
|
+
if md5 != response.md5
|
115
|
+
raise MessageDigestError,
|
116
|
+
"Expected MD5 digest (#{md5}) does not match response header: #{response.md5}"
|
117
|
+
end
|
118
|
+
else
|
119
|
+
@md5 = response.md5
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
109
123
|
def io_like?
|
110
124
|
body.respond_to?(:read) && body.respond_to?(:rewind)
|
111
125
|
end
|
@@ -119,7 +133,7 @@ module Duracloud
|
|
119
133
|
|
120
134
|
def store
|
121
135
|
headers = {
|
122
|
-
"Content-MD5" => md5,
|
136
|
+
"Content-MD5" => md5 || calculate_md5,
|
123
137
|
"Content-Type" => content_type || "application/octet-stream"
|
124
138
|
}
|
125
139
|
headers.merge!(properties)
|
@@ -127,7 +141,7 @@ module Duracloud
|
|
127
141
|
Client.store_content(*args, **options)
|
128
142
|
end
|
129
143
|
|
130
|
-
def
|
144
|
+
def calculate_md5
|
131
145
|
digest = Digest::MD5.new
|
132
146
|
if io_like?
|
133
147
|
body.rewind
|
data/lib/duracloud/error.rb
CHANGED
data/lib/duracloud/properties.rb
CHANGED
@@ -25,7 +25,7 @@ module Duracloud
|
|
25
25
|
INTERNAL = /\A#{PREFIX}content-(mimetype|size|checksum|modified)\z/
|
26
26
|
|
27
27
|
# Properties set by the DuraCloud SyncTool
|
28
|
-
SYNCTOOL = /\A#{PREFIX}(creator|(content-file-(created|modified|last-accessed
|
28
|
+
SYNCTOOL = /\A#{PREFIX}(creator|(content-file-(created|modified|last-accessed|path)))\z/
|
29
29
|
|
30
30
|
# Is the property valid for this class of properties?
|
31
31
|
# @note Subclasses should override this method rather than the `#property?'
|
data/lib/duracloud/space.rb
CHANGED
@@ -160,7 +160,7 @@ module Duracloud
|
|
160
160
|
# @return [Duracloud::Content] the content item.
|
161
161
|
# @raise [Duracloud::NotFoundError] if the content item does not exist.
|
162
162
|
def find_content(content_id)
|
163
|
-
Content.find(space_id, content_id, store_id)
|
163
|
+
Content.find(space_id: space_id, content_id: content_id, store_id: store_id)
|
164
164
|
end
|
165
165
|
|
166
166
|
# Return the audit log for the space
|
data/lib/duracloud/version.rb
CHANGED
data/spec/unit/content_spec.rb
CHANGED
@@ -7,31 +7,64 @@ module Duracloud
|
|
7
7
|
describe "when it exists" do
|
8
8
|
before { stub_request(:head, url) }
|
9
9
|
specify {
|
10
|
-
expect(Content.find("foo", "bar")).to be_a(Content)
|
10
|
+
expect(Content.find(space_id: "foo", content_id: "bar")).to be_a(Content)
|
11
11
|
}
|
12
12
|
end
|
13
13
|
describe "when it does not exist" do
|
14
14
|
before { stub_request(:head, url).to_return(status: 404) }
|
15
15
|
specify {
|
16
|
-
expect { Content.find("foo", "bar") }.to raise_error(NotFoundError)
|
16
|
+
expect { Content.find(space_id: "foo", content_id: "bar") }.to raise_error(NotFoundError)
|
17
17
|
}
|
18
18
|
end
|
19
|
+
describe "when providing an MD5" do
|
20
|
+
before do
|
21
|
+
stub_request(:head, url).to_return(headers: {'Content-MD5'=>'foo'})
|
22
|
+
end
|
23
|
+
describe "that is correct" do
|
24
|
+
specify {
|
25
|
+
expect(Content.find(space_id: "foo", content_id: "bar", md5: "foo")).to be_a(Content)
|
26
|
+
}
|
27
|
+
end
|
28
|
+
describe "that is incorrect" do
|
29
|
+
specify {
|
30
|
+
expect { Content.find(space_id: "foo", content_id: "bar", md5: "bar") }.to raise_error(MessageDigestError)
|
31
|
+
}
|
32
|
+
end
|
33
|
+
end
|
19
34
|
end
|
20
35
|
|
21
36
|
describe ".exist?" do
|
22
|
-
subject { Content.exist?("foo", "bar") }
|
23
37
|
describe "when it exists" do
|
24
38
|
before { stub_request(:head, url) }
|
25
|
-
|
39
|
+
specify {
|
40
|
+
expect(Content.exist?(space_id: "foo", content_id: "bar")).to be true
|
41
|
+
}
|
26
42
|
end
|
27
43
|
describe "when it does not exist" do
|
28
44
|
before { stub_request(:head, url).to_return(status: 404) }
|
29
|
-
|
45
|
+
specify {
|
46
|
+
expect(Content.exist?(space_id: "foo", content_id: "bar")).to be false
|
47
|
+
}
|
48
|
+
end
|
49
|
+
describe "when providing an MD5" do
|
50
|
+
before do
|
51
|
+
stub_request(:head, url).to_return(headers: {'Content-MD5'=>'foo'})
|
52
|
+
end
|
53
|
+
describe "that is correct" do
|
54
|
+
specify {
|
55
|
+
expect(Content.exist?(space_id: "foo", content_id: "bar", md5: "foo")).to be true
|
56
|
+
}
|
57
|
+
end
|
58
|
+
describe "that is incorrect" do
|
59
|
+
specify {
|
60
|
+
expect { Content.exist?(space_id: "foo", content_id: "bar", md5: "bar") }.to raise_error(MessageDigestError)
|
61
|
+
}
|
62
|
+
end
|
30
63
|
end
|
31
64
|
end
|
32
65
|
|
33
66
|
describe "#save" do
|
34
|
-
subject { Content.new("foo", "bar") }
|
67
|
+
subject { Content.new(space_id: "foo", content_id: "bar") }
|
35
68
|
describe "when not persisted" do
|
36
69
|
describe "when empty" do
|
37
70
|
it "raises an exception" do
|
@@ -51,7 +84,9 @@ module Duracloud
|
|
51
84
|
end
|
52
85
|
describe "and the space exists" do
|
53
86
|
before {
|
54
|
-
stub_request(:put, url)
|
87
|
+
stub_request(:put, url)
|
88
|
+
.with(body: "Some file content",
|
89
|
+
headers: {"Content-MD5"=>"92bbcf620ceb5f5bf38f08e9a1f31e7b"})
|
55
90
|
.to_return(status: 201)
|
56
91
|
}
|
57
92
|
it "stores the content" do
|
@@ -68,7 +103,9 @@ module Duracloud
|
|
68
103
|
}
|
69
104
|
describe "and the body has changed" do
|
70
105
|
before {
|
71
|
-
stub_request(:put, url)
|
106
|
+
stub_request(:put, url)
|
107
|
+
.with(body: "Some file content",
|
108
|
+
headers: {"Content-MD5"=>"92bbcf620ceb5f5bf38f08e9a1f31e7b"})
|
72
109
|
.to_return(status: 201)
|
73
110
|
}
|
74
111
|
it "stores the content" do
|
@@ -91,10 +128,12 @@ module Duracloud
|
|
91
128
|
describe "when the body is a file" do
|
92
129
|
let(:path) { File.expand_path('../../fixtures/lorem_ipsum.txt', __FILE__) }
|
93
130
|
let(:file) { File.new(path, "rb") }
|
94
|
-
before
|
95
|
-
stub_request(:put, url)
|
131
|
+
before do
|
132
|
+
stub_request(:put, url)
|
133
|
+
.with(body: File.read(path),
|
134
|
+
headers: {"Content-MD5"=>"039d7100bea9ef2efbe151db953726ce"})
|
96
135
|
.to_return(status: 201)
|
97
|
-
|
136
|
+
end
|
98
137
|
it "stores the file content" do
|
99
138
|
subject.body = file
|
100
139
|
subject.save
|
@@ -103,7 +142,7 @@ module Duracloud
|
|
103
142
|
end
|
104
143
|
|
105
144
|
describe "#delete" do
|
106
|
-
subject { Content.new("foo", "bar") }
|
145
|
+
subject { Content.new(space_id: "foo", content_id: "bar") }
|
107
146
|
describe "when not found" do
|
108
147
|
before { stub_request(:delete, url).to_return(status: 404) }
|
109
148
|
it "raises an exception" do
|
@@ -124,11 +163,12 @@ module Duracloud
|
|
124
163
|
allow(Client).to receive(:get_content_properties)
|
125
164
|
.with("foo", "bar", hash_including(storeID: nil)) {
|
126
165
|
double(headers: {'x-dura-meta-creator'=>'testuser'},
|
127
|
-
content_type: 'text/plain'
|
166
|
+
content_type: 'text/plain',
|
167
|
+
md5: '08a008a01d498c404b0c30852b39d3b8')
|
128
168
|
}
|
129
169
|
}
|
130
170
|
specify {
|
131
|
-
content = Content.find("foo", "bar")
|
171
|
+
content = Content.find(space_id: "foo", content_id: "bar")
|
132
172
|
expect(content.properties.x_dura_meta_creator).to eq('testuser')
|
133
173
|
}
|
134
174
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: duracloud-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Chandek-Stark
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-01-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hashie
|
@@ -42,16 +42,22 @@ dependencies:
|
|
42
42
|
name: activemodel
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '4.2'
|
48
|
+
- - "<"
|
46
49
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
50
|
+
version: '6'
|
48
51
|
type: :runtime
|
49
52
|
prerelease: false
|
50
53
|
version_requirements: !ruby/object:Gem::Requirement
|
51
54
|
requirements:
|
52
|
-
- - "
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '4.2'
|
58
|
+
- - "<"
|
53
59
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
60
|
+
version: '6'
|
55
61
|
- !ruby/object:Gem::Dependency
|
56
62
|
name: nokogiri
|
57
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -151,8 +157,8 @@ files:
|
|
151
157
|
- README.md
|
152
158
|
- Rakefile
|
153
159
|
- duracloud.gemspec
|
154
|
-
- gemfiles/Gemfile.activemodel-4.1
|
155
160
|
- gemfiles/Gemfile.activemodel-4.2
|
161
|
+
- gemfiles/Gemfile.activemodel-5.0
|
156
162
|
- lib/duracloud-client.rb
|
157
163
|
- lib/duracloud.rb
|
158
164
|
- lib/duracloud/audit_log.rb
|
@@ -204,7 +210,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
204
210
|
requirements:
|
205
211
|
- - ">="
|
206
212
|
- !ruby/object:Gem::Version
|
207
|
-
version: '2.
|
213
|
+
version: '2.2'
|
208
214
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
209
215
|
requirements:
|
210
216
|
- - ">="
|
@@ -212,7 +218,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
212
218
|
version: '0'
|
213
219
|
requirements: []
|
214
220
|
rubyforge_project:
|
215
|
-
rubygems_version: 2.
|
221
|
+
rubygems_version: 2.6.8
|
216
222
|
signing_key:
|
217
223
|
specification_version: 4
|
218
224
|
summary: Ruby client for communicating with DuraCloud
|