duracloud-client 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/lib/duracloud/abstract_entity.rb +2 -3
- data/lib/duracloud/chunked_content.rb +1 -0
- data/lib/duracloud/content.rb +2 -1
- data/lib/duracloud/properties.rb +7 -95
- data/lib/duracloud/response.rb +5 -0
- data/lib/duracloud/space.rb +6 -4
- data/lib/duracloud/space_acls.rb +3 -6
- data/lib/duracloud/version.rb +1 -1
- data/lib/duracloud.rb +0 -2
- data/spec/spec_helper.rb +12 -0
- data/spec/unit/content_spec.rb +20 -4
- data/spec/unit/properties_spec.rb +9 -7
- data/spec/unit/space_spec.rb +17 -16
- metadata +2 -4
- data/lib/duracloud/content_properties.rb +0 -7
- data/lib/duracloud/space_properties.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 37ba6ce5cc5015994ed96ce7d5fc1ad987b5ef96
|
4
|
+
data.tar.gz: 34d6471b5dbc0a84b65c06f8c2604f7e3c5b0f88
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 239504e09b5efb3d8db2e46afd0d24d935dcd8258c67ab996b302946ba9bb3a1322f6f385864e1f955be4d073a0790e8fd57202f6a788c7b6303189c7a137c23
|
7
|
+
data.tar.gz: 85b33cbfb16b8f4529fb88b6120904929407fe5532c7699c0a4a350d51fc9dcf9c645a7e1d25ec31eea399dd569de3cfd07339a4751ad51c22ba29fdce2e92bb
|
data/README.md
CHANGED
@@ -192,13 +192,13 @@ D, [2016-04-29T18:31:16.975749 #32379] DEBUG -- : Duracloud::Client HEAD https:/
|
|
192
192
|
>> content.properties
|
193
193
|
=> #<Duracloud::ContentProperties x-dura-meta-owner="ellen@example.com">
|
194
194
|
|
195
|
-
>> content.properties
|
195
|
+
>> content.properties["x-dura-meta-creator"] = "bob@example.com"
|
196
196
|
>> content.save
|
197
197
|
D, [2016-04-29T18:31:52.770195 #32379] DEBUG -- : Duracloud::Client POST https://foo.duracloud.org/durastore/rest-api-testing/foo3 200 OK
|
198
198
|
I, [2016-04-29T18:31:52.770293 #32379] INFO -- : Content foo3 updated successfully
|
199
199
|
=> true
|
200
200
|
|
201
|
-
>> content.properties
|
201
|
+
>> content.properties["x-dura-meta-creator"]
|
202
202
|
D, [2016-04-29T18:32:06.465928 #32379] DEBUG -- : Duracloud::Client HEAD https://foo.duracloud.org/durastore/rest-api-testing/foo3 200 OK
|
203
203
|
=> "bob@example.com"
|
204
204
|
```
|
@@ -42,7 +42,7 @@ module Duracloud
|
|
42
42
|
# but does not exist in Duracloud
|
43
43
|
def properties
|
44
44
|
load_properties if persisted? && @properties.nil?
|
45
|
-
@properties ||=
|
45
|
+
@properties ||= Properties.new
|
46
46
|
end
|
47
47
|
|
48
48
|
|
@@ -76,8 +76,7 @@ module Duracloud
|
|
76
76
|
end
|
77
77
|
|
78
78
|
def properties=(props)
|
79
|
-
|
80
|
-
@properties = properties_class.new(filtered)
|
79
|
+
@properties = Properties.new(props)
|
81
80
|
end
|
82
81
|
|
83
82
|
def reset_properties
|
data/lib/duracloud/content.rb
CHANGED
@@ -46,7 +46,7 @@ module Duracloud
|
|
46
46
|
end
|
47
47
|
|
48
48
|
attr_accessor :space_id, :content_id, :store_id,
|
49
|
-
:body, :md5, :content_type, :size
|
49
|
+
:body, :md5, :content_type, :size, :modified
|
50
50
|
alias_method :id, :content_id
|
51
51
|
validates_presence_of :space_id, :content_id
|
52
52
|
|
@@ -168,6 +168,7 @@ module Duracloud
|
|
168
168
|
self.properties = response.headers
|
169
169
|
self.content_type = response.content_type
|
170
170
|
self.size = response.size
|
171
|
+
self.modified = response.modified
|
171
172
|
end
|
172
173
|
|
173
174
|
def do_delete
|
data/lib/duracloud/properties.rb
CHANGED
@@ -6,109 +6,30 @@ module Duracloud
|
|
6
6
|
#
|
7
7
|
# Encapsulates Duracloud "properties" which are transmitted via HTTP headers.
|
8
8
|
#
|
9
|
-
# @abstract
|
10
|
-
#
|
11
9
|
class Properties < Hashie::Mash
|
12
10
|
|
13
11
|
PREFIX = "x-dura-meta-".freeze
|
12
|
+
PREFIX_RE = /\A#{PREFIX}/i
|
14
13
|
|
15
|
-
#
|
16
|
-
SPACE = /\A#{PREFIX}space-(count|created)\z/
|
17
|
-
|
18
|
-
# Space ACL headers
|
19
|
-
SPACE_ACLS = /\A#{PREFIX}acl-/
|
20
|
-
|
21
|
-
# Copy Content headers
|
22
|
-
COPY_CONTENT = /\A#{PREFIX}copy-source(-store)?\z/
|
23
|
-
|
24
|
-
# DuraCloud internal content properties
|
25
|
-
INTERNAL = /\A#{PREFIX}content-(mimetype|size|checksum|modified)\z/
|
26
|
-
|
27
|
-
# Properties set by the DuraCloud SyncTool
|
28
|
-
SYNCTOOL = /\A#{PREFIX}(creator|(content-file-(created|modified|last-accessed|path)))\z/
|
29
|
-
|
30
|
-
# Is the property valid for this class of properties?
|
31
|
-
# @note Subclasses should override this method rather than the `#property?'
|
32
|
-
# instance method.
|
14
|
+
# Is the property name valid?
|
33
15
|
# @param prop [String] the property name
|
34
16
|
# @return [Boolean]
|
35
17
|
def self.property?(prop)
|
36
|
-
|
37
|
-
end
|
38
|
-
|
39
|
-
# Filter the hash of properties, selecting only the properties valid
|
40
|
-
# for this particular usage (subclass).
|
41
|
-
# @param hsh [Hash] the unfiltered properties
|
42
|
-
# @return [Hash] the filtered properties
|
43
|
-
def self.filter(hsh)
|
44
|
-
hsh.select { |k, v| property?(k) }
|
45
|
-
end
|
46
|
-
|
47
|
-
# Is the property a (theoretically) valid DuraCloud property?
|
48
|
-
# @param prop [String] the property name
|
49
|
-
# @return [Boolean]
|
50
|
-
def self.duracloud_property?(prop)
|
51
|
-
prop.start_with?(PREFIX)
|
52
|
-
end
|
53
|
-
|
54
|
-
# Is the property a reserved "internal" DuraCloud property?
|
55
|
-
# @param prop [String] the property name
|
56
|
-
# @return [Boolean]
|
57
|
-
def self.internal_property?(prop)
|
58
|
-
INTERNAL =~ prop
|
18
|
+
!!( PREFIX_RE =~ prop.to_s )
|
59
19
|
end
|
60
20
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
def self.space_property?(prop)
|
65
|
-
SPACE =~ prop
|
21
|
+
def initialize(source = nil, default = nil, &block)
|
22
|
+
source.select! { |k, v| property?(k) } if source
|
23
|
+
super
|
66
24
|
end
|
67
25
|
|
68
|
-
# Is the property a space ACL?
|
69
|
-
# @param prop [String] the property name
|
70
|
-
# @return [Boolean]
|
71
|
-
def self.space_acl?(prop)
|
72
|
-
SPACE_ACLS =~ prop
|
73
|
-
end
|
74
|
-
|
75
|
-
# Is the property used for copying content?
|
76
|
-
# @param prop [String] the property name
|
77
|
-
# @return [Boolean]
|
78
|
-
def self.copy_content_property?(prop)
|
79
|
-
COPY_CONTENT =~ prop
|
80
|
-
end
|
81
|
-
|
82
|
-
# Is the property valid for this class of properties?
|
83
|
-
# @note Subclasses should not override this method, but instead
|
84
|
-
# override the `.property?' class method.
|
85
|
-
# @param prop [String] the property name
|
86
|
-
# @return [Boolean]
|
87
|
-
# @api private
|
88
26
|
def property?(prop)
|
89
27
|
self.class.property?(prop)
|
90
28
|
end
|
91
29
|
|
92
|
-
# Filter the hash of properties, selecting only the properties valid
|
93
|
-
# for this particular usage (subclass).
|
94
|
-
# @param hsh [Hash] the unfiltered properties
|
95
|
-
# @return [Hash] the filtered properties
|
96
|
-
def filter(hsh)
|
97
|
-
self.class.filter(hsh)
|
98
|
-
end
|
99
|
-
|
100
|
-
# @api private
|
101
|
-
def regular_writer(key, value)
|
102
|
-
if property?(key)
|
103
|
-
super
|
104
|
-
else
|
105
|
-
raise Error, "#{self.class}: Unrecognized or restricted property \"#{key}\"."
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
30
|
# @api private
|
110
31
|
def convert_key(key)
|
111
|
-
force_ascii(
|
32
|
+
force_ascii(key)
|
112
33
|
end
|
113
34
|
|
114
35
|
# @api private
|
@@ -127,15 +48,6 @@ module Duracloud
|
|
127
48
|
|
128
49
|
private
|
129
50
|
|
130
|
-
# Coerce to a DuraCloud property
|
131
|
-
def duracloud_property!(prop)
|
132
|
-
prop.dup.tap do |p|
|
133
|
-
p.gsub!(/_/, '-')
|
134
|
-
p.downcase!
|
135
|
-
p.prepend(PREFIX) unless self.class.duracloud_property?(p)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
51
|
def convert_array(value)
|
140
52
|
value.uniq!
|
141
53
|
if value.length > 1
|
data/lib/duracloud/response.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "forwardable"
|
2
|
+
require "date"
|
2
3
|
|
3
4
|
module Duracloud
|
4
5
|
class Response
|
@@ -43,5 +44,9 @@ module Duracloud
|
|
43
44
|
def size
|
44
45
|
header["content-length"].first.to_i rescue nil
|
45
46
|
end
|
47
|
+
|
48
|
+
def modified
|
49
|
+
DateTime.parse(header["last-modified"].first) rescue nil
|
50
|
+
end
|
46
51
|
end
|
47
52
|
end
|
data/lib/duracloud/space.rb
CHANGED
@@ -141,16 +141,18 @@ module Duracloud
|
|
141
141
|
|
142
142
|
# Return the number of items in the space
|
143
143
|
# @return [Fixnum] the number of items
|
144
|
+
# @note If the count is over 1000, DuraCloud sets the
|
145
|
+
# x-dura-meta-space-count header to "1000+".
|
146
|
+
# This method will in that case return 1000, indicating
|
147
|
+
# that the exact count must be retrieved by other means.
|
144
148
|
def count
|
145
|
-
properties.
|
149
|
+
properties["x-dura-meta-space-count"].to_i
|
146
150
|
end
|
147
151
|
|
148
152
|
# Return the creation date of the space, if persisted, or nil.
|
149
153
|
# @return [DateTime] the date
|
150
154
|
def created
|
151
|
-
|
152
|
-
DateTime.parse(space_created)
|
153
|
-
end
|
155
|
+
DateTime.parse(properties["x-dura-meta-space-created"]) rescue nil
|
154
156
|
end
|
155
157
|
|
156
158
|
# Find a content item in the space
|
data/lib/duracloud/space_acls.rb
CHANGED
@@ -6,18 +6,15 @@ module Duracloud
|
|
6
6
|
|
7
7
|
ACL_PREFIX = (PREFIX + "acl-").freeze
|
8
8
|
|
9
|
-
def self.property?(prop)
|
10
|
-
space_acl?(prop)
|
11
|
-
end
|
12
|
-
|
13
9
|
attr_reader :space
|
14
10
|
|
15
11
|
def initialize(space)
|
16
|
-
super()
|
17
12
|
@space = space
|
18
13
|
if space.persisted?
|
19
14
|
response = Client.get_space_acls(space.space_id, **query)
|
20
|
-
|
15
|
+
super(response.headers)
|
16
|
+
else
|
17
|
+
super()
|
21
18
|
end
|
22
19
|
end
|
23
20
|
|
data/lib/duracloud/version.rb
CHANGED
data/lib/duracloud.rb
CHANGED
@@ -13,7 +13,6 @@ module Duracloud
|
|
13
13
|
autoload :Connection, "duracloud/connection"
|
14
14
|
autoload :Content, "duracloud/content"
|
15
15
|
autoload :ContentManifest, "duracloud/content_manifest"
|
16
|
-
autoload :ContentProperties, "duracloud/content_properties"
|
17
16
|
autoload :DurastoreRequest, "duracloud/durastore_request"
|
18
17
|
autoload :ErrorHandler, "duracloud/error_handler"
|
19
18
|
autoload :HasProperties, "duracloud/has_properties"
|
@@ -25,7 +24,6 @@ module Duracloud
|
|
25
24
|
autoload :RestMethods, "duracloud/rest_methods"
|
26
25
|
autoload :Space, "duracloud/space"
|
27
26
|
autoload :SpaceAcls, "duracloud/space_acls"
|
28
|
-
autoload :SpaceProperties, "duracloud/space_properties"
|
29
27
|
autoload :Store, "duracloud/store"
|
30
28
|
autoload :SyncValidation, "duracloud/sync_validation"
|
31
29
|
autoload :TSV, "duracloud/tsv"
|
data/spec/spec_helper.rb
CHANGED
@@ -4,6 +4,18 @@ require "webmock/rspec"
|
|
4
4
|
|
5
5
|
WebMock.disable_net_connect!(allow_localhost: true)
|
6
6
|
|
7
|
+
# Monkey-patches WebMock to not alter header names
|
8
|
+
WebMock::Util::Headers.class_eval do
|
9
|
+
def self.normalize_headers(headers)
|
10
|
+
return nil unless headers
|
11
|
+
headers.each do |name, value|
|
12
|
+
if value.is_a?(Array) && value.size == 1
|
13
|
+
headers[name] = value.first
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
7
19
|
Duracloud::Client.configure do |config|
|
8
20
|
config.host = "example.com"
|
9
21
|
config.user = "testuser"
|
data/spec/unit/content_spec.rb
CHANGED
@@ -8,21 +8,37 @@ module Duracloud
|
|
8
8
|
describe "when it exists" do
|
9
9
|
subject { described_class.find(space_id: "foo", content_id: "bar") }
|
10
10
|
describe "and it is not chunked" do
|
11
|
-
before {
|
11
|
+
before {
|
12
|
+
stub_request(:head, url)
|
13
|
+
.to_return(headers: {
|
14
|
+
"Content-MD5"=>"164e9aee34c0c42915716e11d5d539b5",
|
15
|
+
"Content-Length"=>"1811970",
|
16
|
+
"Content-Type"=>"image/jpeg",
|
17
|
+
"Last-Modified"=>"2017-06-12T17:36:58",
|
18
|
+
})
|
19
|
+
}
|
12
20
|
it { is_expected.to be_a described_class }
|
13
21
|
it { is_expected.to_not be_chunked }
|
22
|
+
its(:md5) { is_expected.to eq "164e9aee34c0c42915716e11d5d539b5" }
|
23
|
+
its(:size) { is_expected.to eq 1811970 }
|
24
|
+
its(:content_type) { is_expected.to eq "image/jpeg" }
|
25
|
+
its(:modified) { is_expected.to eq DateTime.parse("2017-06-12T17:36:58") }
|
14
26
|
end
|
15
27
|
describe "and it is chunked" do
|
16
28
|
let(:manifest_xml) { File.read(File.expand_path("../../fixtures/content_manifest.xml", __FILE__)) }
|
17
29
|
before do
|
18
30
|
stub_request(:head, url).to_return(status: 404)
|
19
31
|
stub_request(:head, manifest_url)
|
32
|
+
.to_return(headers: {
|
33
|
+
"Last-Modified"=>"2017-06-26T16:38:42",
|
34
|
+
})
|
20
35
|
stub_request(:get, manifest_url).to_return(body: manifest_xml)
|
21
36
|
end
|
22
37
|
it { is_expected.to be_a described_class }
|
23
38
|
its(:md5) { is_expected.to eq "164e9aee34c0c42915716e11d5d539b5" }
|
24
39
|
its(:size) { is_expected.to eq 4227858432 }
|
25
40
|
its(:content_type) { is_expected.to eq "application/octet-stream" }
|
41
|
+
its(:modified) { is_expected.to eq DateTime.parse("2017-06-26T16:38:42") }
|
26
42
|
it { is_expected.to be_chunked }
|
27
43
|
end
|
28
44
|
end
|
@@ -153,7 +169,7 @@ module Duracloud
|
|
153
169
|
.with(headers: {'x-dura-meta-creator'=>'testuser'})
|
154
170
|
}
|
155
171
|
it "updates the properties" do
|
156
|
-
subject.properties
|
172
|
+
subject.properties["x-dura-meta-creator"] = "testuser"
|
157
173
|
subject.save
|
158
174
|
end
|
159
175
|
end
|
@@ -199,9 +215,9 @@ module Duracloud
|
|
199
215
|
'Content-MD5'=>'08a008a01d498c404b0c30852b39d3b8'})
|
200
216
|
end
|
201
217
|
specify {
|
202
|
-
pending "Research Webmock problem with return headers"
|
203
218
|
content = Content.find(space_id: "foo", content_id: "bar")
|
204
|
-
|
219
|
+
puts content.properties.to_h
|
220
|
+
expect(content.properties["x-dura-meta-creator"]).to eq('testuser')
|
205
221
|
}
|
206
222
|
end
|
207
223
|
|
@@ -1,13 +1,15 @@
|
|
1
1
|
module Duracloud
|
2
2
|
RSpec.describe Properties do
|
3
3
|
|
4
|
-
describe "
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
describe "
|
10
|
-
|
4
|
+
describe "ignores non-DuraCloud keys" do
|
5
|
+
subject { described_class.new("access-control-allow-headers"=>"Content-Type, Authorization", "access-control-allow-methods"=>"GET, POST, PUT, DELETE", "access-control-allow-origin"=>"*", "cache-control"=>"no-cache=\"set-cookie\"", "content-type"=>"application/octet-stream", "date"=>"Wed, 12 Jul 2017 14:52:41 GMT", "expires"=>"0", "pragma"=>"no-cache", "server"=>"Apache-Coyote/1.1", "strict-transport-security"=>"max-age=31536000 ; includeSubDomains", "vary"=>"Accept-Encoding", "x-content-type-options"=>"nosniff", "x-dura-meta-space-count"=>"1000+", "x-dura-meta-space-created"=>"2017-07-06T20:35:39", "x-frame-options"=>"DENY", "x-xss-protection"=>"1; mode=block", "connection"=>"keep-alive") }
|
6
|
+
its(:to_h) { is_expected.to eq({"x-dura-meta-space-count"=>"1000+", "x-dura-meta-space-created"=>"2017-07-06T20:35:39"}) }
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "preserves original keys" do
|
10
|
+
subject { described_class.new("x-dura-meta-acl-foo_bar"=>"READ", "x-dura-meta-acl-group-spam-eggs"=>"WRITE") }
|
11
|
+
its(:to_h) { is_expected.to eq({"x-dura-meta-acl-foo_bar"=>"READ", "x-dura-meta-acl-group-spam-eggs"=>"WRITE"}) }
|
12
|
+
end
|
11
13
|
|
12
14
|
end
|
13
15
|
end
|
data/spec/unit/space_spec.rb
CHANGED
@@ -52,9 +52,15 @@ EOS
|
|
52
52
|
describe "when found" do
|
53
53
|
before {
|
54
54
|
stub_request(:head, url)
|
55
|
+
.to_return(headers: {
|
56
|
+
"x-dura-meta-space-count"=>"1000+",
|
57
|
+
"x-dura-meta-space-created"=>"2017-05-18T20:03:18",
|
58
|
+
})
|
55
59
|
}
|
56
60
|
it { is_expected.to be_a(Space) }
|
57
61
|
its(:space_id) { is_expected.to eq("foo") }
|
62
|
+
its(:count) { is_expected.to eq 1000 }
|
63
|
+
its(:created) { is_expected.to eq DateTime.parse("2017-05-18T20:03:18") }
|
58
64
|
end
|
59
65
|
describe "when not found" do
|
60
66
|
before {
|
@@ -123,22 +129,17 @@ EOS
|
|
123
129
|
stub_request(:head, "#{url}/foo1")
|
124
130
|
stub_request(:head, "#{url}/foo2")
|
125
131
|
stub_request(:head, "#{url}/foo3")
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
headers: {
|
138
|
-
'x-dura-meta-space-count'=>'3',
|
139
|
-
'x-dura-meta-space-created'=>'2016-04-05T17:59:11'
|
140
|
-
})
|
141
|
-
}
|
132
|
+
stub_request(:get, "#{url}?maxResults=1000")
|
133
|
+
.to_return(body: body,
|
134
|
+
headers: {
|
135
|
+
'X-Dura-Meta-Space-Count'=>'3',
|
136
|
+
'X-Dura-Meta-Space-Created'=>'2016-04-05T17:59:11'
|
137
|
+
})
|
138
|
+
stub_request(:head, url)
|
139
|
+
.to_return(headers: {
|
140
|
+
'x-dura-meta-space-count'=>'3',
|
141
|
+
'x-dura-meta-space-created'=>'2016-04-05T17:59:11'
|
142
|
+
})
|
142
143
|
}
|
143
144
|
describe "class methods" do
|
144
145
|
specify {
|
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.7.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: 2017-
|
11
|
+
date: 2017-07-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hashie
|
@@ -174,7 +174,6 @@ files:
|
|
174
174
|
- lib/duracloud/connection.rb
|
175
175
|
- lib/duracloud/content.rb
|
176
176
|
- lib/duracloud/content_manifest.rb
|
177
|
-
- lib/duracloud/content_properties.rb
|
178
177
|
- lib/duracloud/durastore_request.rb
|
179
178
|
- lib/duracloud/error.rb
|
180
179
|
- lib/duracloud/error_handler.rb
|
@@ -185,7 +184,6 @@ files:
|
|
185
184
|
- lib/duracloud/rest_methods.rb
|
186
185
|
- lib/duracloud/space.rb
|
187
186
|
- lib/duracloud/space_acls.rb
|
188
|
-
- lib/duracloud/space_properties.rb
|
189
187
|
- lib/duracloud/store.rb
|
190
188
|
- lib/duracloud/sync_validation.rb
|
191
189
|
- lib/duracloud/tsv.rb
|