duracloud-client 0.6.0 → 0.7.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
  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