duracloud-client 0.1.5 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|