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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7ea05804282811db4ddae6b49a04e87f30f3eec7
4
- data.tar.gz: 8ab80ee402b9ff8f17dde4e6aeb445af13af77d0
3
+ metadata.gz: 37ba6ce5cc5015994ed96ce7d5fc1ad987b5ef96
4
+ data.tar.gz: 34d6471b5dbc0a84b65c06f8c2604f7e3c5b0f88
5
5
  SHA512:
6
- metadata.gz: 0b67d6ac687c02438b8814b54ba3b2eec6e84ce1db77370aacd76789e8f22298af0370eda6a666dfc392533515db25608d4490d99819fa0ac8afc1203e823030
7
- data.tar.gz: b832eed79711148ef5a0ab4be82d6f7d29186138ef66c403b3b99b71ca504e7f55975f840ee9fc64451848f6876629a182058ee155e165270eace05feb3da711
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.creator = "bob@example.com"
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.creator
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 ||= properties_class.new
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
- filtered = props ? properties_class.filter(props) : props
80
- @properties = properties_class.new(filtered)
79
+ @properties = Properties.new(props)
81
80
  end
82
81
 
83
82
  def reset_properties
@@ -34,6 +34,7 @@ module Duracloud
34
34
  self.properties = manifest.properties.dup
35
35
  self.content_type = manifest.source.content_type
36
36
  self.size = manifest.source.size
37
+ self.modified = manifest.content.modified
37
38
  end
38
39
 
39
40
  end
@@ -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
@@ -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
- # Space properties
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
- duracloud_property?(prop)
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
- # Is the property a space property?
62
- # @param prop [String] the property name
63
- # @return [Boolean]
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(duracloud_property!(super))
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
@@ -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
@@ -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.space_count.to_i
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
- if space_created = properties.space_created
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
@@ -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
- update filter(response.headers)
15
+ super(response.headers)
16
+ else
17
+ super()
21
18
  end
22
19
  end
23
20
 
@@ -1,3 +1,3 @@
1
1
  module Duracloud
2
- VERSION = "0.6.0"
2
+ VERSION = "0.7.0"
3
3
  end
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"
@@ -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 { stub_request(:head, url) }
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.creator = "testuser"
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
- expect(content.properties.x_dura_meta_creator).to eq('testuser')
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 ".filter"
5
- describe ".property?"
6
- describe ".duraspace_property?"
7
- describe ".internal_property?"
8
- describe ".space_property?"
9
- describe ".space_acl?"
10
- describe ".copy_content_property?"
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
@@ -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
- allow(Client).to receive(:get_space)
127
- .with("foo", hash_including(storeID: nil)) {
128
- double(body: body,
129
- headers: {
130
- 'x-dura-meta-space-count'=>'3',
131
- 'x-dura-meta-space-created'=>'2016-04-05T17:59:11'
132
- })
133
- }
134
- allow(Client).to receive(:get_space_properties)
135
- .with("foo", hash_including(storeID: nil)) {
136
- double(body: "",
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.6.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-06-29 00:00:00.000000000 Z
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
@@ -1,7 +0,0 @@
1
- module Duracloud
2
- class ContentProperties < Properties
3
- def self.property?(prop)
4
- super && !( space_property?(prop) || space_acl?(prop) || copy_content_property?(prop) )
5
- end
6
- end
7
- end
@@ -1,9 +0,0 @@
1
- require "date"
2
-
3
- module Duracloud
4
- class SpaceProperties < Properties
5
- def self.property?(prop)
6
- space_property?(prop)
7
- end
8
- end
9
- end