rubydora 1.6.5 → 1.7.0.pre1
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/.mailmap +8 -0
- data/CONTRIBUTING.md +113 -0
- data/LICENSE.txt +19 -20
- data/Notices.txt +20 -0
- data/README.rdoc +1 -0
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/gemfiles/gemfile.rails4 +1 -1
- data/lib/rubydora/audit_trail.rb +5 -5
- data/lib/rubydora/datastream.rb +9 -53
- data/lib/rubydora/digital_object.rb +12 -47
- data/lib/rubydora/fc3_service.rb +89 -0
- data/lib/rubydora/fedora_url_helpers.rb +3 -3
- data/lib/rubydora/profile_parser.rb +59 -0
- data/lib/rubydora/repository.rb +20 -34
- data/lib/rubydora/transactions.rb +7 -6
- data/lib/rubydora.rb +2 -0
- data/rubydora.gemspec +0 -1
- data/spec/audit_trail_spec.rb +1 -1
- data/spec/lib/datastream_spec.rb +15 -15
- data/spec/lib/digital_object_spec.rb +37 -37
- data/spec/lib/repository_spec.rb +7 -7
- data/spec/lib/resource_index_spec.rb +2 -2
- data/spec/lib/rest_api_client_spec.rb +2 -2
- data/spec/lib/transactions_spec.rb +7 -8
- metadata +10 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 45b4d25db052316594178dbd272d7f2b44921a37
|
4
|
+
data.tar.gz: de34dc7083ffbd0fec40674678b02c02581de09d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c6d46cfe5791cfaab430456e7b3f1d2ec464101977366f9eb420fb1c5714a27783cebfe8e1beddd1e0036d8b938c73f7e92beb5f01b9b1db422a4d7f5d14c64
|
7
|
+
data.tar.gz: 796237a546a1f1a5555805ad5aab80f9888607ceb35df79c2035d63ddaac0aaad08ea1dcadd83c5eec361b2c6efdf9111b1c9dc57141c0195c581fe42fe93960
|
data/.mailmap
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
Mark Bussey <mark@curationexperts.com> mark-dce <mark@curationexperts.com>
|
2
|
+
Andrew Myers <andrew_myers@wgbh.org> afred <afredmyers@gmail.com>
|
3
|
+
Chris Beer <chris@cbeer.info> <chris@cbeer.info>
|
4
|
+
Chris Beer <chris@cbeer.info> <cabeer@stanford.edu>
|
5
|
+
Chris Beer <chris@cbeer.info> <chris_beer@wgbh.org>
|
6
|
+
Justin Coyne <justin@curationexperts.com> <justin.coyne@yourmediashelf.com>
|
7
|
+
Justin Coyne <justin@curationexperts.com> <digger250@gmail.com>
|
8
|
+
David Chandek-Stark <dchandekstark@gmail.com>
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
# How to Contribute
|
2
|
+
|
3
|
+
We want your help to make Project Hydra great.
|
4
|
+
There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things.
|
5
|
+
|
6
|
+
## Hydra Project Intellectual Property Licensing and Ownership
|
7
|
+
|
8
|
+
All code contributors must have an Individual Contributor License Agreement (iCLA) on file with the Hydra Project Steering Group.
|
9
|
+
If the contributor works for an institution, the institution must have a Corporate Contributor License Agreement (cCLA) on file.
|
10
|
+
|
11
|
+
https://wiki.duraspace.org/display/hydra/Hydra+Project+Intellectual+Property+Licensing+and+Ownership
|
12
|
+
|
13
|
+
You should also add yourself to the `CONTRIBUTORS.md` file in the root of the project.
|
14
|
+
|
15
|
+
## Contribution Tasks
|
16
|
+
|
17
|
+
* Reporting Issues
|
18
|
+
* Making Changes
|
19
|
+
* Submitting Changes
|
20
|
+
* Merging Changes
|
21
|
+
|
22
|
+
### Reporting Issues
|
23
|
+
|
24
|
+
* Make sure you have a [GitHub account](https://github.com/signup/free)
|
25
|
+
* Submit a [Github issue](./issues) by:
|
26
|
+
* Clearly describing the issue
|
27
|
+
* Provide a descriptive summary
|
28
|
+
* Explain the expected behavior
|
29
|
+
* Explain the actual behavior
|
30
|
+
* Provide steps to reproduce the actual behavior
|
31
|
+
|
32
|
+
### Making Changes
|
33
|
+
|
34
|
+
* Fork the repository on GitHub
|
35
|
+
* Create a topic branch from where you want to base your work.
|
36
|
+
* This is usually the master branch.
|
37
|
+
* To quickly create a topic branch based on master; `git branch fix/master/my_contribution master`
|
38
|
+
* Then checkout the new branch with `git checkout fix/master/my_contribution`.
|
39
|
+
* Please avoid working directly on the `master` branch.
|
40
|
+
* You may find the [hub suite of commands](https://github.com/defunkt/hub) helpful
|
41
|
+
* Make commits of logical units.
|
42
|
+
* Your commit should include a high level description of your work in HISTORY.textile
|
43
|
+
* Check for unnecessary whitespace with `git diff --check` before committing.
|
44
|
+
* Make sure your commit messages are [well formed](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
|
45
|
+
* If you created an issue, you can close it by including "Closes #issue" in your commit message. See [Github's blog post for more details](https://github.com/blog/1386-closing-issues-via-commit-messages)
|
46
|
+
|
47
|
+
```
|
48
|
+
Present tense short summary (50 characters or less)
|
49
|
+
|
50
|
+
More detailed description, if necessary. It should be wrapped to 72
|
51
|
+
characters. Try to be as descriptive as you can, even if you think that
|
52
|
+
the commit content is obvious, it may not be obvious to others. You
|
53
|
+
should add such description also if it's already present in bug tracker,
|
54
|
+
it should not be necessary to visit a webpage to check the history.
|
55
|
+
|
56
|
+
Include Closes #<issue-number> when relavent.
|
57
|
+
|
58
|
+
Description can have multiple paragraphs and you can use code examples
|
59
|
+
inside, just indent it with 4 spaces:
|
60
|
+
|
61
|
+
class PostsController
|
62
|
+
def index
|
63
|
+
respond_with Post.limit(10)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
You can also add bullet points:
|
68
|
+
|
69
|
+
- you can use dashes or asterisks
|
70
|
+
|
71
|
+
- also, try to indent next line of a point for readability, if it's too
|
72
|
+
long to fit in 72 characters
|
73
|
+
```
|
74
|
+
|
75
|
+
* Make sure you have added the necessary tests for your changes.
|
76
|
+
* Run _all_ the tests to assure nothing else was accidentally broken.
|
77
|
+
* When you are ready to submit a pull request
|
78
|
+
|
79
|
+
### Submitting Changes
|
80
|
+
|
81
|
+
[Detailed Walkthrough of One Pull Request per Commit](http://ndlib.github.io/practices/one-commit-per-pull-request/)
|
82
|
+
|
83
|
+
* Read the article ["Using Pull Requests"](https://help.github.com/articles/using-pull-requests) on GitHub.
|
84
|
+
* Make sure your branch is up to date with its parent branch (i.e. master)
|
85
|
+
* `git checkout master`
|
86
|
+
* `git pull --rebase`
|
87
|
+
* `git checkout <your-branch>`
|
88
|
+
* `git rebase master`
|
89
|
+
* It is likely a good idea to run your tests again.
|
90
|
+
* Squash the commits for your branch into one commit
|
91
|
+
* `git rebase --interactive HEAD~<number-of-commits>` ([See Github help](https://help.github.com/articles/interactive-rebase))
|
92
|
+
* To determine the number of commits on your branch: `git log master..<your-branch> --oneline | wc -l`
|
93
|
+
* Squashing your branch's changes into one commit is "good form" and helps the person merging your request to see everything that is going on.
|
94
|
+
* Push your changes to a topic branch in your fork of the repository.
|
95
|
+
* Submit a pull request from your fork to the project.
|
96
|
+
|
97
|
+
### Merging Changes
|
98
|
+
|
99
|
+
* It is considered "poor from" to merge your own request.
|
100
|
+
* Please take the time to review the changes and get a sense of what is being changed. Things to consider:
|
101
|
+
* Does the commit message explain what is going on?
|
102
|
+
* Does the code changes have tests? _Not all changes need new tests, some changes are refactorings_
|
103
|
+
* Does the commit contain more than it should? Are two separate concerns being addressed in one commit?
|
104
|
+
* Did the Travis tests complete successfully?
|
105
|
+
* If you are uncertain, bring other contributors into the conversation by creating a comment that includes their @username.
|
106
|
+
* If you like the pull request, but want others to chime in, create a +1 comment and tag a user.
|
107
|
+
|
108
|
+
# Additional Resources
|
109
|
+
|
110
|
+
* [General GitHub documentation](http://help.github.com/)
|
111
|
+
* [GitHub pull request documentation](http://help.github.com/send-pull-requests/)
|
112
|
+
* [Pro Git](http://git-scm.com/book) is both a free and excellent book about Git.
|
113
|
+
* [A Git Config for Contributing](http://ndlib.github.io/practices/my-typical-per-project-git-config/)
|
data/LICENSE.txt
CHANGED
@@ -1,20 +1,19 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
the
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
1
|
+
##########################################################################
|
2
|
+
# rubydora
|
3
|
+
#
|
4
|
+
# Copyright © 2011 Chris Beer, WGBH
|
5
|
+
# Copyright © 2012 Chris Beer, WGBH, MediaShelf
|
6
|
+
# Copyright © 2013 Data Curation Experts, Stanford University
|
7
|
+
# Additional copyright may be held by others, as reflected in the commit history.
|
8
|
+
#
|
9
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
10
|
+
# you may not use this file except in compliance with the License.
|
11
|
+
# You may obtain a copy of the License at
|
12
|
+
#
|
13
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
14
|
+
#
|
15
|
+
# Unless required by applicable law or agreed to in writing, software
|
16
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
17
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
18
|
+
# See the License for the specific language governing permissions and
|
19
|
+
# limitations under the License.
|
data/Notices.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Chris Beer
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
= rubydora
|
2
2
|
{<img src="https://travis-ci.org/projecthydra/rubydora.png?branch=master" alt="Build Status" />}[https://travis-ci.org/projecthydra/rubydora]
|
3
|
+
{<img src="https://badge.fury.io/rb/rubydora.png" alt="Gem Version" />}[http://badge.fury.io/rb/rubydora]
|
3
4
|
|
4
5
|
Rubydora is a low-level Fedora Commons REST API consumer, providing direct access to REST API methods, as well as a primitive ruby abstraction.
|
5
6
|
|
data/Rakefile
CHANGED
@@ -49,7 +49,7 @@ task :ci => 'jetty:clean' do
|
|
49
49
|
:jetty_port => ENV['TEST_JETTY_PORT'] || 8983,
|
50
50
|
:solr_home => File.expand_path(File.dirname(__FILE__) + '/jetty/solr'),
|
51
51
|
:fedora_home => File.expand_path(File.dirname(__FILE__) + '/jetty/fedora/default'),
|
52
|
-
:startup_wait =>
|
52
|
+
:startup_wait => 90,
|
53
53
|
:java_opts => ['-Xmx256m', '-XX:MaxPermSize=128m']
|
54
54
|
}
|
55
55
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.7.0.pre1
|
data/gemfiles/gemfile.rails4
CHANGED
data/lib/rubydora/audit_trail.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
module Rubydora::AuditTrail
|
2
2
|
|
3
|
-
def audit_trail
|
4
|
-
|
3
|
+
def audit_trail(pid)
|
4
|
+
FedoraAuditTrail.new(object_xml(pid: pid))
|
5
5
|
end
|
6
|
-
|
6
|
+
|
7
7
|
private
|
8
8
|
|
9
9
|
AT_NS = {'audit' => 'info:fedora/fedora-system:def/audit#'}
|
@@ -11,8 +11,8 @@ module Rubydora::AuditTrail
|
|
11
11
|
AT_XPATH = '/foxml:digitalObject/foxml:datastream[@ID = "AUDIT"]/descendant::audit:auditTrail'
|
12
12
|
|
13
13
|
class FedoraAuditTrail
|
14
|
-
def initialize(
|
15
|
-
@ng_xml = Nokogiri::XML(
|
14
|
+
def initialize(object_xml)
|
15
|
+
@ng_xml = Nokogiri::XML(object_xml).xpath(AT_XPATH, FOXML_NS.merge(AT_NS))
|
16
16
|
end
|
17
17
|
def records
|
18
18
|
if !@records
|
data/lib/rubydora/datastream.rb
CHANGED
@@ -75,7 +75,7 @@ module Rubydora
|
|
75
75
|
return @asOfDateTime
|
76
76
|
end
|
77
77
|
|
78
|
-
return self.class.new(@digital_object,
|
78
|
+
return self.class.new(@digital_object, dsid, @options.merge(:asOfDateTime => asOfDateTime))
|
79
79
|
end
|
80
80
|
|
81
81
|
def self.default_attributes
|
@@ -119,7 +119,7 @@ module Rubydora
|
|
119
119
|
# Does this datastream already exist?
|
120
120
|
# @return [Boolean]
|
121
121
|
def new?
|
122
|
-
digital_object.nil? || digital_object.
|
122
|
+
digital_object.nil? || digital_object.new_record? || profile.empty?
|
123
123
|
end
|
124
124
|
|
125
125
|
# This method is overridden in ActiveFedora, so we didn't
|
@@ -260,61 +260,18 @@ module Rubydora
|
|
260
260
|
|
261
261
|
return @profile = {} unless digital_object.respond_to? :repository
|
262
262
|
|
263
|
-
@profile =
|
264
|
-
xml = profile_xml(opts)
|
265
|
-
|
266
|
-
(self.profile_xml_to_hash(xml) unless xml.blank?) || {}
|
267
|
-
end
|
263
|
+
@profile = repository.datastream_profile(pid, dsid, opts[:validateChecksum], asOfDateTime)
|
268
264
|
end
|
269
265
|
|
270
|
-
def
|
271
|
-
|
272
|
-
|
273
|
-
@profile_xml ||= begin
|
274
|
-
|
275
|
-
options = { :pid => pid, :dsid => dsid }
|
276
|
-
options.merge!(opts)
|
277
|
-
options[:asOfDateTime] = asOfDateTime if asOfDateTime
|
278
|
-
options[:validateChecksum] = true if repository.config[:validateChecksum]
|
279
|
-
repository.datastream(options)
|
280
|
-
rescue RestClient::Unauthorized => e
|
281
|
-
raise e
|
282
|
-
rescue RestClient::ResourceNotFound
|
283
|
-
# the datastream is new
|
284
|
-
''
|
285
|
-
end
|
286
|
-
end
|
287
|
-
|
288
|
-
def profile= profile_xml
|
289
|
-
@profile = self.profile_xml_to_hash(profile_xml)
|
290
|
-
end
|
291
|
-
|
292
|
-
def profile_xml_to_hash profile_xml
|
293
|
-
profile_xml.gsub! '<datastreamProfile', '<datastreamProfile xmlns="http://www.fedora.info/definitions/1/0/management/"' unless profile_xml =~ /xmlns=/
|
294
|
-
doc = Nokogiri::XML(profile_xml)
|
295
|
-
h = doc.xpath('/management:datastreamProfile/*', {'management' => "http://www.fedora.info/definitions/1/0/management/"} ).inject({}) do |sum, node|
|
296
|
-
sum[node.name] ||= []
|
297
|
-
sum[node.name] << node.text
|
298
|
-
sum
|
299
|
-
end.reject { |key, values| values.empty? }
|
300
|
-
h.select { |key, values| values.length == 1 }.each do |key, values|
|
301
|
-
h[key] = values.reject { |x| x.empty? }.first
|
302
|
-
end
|
303
|
-
|
304
|
-
h['dsSize'] &&= h['dsSize'].to_i rescue h['dsSize']
|
305
|
-
h['dsCreateDate'] &&= Time.parse(h['dsCreateDate']) rescue h['dsCreateDate']
|
306
|
-
h['dsChecksumValid'] &&= h['dsChecksumValid'] == 'true'
|
307
|
-
h['dsVersionable'] &&= h['dsVersionable'] == 'true'
|
308
|
-
h
|
266
|
+
def profile= profile_hash
|
267
|
+
raise ArgumentError, "Must pass a profile, you passed #{profile_hash.class}" unless profile_hash.kind_of? Hash
|
268
|
+
@profile = profile_hash
|
309
269
|
end
|
310
270
|
|
311
271
|
def versions
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
doc = Nokogiri::XML(versions_xml)
|
316
|
-
doc.xpath('//management:datastreamProfile', {'management' => "http://www.fedora.info/definitions/1/0/management/"} ).map do |ds|
|
317
|
-
self.class.new @digital_object, @dsid, :profile => ds.to_s, :asOfDateTime => ds.xpath('management:dsCreateDate', 'management' => "http://www.fedora.info/definitions/1/0/management/").text
|
272
|
+
versions = repository.versions_for_datastream(pid, dsid)
|
273
|
+
versions.map do |asOfDateTime, profile|
|
274
|
+
self.class.new(@digital_object, dsid, asOfDateTime: asOfDateTime, profile: profile)
|
318
275
|
end
|
319
276
|
end
|
320
277
|
|
@@ -412,7 +369,6 @@ module Rubydora
|
|
412
369
|
# @return [Hash]
|
413
370
|
def reset_profile_attributes
|
414
371
|
@profile = nil
|
415
|
-
@profile_xml = nil
|
416
372
|
@datastream_content = nil
|
417
373
|
@content = nil
|
418
374
|
@changed_attributes = {}
|
@@ -14,14 +14,13 @@ module Rubydora
|
|
14
14
|
include ActiveModel::Dirty
|
15
15
|
include Rubydora::ModelsMixin
|
16
16
|
include Rubydora::RelationshipsMixin
|
17
|
-
include Rubydora::AuditTrail
|
18
17
|
|
19
18
|
extend Deprecation
|
20
19
|
|
21
20
|
attr_reader :pid
|
22
21
|
|
23
22
|
# mapping object parameters to profile elements
|
24
|
-
OBJ_ATTRIBUTES = {:state => :objState, :ownerId => :objOwnerId, :label => :objLabel, :logMessage => nil, :lastModifiedDate => :objLastModDate }
|
23
|
+
OBJ_ATTRIBUTES = {:state => :objState, :ownerId => :objOwnerId, :label => :objLabel, :logMessage => nil, :lastModifiedDate => :objLastModDate, :createdDate => :objCreateDate }
|
25
24
|
|
26
25
|
OBJ_DEFAULT_ATTRIBUTES = { }
|
27
26
|
|
@@ -100,6 +99,11 @@ module Rubydora
|
|
100
99
|
end
|
101
100
|
end
|
102
101
|
|
102
|
+
def audit_trail
|
103
|
+
@audit_trail ||= repository.audit_trail(self.pid)
|
104
|
+
end
|
105
|
+
|
106
|
+
|
103
107
|
##
|
104
108
|
# Return a full uri pid (for use in relations, etc
|
105
109
|
def uri
|
@@ -110,9 +114,10 @@ module Rubydora
|
|
110
114
|
|
111
115
|
# Does this object already exist?
|
112
116
|
# @return [Boolean]
|
113
|
-
def
|
114
|
-
self.
|
117
|
+
def new_record?
|
118
|
+
self.profile.empty?
|
115
119
|
end
|
120
|
+
alias :new? :new_record?
|
116
121
|
|
117
122
|
def asOfDateTime asOfDateTime = nil
|
118
123
|
if asOfDateTime == nil
|
@@ -129,53 +134,15 @@ module Rubydora
|
|
129
134
|
# Retrieve the object profile as a hash (and cache it)
|
130
135
|
# @return [Hash] see Fedora #getObject documentation for keys
|
131
136
|
def profile
|
132
|
-
return {} if profile_xml.nil?
|
133
|
-
|
134
137
|
@profile ||= begin
|
135
|
-
profile_xml.gsub! '<objectProfile', '<objectProfile xmlns="http://www.fedora.info/definitions/1/0/access/"' unless profile_xml =~ /xmlns=/
|
136
|
-
doc = Nokogiri::XML(profile_xml)
|
137
|
-
h = doc.xpath('/access:objectProfile/*', {'access' => "http://www.fedora.info/definitions/1/0/access/"} ).inject({}) do |sum, node|
|
138
|
-
sum[node.name] ||= []
|
139
|
-
sum[node.name] << node.text
|
140
|
-
|
141
|
-
if node.name == "objModels"
|
142
|
-
sum[node.name] = node.xpath('access:model', {'access' => "http://www.fedora.info/definitions/1/0/access/"}).map { |x| x.text }
|
143
|
-
end
|
144
|
-
|
145
|
-
sum
|
146
|
-
end.reject { |key, values| values.empty? }
|
147
|
-
|
148
|
-
h.select { |key, values| values.length == 1 }.each do |key, values|
|
149
|
-
next if key == "objModels"
|
150
|
-
h[key] = values.reject { |x| x.empty? }.first
|
151
|
-
end
|
152
138
|
@new = false
|
153
|
-
|
154
|
-
h
|
155
|
-
|
139
|
+
repository.object_profile(pid, asOfDateTime)
|
156
140
|
end.freeze
|
157
141
|
end
|
158
142
|
|
159
|
-
def profile_xml
|
160
|
-
@profile_xml ||= begin
|
161
|
-
options = { :pid => pid }
|
162
|
-
options[:asOfDateTime] = asOfDateTime if asOfDateTime
|
163
|
-
repository.object(options)
|
164
|
-
rescue RestClient::ResourceNotFound => e
|
165
|
-
''
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
def object_xml
|
170
|
-
repository.object_xml(pid: pid)
|
171
|
-
end
|
172
|
-
|
173
143
|
def versions
|
174
|
-
|
175
|
-
|
176
|
-
doc = Nokogiri::XML(versions_xml)
|
177
|
-
doc.xpath('//access:objectChangeDate', {'access' => 'http://www.fedora.info/definitions/1/0/access/' } ).map do |changeDate|
|
178
|
-
self.class.new pid, repository, :asOfDateTime => changeDate.text
|
144
|
+
repository.versions_for_object(pid).map do |changeDate|
|
145
|
+
self.class.new pid, repository, :asOfDateTime => changeDate
|
179
146
|
end
|
180
147
|
end
|
181
148
|
|
@@ -222,7 +189,6 @@ module Rubydora
|
|
222
189
|
if self.new?
|
223
190
|
self.pid = repository.ingest to_api_params.merge(:pid => pid)
|
224
191
|
@profile = nil #will cause a reload with updated data
|
225
|
-
@profile_xml = nil
|
226
192
|
else
|
227
193
|
p = to_api_params
|
228
194
|
repository.modify_object p.merge(:pid => pid) unless p.empty?
|
@@ -241,7 +207,6 @@ module Rubydora
|
|
241
207
|
run_callbacks :destroy do
|
242
208
|
@datastreams = nil
|
243
209
|
@profile = nil
|
244
|
-
@profile_xml = nil
|
245
210
|
@pid = nil
|
246
211
|
nil
|
247
212
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Rubydora
|
2
|
+
# This class abstracts away all of the API details including XML parsing
|
3
|
+
# This allows the driver (Fc3Service) to be swapped out without having to modify
|
4
|
+
# the ORM layer (e.g. Datastream, DigitalObject, Repository)
|
5
|
+
class Fc3Service
|
6
|
+
include RestApiClient
|
7
|
+
include Rubydora::AuditTrail
|
8
|
+
|
9
|
+
attr_reader :config
|
10
|
+
def initialize(config)
|
11
|
+
@config = config
|
12
|
+
end
|
13
|
+
|
14
|
+
# Reserve a new pid for the object
|
15
|
+
# @params [Hash] options
|
16
|
+
# @option options [String] :namespace the namespece for the pid
|
17
|
+
def mint(options={})
|
18
|
+
d = Nokogiri::XML(next_pid(options))
|
19
|
+
d.xpath('//fedora:pid', 'fedora' => 'http://www.fedora.info/definitions/1/0/management/').text
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
# repository profile (from API-A-LITE data)
|
24
|
+
# @return [Hash]
|
25
|
+
def repository_profile
|
26
|
+
begin
|
27
|
+
profile_xml = self.describe.strip
|
28
|
+
h = ProfileParser.parse_repository_profile(profile_xml)
|
29
|
+
h.select { |key, value| value.length == 1 }.each do |key, value|
|
30
|
+
next if key == "objModels"
|
31
|
+
h[key] = value.first
|
32
|
+
end
|
33
|
+
|
34
|
+
h
|
35
|
+
rescue
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def object_profile(pid, asOfDateTime = nil)
|
41
|
+
options = {pid: pid}
|
42
|
+
options[:asOfDateTime] = asOfDateTime if asOfDateTime
|
43
|
+
begin
|
44
|
+
xml = object(options)
|
45
|
+
ProfileParser.parse_object_profile(xml)
|
46
|
+
rescue RestClient::ResourceNotFound
|
47
|
+
{}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def datastream_profile(pid, dsid, validateChecksum, asOfDateTime = nil)
|
52
|
+
xml = begin
|
53
|
+
options = { pid: pid, dsid: dsid}
|
54
|
+
options[:validateChecksum] = validateChecksum if validateChecksum
|
55
|
+
options[:asOfDateTime] = asOfDateTime if asOfDateTime
|
56
|
+
options[:validateChecksum] = true if config[:validateChecksum]
|
57
|
+
datastream(options)
|
58
|
+
rescue RestClient::Unauthorized => e
|
59
|
+
raise e
|
60
|
+
rescue RestClient::ResourceNotFound
|
61
|
+
# the datastream is new
|
62
|
+
''
|
63
|
+
end
|
64
|
+
|
65
|
+
ProfileParser.parse_datastream_profile(xml)
|
66
|
+
end
|
67
|
+
|
68
|
+
def versions_for_datastream(pid, dsid)
|
69
|
+
versions_xml = datastream_versions(:pid => pid, :dsid => dsid)
|
70
|
+
return {} if versions_xml.nil?
|
71
|
+
versions_xml.gsub! '<datastreamProfile', '<datastreamProfile xmlns="http://www.fedora.info/definitions/1/0/management/"' unless versions_xml =~ /xmlns=/
|
72
|
+
doc = Nokogiri::XML(versions_xml)
|
73
|
+
versions = {}
|
74
|
+
doc.xpath('//management:datastreamProfile', {'management' => "http://www.fedora.info/definitions/1/0/management/"} ).each do |ds|
|
75
|
+
key = ds.xpath('management:dsCreateDate', 'management' => "http://www.fedora.info/definitions/1/0/management/").text
|
76
|
+
versions[key] = ProfileParser.parse_datastream_profile(ds.to_s)
|
77
|
+
end
|
78
|
+
versions
|
79
|
+
end
|
80
|
+
|
81
|
+
def versions_for_object(pid)
|
82
|
+
versions_xml = object_versions(:pid => pid)
|
83
|
+
versions_xml.gsub! '<fedoraObjectHistory', '<fedoraObjectHistory xmlns="http://www.fedora.info/definitions/1/0/access/"' unless versions_xml =~ /xmlns=/
|
84
|
+
doc = Nokogiri::XML(versions_xml)
|
85
|
+
doc.xpath('//access:objectChangeDate', {'access' => 'http://www.fedora.info/definitions/1/0/access/' } ).map(&:text)
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
@@ -47,7 +47,7 @@ module Rubydora
|
|
47
47
|
# @param [Hash] options to convert to URL parameters
|
48
48
|
# @return [String] URI
|
49
49
|
def dissemination_url pid, sdef = nil, method = nil, options = nil
|
50
|
-
raise "" unless pid
|
50
|
+
raise ArgumentError, "You must provide a pid" unless pid
|
51
51
|
url_for(object_url(pid) + "/methods" + (("/#{CGI::escape(sdef)}" if sdef) || '') + (("/#{CGI::escape(method)}" if method) || ''), options)
|
52
52
|
end
|
53
53
|
|
@@ -57,7 +57,7 @@ module Rubydora
|
|
57
57
|
# @param [Hash] options to convert to URL parameters
|
58
58
|
# @return [String] URI
|
59
59
|
def datastream_url pid, dsid, options = nil
|
60
|
-
raise "" unless pid and dsid
|
60
|
+
raise ArgumentError, "You must provide a pid and a dsid" unless pid and dsid
|
61
61
|
url_for(object_url(pid) + "/datastreams/#{CGI::escape(dsid)}", options)
|
62
62
|
end
|
63
63
|
|
@@ -68,7 +68,7 @@ module Rubydora
|
|
68
68
|
# @param [Hash] options to convert to URL parameters
|
69
69
|
# @return [String] URI
|
70
70
|
def datastreams_url pid, options = nil
|
71
|
-
raise "" unless pid
|
71
|
+
raise ArgumentError, "You must provide a pid" unless pid
|
72
72
|
url_for(object_url(pid) + "/datastreams", options)
|
73
73
|
end
|
74
74
|
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Rubydora
|
2
|
+
module ProfileParser
|
3
|
+
def self.parse_datastream_profile profile_xml
|
4
|
+
profile_xml.gsub! '<datastreamProfile', '<datastreamProfile xmlns="http://www.fedora.info/definitions/1/0/management/"' unless profile_xml =~ /xmlns=/
|
5
|
+
doc = Nokogiri::XML(profile_xml)
|
6
|
+
h = doc.xpath('/management:datastreamProfile/*', {'management' => "http://www.fedora.info/definitions/1/0/management/"} ).inject({}) do |sum, node|
|
7
|
+
sum[node.name] ||= []
|
8
|
+
sum[node.name] << node.text
|
9
|
+
sum
|
10
|
+
end.reject { |key, values| values.empty? }
|
11
|
+
h.select { |key, values| values.length == 1 }.each do |key, values|
|
12
|
+
h[key] = values.reject { |x| x.empty? }.first
|
13
|
+
end
|
14
|
+
|
15
|
+
h['dsSize'] &&= h['dsSize'].to_i rescue h['dsSize']
|
16
|
+
h['dsCreateDate'] &&= Time.parse(h['dsCreateDate']) rescue h['dsCreateDate']
|
17
|
+
h['dsChecksumValid'] &&= h['dsChecksumValid'] == 'true'
|
18
|
+
h['dsVersionable'] &&= h['dsVersionable'] == 'true'
|
19
|
+
h.with_indifferent_access
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.parse_object_profile profile_xml
|
23
|
+
profile_xml.gsub! '<objectProfile', '<objectProfile xmlns="http://www.fedora.info/definitions/1/0/access/"' unless profile_xml =~ /xmlns=/
|
24
|
+
doc = Nokogiri::XML(profile_xml)
|
25
|
+
h = doc.xpath('/access:objectProfile/*', {'access' => "http://www.fedora.info/definitions/1/0/access/"} ).inject({}) do |sum, node|
|
26
|
+
sum[node.name] ||= []
|
27
|
+
sum[node.name] << node.text
|
28
|
+
|
29
|
+
if node.name == "objModels"
|
30
|
+
sum[node.name] = node.xpath('access:model', {'access' => "http://www.fedora.info/definitions/1/0/access/"}).map { |x| x.text }
|
31
|
+
end
|
32
|
+
|
33
|
+
sum
|
34
|
+
end.reject { |key, values| values.empty? }
|
35
|
+
h.select { |key, values| values.length == 1 }.each do |key, values|
|
36
|
+
next if key == "objModels"
|
37
|
+
h[key] = values.reject { |x| x.empty? }.first
|
38
|
+
end
|
39
|
+
h.with_indifferent_access
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.parse_repository_profile profile_xml
|
43
|
+
profile_xml.gsub! '<fedoraRepository', '<fedoraRepository xmlns="http://www.fedora.info/definitions/1/0/access/"' unless profile_xml =~ /xmlns=/
|
44
|
+
doc = Nokogiri::XML(profile_xml)
|
45
|
+
xmlns = { 'access' => "http://www.fedora.info/definitions/1/0/access/" }
|
46
|
+
h = doc.xpath('/access:fedoraRepository/*', xmlns).inject({}) do |sum, node|
|
47
|
+
sum[node.name] ||= []
|
48
|
+
case node.name
|
49
|
+
when "repositoryPID"
|
50
|
+
sum[node.name] << Hash[*node.xpath('access:*', xmlns).map { |x| [node.name, node.text]}.flatten]
|
51
|
+
else
|
52
|
+
sum[node.name] << node.text
|
53
|
+
end
|
54
|
+
sum
|
55
|
+
end
|
56
|
+
h.with_indifferent_access
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/rubydora/repository.rb
CHANGED
@@ -1,10 +1,27 @@
|
|
1
1
|
require 'active_support/core_ext/hash/indifferent_access'
|
2
|
+
require 'active_support/core_ext/module/delegation' # This line only needed for rails 3
|
2
3
|
|
3
4
|
module Rubydora
|
4
5
|
# Fedora Repository object that provides API access
|
5
6
|
class Repository
|
6
7
|
include ResourceIndex
|
7
|
-
|
8
|
+
|
9
|
+
attr_writer :api
|
10
|
+
def api
|
11
|
+
@api ||= driver.new(config)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Eventually driver can decide between Fc3Service and Fc4Service
|
15
|
+
def driver
|
16
|
+
Fc3Service
|
17
|
+
end
|
18
|
+
|
19
|
+
delegate :client, :transaction, :mint, :ingest, :find_objects, :purge_object,
|
20
|
+
:modify_object, :datastreams, :add_datastream, :modify_datastream,
|
21
|
+
:set_datastream_options, :datastream_dissemination, :purge_datastream,
|
22
|
+
:add_relationship, :purge_relationship, :repository_profile,
|
23
|
+
:object_profile, :datastream_profile, :versions_for_datastream,
|
24
|
+
:versions_for_object, :audit_trail, to: :api
|
8
25
|
|
9
26
|
# repository configuration (see #initialize)
|
10
27
|
attr_reader :config
|
@@ -28,14 +45,6 @@ module Rubydora
|
|
28
45
|
DigitalObject.find_or_initialize(pid, self)
|
29
46
|
end
|
30
47
|
|
31
|
-
# Reserve a new pid for the object
|
32
|
-
# @params [Hash] options
|
33
|
-
# @option options [String] :namespace the namespece for the pid
|
34
|
-
def mint(options={})
|
35
|
-
d = Nokogiri::XML(next_pid(options))
|
36
|
-
d.xpath('//fedora:pid', 'fedora' => 'http://www.fedora.info/definitions/1/0/management/').text
|
37
|
-
end
|
38
|
-
|
39
48
|
# High-level access to the Fedora find_objects API
|
40
49
|
#
|
41
50
|
# @params [String] query
|
@@ -76,35 +85,12 @@ module Rubydora
|
|
76
85
|
# repository profile (from API-A-LITE data)
|
77
86
|
# @return [Hash]
|
78
87
|
def profile
|
79
|
-
@profile ||=
|
80
|
-
profile_xml = self.describe.strip
|
81
|
-
profile_xml.gsub! '<fedoraRepository', '<fedoraRepository xmlns="http://www.fedora.info/definitions/1/0/access/"' unless profile_xml =~ /xmlns=/
|
82
|
-
doc = Nokogiri::XML(profile_xml)
|
83
|
-
xmlns = { 'access' => "http://www.fedora.info/definitions/1/0/access/" }
|
84
|
-
h = doc.xpath('/access:fedoraRepository/*', xmlns).inject({}) do |sum, node|
|
85
|
-
sum[node.name] ||= []
|
86
|
-
case node.name
|
87
|
-
when "repositoryPID"
|
88
|
-
sum[node.name] << Hash[*node.xpath('access:*', xmlns).map { |x| [node.name, node.text]}.flatten]
|
89
|
-
else
|
90
|
-
sum[node.name] << node.text
|
91
|
-
end
|
92
|
-
sum
|
93
|
-
end
|
94
|
-
h.select { |key, value| value.length == 1 }.each do |key, value|
|
95
|
-
next if key == "objModels"
|
96
|
-
h[key] = value.first
|
97
|
-
end
|
98
|
-
|
99
|
-
h
|
100
|
-
rescue
|
101
|
-
nil
|
102
|
-
end
|
88
|
+
@profile ||= repository_profile
|
103
89
|
end
|
104
90
|
|
105
91
|
# @return [Float] repository version
|
106
92
|
def version
|
107
|
-
@version ||=
|
93
|
+
@version ||= repository_profile['repositoryVersion'].to_f rescue nil
|
108
94
|
end
|
109
95
|
|
110
96
|
# Raise an error if unable to connect to the API endpoint
|
@@ -40,22 +40,23 @@ module Rubydora
|
|
40
40
|
|
41
41
|
before_modify_object do |options|
|
42
42
|
if Rubydora::Transactions.use_transactions
|
43
|
-
|
44
|
-
|
43
|
+
xml = object(pid: options[:pid])
|
44
|
+
profile = ProfileParser.parse_object_profile(xml)
|
45
|
+
append_to_transactions_log :modify_object, :pid => options[:pid], :state => profile[:objState], :ownerId => profile[:objOwnerId], :logMessage => 'reverting'
|
45
46
|
end
|
46
47
|
end
|
47
48
|
|
48
49
|
before_set_datastream_options do |options|
|
49
50
|
if Rubydora::Transactions.use_transactions
|
50
|
-
|
51
|
-
|
51
|
+
xml = datastream(pid: options[:pid], dsid: options[:dsid])
|
52
|
+
profile = ProfileParser.parse_datastream_profile(xml)
|
52
53
|
|
53
54
|
if options[:options][:versionable]
|
54
|
-
append_to_transactions_log :set_datastream_options, :pid => options[:pid], :dsid => options[:dsid], :versionable =>
|
55
|
+
append_to_transactions_log :set_datastream_options, :pid => options[:pid], :dsid => options[:dsid], :versionable => profile[:dsVersionable]
|
55
56
|
end
|
56
57
|
|
57
58
|
if options[:options][:state]
|
58
|
-
append_to_transactions_log :set_datastream_options, :pid => options[:pid], :dsid => options[:dsid], :state =>
|
59
|
+
append_to_transactions_log :set_datastream_options, :pid => options[:pid], :dsid => options[:dsid], :state => profile[:dsState]
|
59
60
|
end
|
60
61
|
end
|
61
62
|
end
|
data/lib/rubydora.rb
CHANGED
@@ -15,6 +15,8 @@ module Rubydora
|
|
15
15
|
autoload :ArrayWithCallback, "rubydora/array_with_callback"
|
16
16
|
autoload :Transactions, "rubydora/transactions"
|
17
17
|
autoload :AuditTrail, "rubydora/audit_trail"
|
18
|
+
autoload :ProfileParser, "rubydora/profile_parser"
|
19
|
+
autoload :Fc3Service, "rubydora/fc3_service"
|
18
20
|
|
19
21
|
require 'csv'
|
20
22
|
require 'time'
|
data/rubydora.gemspec
CHANGED
@@ -27,7 +27,6 @@ Gem::Specification.new do |s|
|
|
27
27
|
s.add_dependency "deprecation"
|
28
28
|
|
29
29
|
s.add_development_dependency("rake")
|
30
|
-
s.add_development_dependency("shoulda")
|
31
30
|
s.add_development_dependency("bundler", ">= 1.0.14")
|
32
31
|
s.add_development_dependency("rspec")
|
33
32
|
s.add_development_dependency("yard")
|
data/spec/audit_trail_spec.rb
CHANGED
@@ -8,7 +8,7 @@ describe "#audit_trail" do
|
|
8
8
|
@xml = f.read
|
9
9
|
end
|
10
10
|
@repo = Rubydora::Repository.new
|
11
|
-
@repo.stub(:object_xml).with(hash_including(:pid => 'foo:bar')).and_return(@xml)
|
11
|
+
@repo.api.stub(:object_xml).with(hash_including(:pid => 'foo:bar')).and_return(@xml)
|
12
12
|
@test_object = Rubydora::DigitalObject.new('foo:bar', @repo)
|
13
13
|
end
|
14
14
|
it "should have the correct number of audit records" do
|
data/spec/lib/datastream_spec.rb
CHANGED
@@ -3,15 +3,15 @@ require 'stringio'
|
|
3
3
|
|
4
4
|
describe Rubydora::Datastream do
|
5
5
|
before do
|
6
|
-
@mock_repository =
|
7
|
-
@mock_object =
|
8
|
-
@mock_object.stub(:repository => @mock_repository, :pid => 'pid', :
|
6
|
+
@mock_repository = Rubydora::Fc3Service.new({})
|
7
|
+
@mock_object = double(Rubydora::DigitalObject)
|
8
|
+
@mock_object.stub(:repository => @mock_repository, :pid => 'pid', :new_record? => false)
|
9
9
|
end
|
10
10
|
|
11
11
|
describe "stream" do
|
12
12
|
subject { Rubydora::Datastream.new @mock_object, 'dsid' }
|
13
13
|
before do
|
14
|
-
stub_response =
|
14
|
+
stub_response = double
|
15
15
|
stub_response.stub(:read_body).and_yield("one1").and_yield('two2').and_yield('thre').and_yield('four')
|
16
16
|
@mock_repository.should_receive(:datastream_dissemination).with(hash_including(:pid => 'pid', :dsid => 'dsid')).and_yield(stub_response)
|
17
17
|
prof = <<-XML
|
@@ -19,7 +19,7 @@ describe Rubydora::Datastream do
|
|
19
19
|
<dsSize>16</dsSize>
|
20
20
|
</datastreamProfile>
|
21
21
|
XML
|
22
|
-
subject.profile = prof
|
22
|
+
subject.profile = Rubydora::ProfileParser.parse_datastream_profile(prof)
|
23
23
|
end
|
24
24
|
it "should send the whold thing" do
|
25
25
|
e = subject.stream()
|
@@ -212,7 +212,7 @@ describe Rubydora::Datastream do
|
|
212
212
|
describe "retrieve" do
|
213
213
|
before(:each) do
|
214
214
|
@datastream = Rubydora::Datastream.new @mock_object, 'dsid'
|
215
|
-
@mock_repository.
|
215
|
+
@mock_repository.stub(:datastream).and_return <<-XML
|
216
216
|
<datastreamProfile>
|
217
217
|
<dsLocation>some:uri</dsLocation>
|
218
218
|
<dsLabel>label</dsLabel>
|
@@ -261,7 +261,7 @@ describe Rubydora::Datastream do
|
|
261
261
|
describe "for a managed datastream" do
|
262
262
|
before(:each) do
|
263
263
|
@datastream = Rubydora::Datastream.new @mock_object, 'dsid'
|
264
|
-
@mock_repository.
|
264
|
+
@mock_repository.stub(:datastream).and_return <<-XML
|
265
265
|
<datastreamProfile>
|
266
266
|
<dsLocation>some:uri</dsLocation>
|
267
267
|
<dsLabel>label</dsLabel>
|
@@ -307,7 +307,7 @@ describe Rubydora::Datastream do
|
|
307
307
|
|
308
308
|
describe "for an inline datastream" do
|
309
309
|
before(:each) do
|
310
|
-
@mock_repository.
|
310
|
+
@mock_repository.stub(:datastream).and_return <<-XML
|
311
311
|
<datastreamProfile>
|
312
312
|
<dsLocation>some:uri</dsLocation>
|
313
313
|
<dsLabel>label</dsLabel>
|
@@ -335,7 +335,7 @@ describe Rubydora::Datastream do
|
|
335
335
|
subject.stub(:new? => true)
|
336
336
|
end
|
337
337
|
|
338
|
-
subject { Rubydora::Datastream.new
|
338
|
+
subject { Rubydora::Datastream.new double(:pid => 'asdf', :new? => false), 'asdf' }
|
339
339
|
it "should have content if it is persisted" do
|
340
340
|
subject.stub(:new? => false)
|
341
341
|
subject.should have_content
|
@@ -362,7 +362,7 @@ describe Rubydora::Datastream do
|
|
362
362
|
describe "update" do
|
363
363
|
before(:each) do
|
364
364
|
@datastream = Rubydora::Datastream.new @mock_object, 'dsid'
|
365
|
-
@mock_repository.
|
365
|
+
@mock_repository.stub(:datastream).and_return <<-XML
|
366
366
|
<datastreamProfile>
|
367
367
|
<dsLocation>some:uri</dsLocation>
|
368
368
|
<dsLabel>label</dsLabel>
|
@@ -411,7 +411,7 @@ describe Rubydora::Datastream do
|
|
411
411
|
before(:each) do
|
412
412
|
@datastream = Rubydora::Datastream.new @mock_object, 'dsid'
|
413
413
|
@datastream.stub :content_changed? => false
|
414
|
-
@mock_repository.
|
414
|
+
@mock_repository.stub(:datastream).and_return <<-XML
|
415
415
|
<datastreamProfile>
|
416
416
|
<dsLocation>some:uri</dsLocation>
|
417
417
|
<dsLabel>label</dsLabel>
|
@@ -443,7 +443,7 @@ describe Rubydora::Datastream do
|
|
443
443
|
before(:each) do
|
444
444
|
@datastream = Rubydora::Datastream.new @mock_object, 'dsid'
|
445
445
|
@datastream.stub(:new? => false)
|
446
|
-
@mock_repository.
|
446
|
+
@mock_repository.stub(:datastream_versions).and_return <<-XML
|
447
447
|
<datastreamHistory>
|
448
448
|
<datastreamProfile>
|
449
449
|
<dsVersionID>dsid.1</dsVersionID>
|
@@ -504,7 +504,7 @@ describe Rubydora::Datastream do
|
|
504
504
|
describe "when no versions are found" do
|
505
505
|
before(:each) do
|
506
506
|
@datastream = Rubydora::Datastream.new @mock_object, 'dsid'
|
507
|
-
@mock_repository.
|
507
|
+
@mock_repository.stub(:datastream_versions).and_return nil
|
508
508
|
end
|
509
509
|
|
510
510
|
it "should have an emptylist of previous versions" do
|
@@ -700,7 +700,7 @@ describe Rubydora::Datastream do
|
|
700
700
|
<dsChecksumValid>true</dsChecksumValid>
|
701
701
|
</datastreamProfile>
|
702
702
|
XML
|
703
|
-
@datastream.profile = prof
|
703
|
+
@datastream.profile = Rubydora::ProfileParser.parse_datastream_profile(prof)
|
704
704
|
@datastream.profile.should == {'dsChecksumValid' =>true}
|
705
705
|
end
|
706
706
|
end
|
@@ -709,7 +709,7 @@ describe Rubydora::Datastream do
|
|
709
709
|
describe "with a digital_object that doesn't have a repository" do
|
710
710
|
### see UnsavedDigitalObject in ActiveFedora
|
711
711
|
before(:each) do
|
712
|
-
@datastream = Rubydora::Datastream.new
|
712
|
+
@datastream = Rubydora::Datastream.new double(:foo), 'dsid'
|
713
713
|
end
|
714
714
|
it "should be empty if the digital_object doesn't have a repository" do
|
715
715
|
@datastream.profile.should == {}
|
@@ -2,14 +2,8 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Rubydora::DigitalObject do
|
4
4
|
before do
|
5
|
-
@mock_repository =
|
5
|
+
@mock_repository = Rubydora::Fc3Service.new({})
|
6
6
|
end
|
7
|
-
describe "new" do
|
8
|
-
it "should load a DigitalObject instance" do
|
9
|
-
Rubydora::DigitalObject.new("pid").should be_a_kind_of(Rubydora::DigitalObject)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
7
|
describe "profile" do
|
14
8
|
before(:each) do
|
15
9
|
@object = Rubydora::DigitalObject.new 'pid', @mock_repository
|
@@ -46,28 +40,38 @@ describe Rubydora::DigitalObject do
|
|
46
40
|
end
|
47
41
|
end
|
48
42
|
|
49
|
-
describe "
|
43
|
+
describe "initialize" do
|
50
44
|
before(:each) do
|
51
45
|
@mock_repository.stub(:object) { raise RestClient::ResourceNotFound }
|
52
|
-
|
46
|
+
end
|
47
|
+
subject { Rubydora::DigitalObject.new 'pid', @mock_repository }
|
48
|
+
|
49
|
+
it "should load a DigitalObject instance" do
|
50
|
+
expect(subject).to be_a_kind_of(Rubydora::DigitalObject)
|
53
51
|
end
|
54
52
|
|
55
53
|
it "should be new" do
|
56
|
-
|
54
|
+
expect(subject).to be_new
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should be new_record" do
|
58
|
+
expect(subject).to be_new_record
|
57
59
|
end
|
58
60
|
|
59
61
|
it "should call ingest on save" do
|
60
|
-
|
61
|
-
@mock_repository.
|
62
|
-
|
62
|
+
subject.stub(:datastreams) { {} }
|
63
|
+
expect(@mock_repository).to receive(:ingest).with(hash_including(:pid => 'pid')).and_return('pid')
|
64
|
+
subject.save
|
63
65
|
end
|
64
66
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
67
|
+
describe "without a provided pid" do
|
68
|
+
subject { Rubydora::DigitalObject.new nil, @mock_repository }
|
69
|
+
it "should create a new Fedora object with a generated PID if no PID is provided" do
|
70
|
+
@mock_repository.should_receive(:ingest).with(hash_including(:pid => nil)).and_return('pid')
|
71
|
+
@mock_repository.should_receive(:datastreams).with(hash_including(:pid => 'pid')).and_raise(RestClient::ResourceNotFound)
|
72
|
+
subject.save
|
73
|
+
subject.pid.should == 'pid'
|
74
|
+
end
|
71
75
|
end
|
72
76
|
end
|
73
77
|
|
@@ -92,7 +96,7 @@ describe Rubydora::DigitalObject do
|
|
92
96
|
"<objectDatastreams><datastream dsid='a'></datastream>><datastream dsid='b'></datastream>><datastream dsid='c'></datastream></objectDatastreams>"
|
93
97
|
end
|
94
98
|
@object = Rubydora::DigitalObject.new 'pid', @mock_repository
|
95
|
-
@object.stub(:
|
99
|
+
@object.stub(:new_record? => false)
|
96
100
|
end
|
97
101
|
|
98
102
|
describe "datastreams" do
|
@@ -172,17 +176,17 @@ describe Rubydora::DigitalObject do
|
|
172
176
|
|
173
177
|
describe "saving an object's datastreams" do
|
174
178
|
before do
|
175
|
-
@new_ds =
|
179
|
+
@new_ds = double(Rubydora::Datastream)
|
176
180
|
@new_ds.stub(:new? => true, :changed? => true, :content_changed? => true, :content => 'XXX')
|
177
|
-
@new_empty_ds =
|
181
|
+
@new_empty_ds = double(Rubydora::Datastream)
|
178
182
|
@new_empty_ds.stub(:new? => true, :changed? => false, :content_changed? => false, :content => nil)
|
179
|
-
@existing_ds =
|
183
|
+
@existing_ds = double(Rubydora::Datastream)
|
180
184
|
@existing_ds.stub(:new? => false, :changed? => false, :content_changed? => false, :content => 'YYY')
|
181
|
-
@changed_attr_ds =
|
185
|
+
@changed_attr_ds = double(Rubydora::Datastream)
|
182
186
|
@changed_attr_ds.stub(:new? => false, :changed? => true, :content_changed? => false, :content => 'YYY')
|
183
|
-
@changed_ds =
|
187
|
+
@changed_ds = double(Rubydora::Datastream)
|
184
188
|
@changed_ds.stub(:new? => false, :changed? => true, :content_changed? => true, :content => 'ZZZ')
|
185
|
-
@changed_empty_ds =
|
189
|
+
@changed_empty_ds = double(Rubydora::Datastream)
|
186
190
|
@changed_empty_ds.stub(:new? => false, :changed? => true, :content_changed? => true, :content => nil)
|
187
191
|
|
188
192
|
end
|
@@ -262,7 +266,7 @@ describe Rubydora::DigitalObject do
|
|
262
266
|
end
|
263
267
|
|
264
268
|
it "should remove models from fedora" do
|
265
|
-
@object.
|
269
|
+
@object.stub(:profile).and_return({"objModels" => ['asdf']})
|
266
270
|
@mock_repository.should_receive(:purge_relationship) do |params|
|
267
271
|
params.should have_key(:subject)
|
268
272
|
params[:predicate].should == 'info:fedora/fedora-system:def/model#hasModel'
|
@@ -272,7 +276,7 @@ describe Rubydora::DigitalObject do
|
|
272
276
|
end
|
273
277
|
|
274
278
|
it "should be able to handle complete model replacemenet" do
|
275
|
-
@object.
|
279
|
+
@object.stub(:profile).and_return({"objModels" => ['asdf']})
|
276
280
|
@mock_repository.should_receive(:add_relationship).with(instance_of(Hash))
|
277
281
|
@mock_repository.should_receive(:purge_relationship).with(instance_of(Hash))
|
278
282
|
@object.models = '1234'
|
@@ -301,7 +305,7 @@ describe Rubydora::DigitalObject do
|
|
301
305
|
params[:predicate].should == 'info:fedora/fedora-system:def/relations-external#hasPart'
|
302
306
|
params[:object].should == 'asdf'
|
303
307
|
end
|
304
|
-
@mock_object =
|
308
|
+
@mock_object = double(Rubydora::DigitalObject)
|
305
309
|
@mock_object.should_receive(:fqpid).and_return('asdf')
|
306
310
|
@mock_repository.should_receive(:find_by_sparql_relationship).with('info:fedora/pid', 'info:fedora/fedora-system:def/relations-external#hasPart').and_return([])
|
307
311
|
@object.parts << @mock_object
|
@@ -313,7 +317,7 @@ describe Rubydora::DigitalObject do
|
|
313
317
|
params[:predicate].should == 'info:fedora/fedora-system:def/relations-external#hasPart'
|
314
318
|
params[:object].should == 'asdf'
|
315
319
|
end
|
316
|
-
@mock_object =
|
320
|
+
@mock_object = double(Rubydora::DigitalObject)
|
317
321
|
@mock_object.should_receive(:fqpid).and_return('asdf')
|
318
322
|
@mock_repository.should_receive(:find_by_sparql_relationship).with('info:fedora/pid', 'info:fedora/fedora-system:def/relations-external#hasPart').and_return([@mock_object])
|
319
323
|
@object.parts.delete(@mock_object)
|
@@ -479,12 +483,8 @@ describe Rubydora::DigitalObject do
|
|
479
483
|
let(:method) { 'lastModifiedDate' }
|
480
484
|
end
|
481
485
|
|
482
|
-
describe "#
|
483
|
-
|
484
|
-
|
485
|
-
@mock_repository.stub(:object_xml).with(hash_including(:pid => 'foo:bar')).and_return(xml)
|
486
|
-
@object = Rubydora::DigitalObject.new 'foo:bar', @mock_repository
|
487
|
-
@object.object_xml.should == @object.repository.object_xml(pid: 'foo:bar')
|
488
|
-
end
|
486
|
+
describe "#createdDate" do
|
487
|
+
it_behaves_like "an object attribute"
|
488
|
+
let(:method) { 'createdDate' }
|
489
489
|
end
|
490
490
|
end
|
data/spec/lib/repository_spec.rb
CHANGED
@@ -4,7 +4,7 @@ describe Rubydora::Repository do
|
|
4
4
|
include Rubydora::FedoraUrlHelpers
|
5
5
|
|
6
6
|
before(:each) do
|
7
|
-
@repository = Rubydora::Repository.new
|
7
|
+
@repository = Rubydora::Repository.new
|
8
8
|
end
|
9
9
|
|
10
10
|
describe "initialize" do
|
@@ -24,7 +24,7 @@ describe Rubydora::Repository do
|
|
24
24
|
|
25
25
|
describe "find" do
|
26
26
|
it "should load objects by pid" do
|
27
|
-
@mock_object =
|
27
|
+
@mock_object = double(Rubydora::DigitalObject)
|
28
28
|
Rubydora::DigitalObject.should_receive(:find).with("pid", instance_of(Rubydora::Repository)).and_return @mock_object
|
29
29
|
|
30
30
|
@repository.find('pid')
|
@@ -34,7 +34,7 @@ describe Rubydora::Repository do
|
|
34
34
|
describe "mint" do
|
35
35
|
before do
|
36
36
|
xml = "<resp xmlns:fedora=\"http://www.fedora.info/definitions/1/0/management/\"><fedora:pid>test:123</fedora:pid></resp>"
|
37
|
-
@repository.should_receive(:next_pid).and_return xml
|
37
|
+
@repository.api.should_receive(:next_pid).and_return xml
|
38
38
|
end
|
39
39
|
it "should call nextPID" do
|
40
40
|
@repository.mint.should == 'test:123'
|
@@ -53,13 +53,13 @@ describe Rubydora::Repository do
|
|
53
53
|
|
54
54
|
describe "profile" do
|
55
55
|
it "should map the fedora repository description to a hash" do
|
56
|
-
@mock_response =
|
57
|
-
@mock_client =
|
56
|
+
@mock_response = double
|
57
|
+
@mock_client = double
|
58
|
+
@repository.api.should_receive(:client).and_return(@mock_client)
|
59
|
+
@mock_client.should_receive(:[]).with(describe_repository_url(:xml=> true)).and_return(@mock_response)
|
58
60
|
@mock_response.should_receive(:get).and_return <<-XML
|
59
61
|
<?xml version="1.0" encoding="UTF-8"?><fedoraRepository xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.fedora.info/definitions/1/0/access/ http://www.fedora.info/definitions/1/0/fedoraRepository.xsd"><repositoryName>Fedora Repository</repositoryName><repositoryBaseURL>http://localhost:8983/fedora</repositoryBaseURL><repositoryVersion>3.3</repositoryVersion><repositoryPID> <PID-namespaceIdentifier>changeme</PID-namespaceIdentifier> <PID-delimiter>:</PID-delimiter> <PID-sample>changeme:100</PID-sample> <retainPID>*</retainPID></repositoryPID><repositoryOAI-identifier> <OAI-namespaceIdentifier>example.org</OAI-namespaceIdentifier> <OAI-delimiter>:</OAI-delimiter> <OAI-sample>oai:example.org:changeme:100</OAI-sample></repositoryOAI-identifier><sampleSearch-URL>http://localhost:8983/fedora/search</sampleSearch-URL><sampleAccess-URL>http://localhost:8983/fedora/get/demo:5</sampleAccess-URL><sampleOAI-URL>http://localhost:8983/fedora/oai?verb=Identify</sampleOAI-URL><adminEmail>bob@example.org</adminEmail><adminEmail>sally@example.org</adminEmail></fedoraRepository>
|
60
62
|
XML
|
61
|
-
@mock_client.should_receive(:[]).with(describe_repository_url(:xml=> true)).and_return(@mock_response)
|
62
|
-
@repository.should_receive(:client).and_return(@mock_client)
|
63
63
|
profile = @repository.profile
|
64
64
|
profile['repositoryVersion'].should == '3.3'
|
65
65
|
end
|
@@ -18,8 +18,8 @@ describe Rubydora::ResourceIndex do
|
|
18
18
|
end
|
19
19
|
|
20
20
|
it "should send sparql queries with appropriate parameters" do
|
21
|
-
@mock_risearch =
|
22
|
-
@mock_client =
|
21
|
+
@mock_risearch = double()
|
22
|
+
@mock_client = double(RestClient::Resource)
|
23
23
|
@mock_risearch.should_receive(:post).with(hash_including(:dt => 'on', :format => 'CSV', :lang => 'sparql', :limit => nil, :query => 'placeholder SPARQL query', :type => 'tuples' ))
|
24
24
|
@mock_client.should_receive(:[]).with('risearch').and_return(@mock_risearch)
|
25
25
|
@mock_repository.should_receive(:client).and_return(@mock_client)
|
@@ -224,7 +224,7 @@ describe Rubydora::RestApiClient do
|
|
224
224
|
RestClient::Request.any_instance.should_receive(:transmit) #stub transmit so that Request.execute can close the file we pass
|
225
225
|
file = StringIO.new('test', 'r') # StringIO is a good stand it for a real File (it has read, rewind and close)
|
226
226
|
@mock_repository.add_datastream :pid => 'mypid', :dsid => 'aaa', :content=>file
|
227
|
-
lambda {file.read}.should_not raise_error
|
227
|
+
lambda {file.read}.should_not raise_error
|
228
228
|
end
|
229
229
|
end
|
230
230
|
end
|
@@ -243,7 +243,7 @@ describe Rubydora::RestApiClient do
|
|
243
243
|
RestClient::Request.any_instance.should_receive(:transmit) #stub transmit so that Request.execute can close the file we pass
|
244
244
|
file = StringIO.new('test', 'r') # StringIO is a good stand it for a real File (it has read, rewind and close)
|
245
245
|
@mock_repository.modify_datastream :pid => 'mypid', :dsid => 'aaa', :content=>file
|
246
|
-
lambda {file.read}.should_not raise_error
|
246
|
+
lambda {file.read}.should_not raise_error
|
247
247
|
end
|
248
248
|
end
|
249
249
|
end
|
@@ -4,8 +4,9 @@ describe Rubydora::Transactions do
|
|
4
4
|
|
5
5
|
|
6
6
|
subject {
|
7
|
-
Rubydora::Repository.any_instance.stub(:version).and_return(100)
|
8
|
-
repository = Rubydora::Repository.new :url => 'http://example.org'
|
7
|
+
# Rubydora::Repository.any_instance.stub(:version).and_return(100)
|
8
|
+
# repository = Rubydora::Repository.new :url => 'http://example.org'
|
9
|
+
Rubydora::Fc3Service.new :url => 'http://example.org'
|
9
10
|
}
|
10
11
|
|
11
12
|
describe "#transaction_is_redundant?" do
|
@@ -69,9 +70,8 @@ describe Rubydora::Transactions do
|
|
69
70
|
it "modify_object" do
|
70
71
|
subject.client.stub_chain(:[], :put).and_return 'asdf'
|
71
72
|
|
72
|
-
|
73
|
-
subject.should_receive(:
|
74
|
-
|
73
|
+
profile_xml = "<objectProfile><objState>A</objState><objOwnerId>567</objOwnerId></objectProfile>"
|
74
|
+
subject.should_receive(:object).with(pid: 'asdf').and_return profile_xml
|
75
75
|
|
76
76
|
subject.transaction do |t|
|
77
77
|
subject.modify_object :pid => 'asdf', :state => 'I', :ownerId => '123', :logMessage => 'changing asdf'
|
@@ -122,9 +122,8 @@ describe Rubydora::Transactions do
|
|
122
122
|
it "set_datastream_options" do
|
123
123
|
subject.client.stub_chain(:[], :put)
|
124
124
|
|
125
|
-
|
126
|
-
|
127
|
-
subject.should_receive(:find).with('asdf').and_return mock_object
|
125
|
+
profile_xml = "<datastreamProfile><dsVersionable>false</dsVersionable></datastreamProfile>"
|
126
|
+
subject.should_receive(:datastream).with(pid: 'asdf', dsid: 'mydsid').and_return profile_xml
|
128
127
|
|
129
128
|
subject.transaction do |t|
|
130
129
|
subject.set_datastream_options :pid => 'asdf', :dsid => 'mydsid', :versionable => true
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubydora
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.0.pre1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Beer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-01-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fastercsv
|
@@ -150,20 +150,6 @@ dependencies:
|
|
150
150
|
- - '>='
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '0'
|
153
|
-
- !ruby/object:Gem::Dependency
|
154
|
-
name: shoulda
|
155
|
-
requirement: !ruby/object:Gem::Requirement
|
156
|
-
requirements:
|
157
|
-
- - '>='
|
158
|
-
- !ruby/object:Gem::Version
|
159
|
-
version: '0'
|
160
|
-
type: :development
|
161
|
-
prerelease: false
|
162
|
-
version_requirements: !ruby/object:Gem::Requirement
|
163
|
-
requirements:
|
164
|
-
- - '>='
|
165
|
-
- !ruby/object:Gem::Version
|
166
|
-
version: '0'
|
167
153
|
- !ruby/object:Gem::Dependency
|
168
154
|
name: bundler
|
169
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -243,10 +229,13 @@ extra_rdoc_files: []
|
|
243
229
|
files:
|
244
230
|
- .gitignore
|
245
231
|
- .gitmodules
|
232
|
+
- .mailmap
|
246
233
|
- .travis.yml
|
234
|
+
- CONTRIBUTING.md
|
247
235
|
- Gemfile
|
248
236
|
- History.textile
|
249
237
|
- LICENSE.txt
|
238
|
+
- Notices.txt
|
250
239
|
- README.rdoc
|
251
240
|
- Rakefile
|
252
241
|
- VERSION
|
@@ -258,8 +247,10 @@ files:
|
|
258
247
|
- lib/rubydora/callbacks.rb
|
259
248
|
- lib/rubydora/datastream.rb
|
260
249
|
- lib/rubydora/digital_object.rb
|
250
|
+
- lib/rubydora/fc3_service.rb
|
261
251
|
- lib/rubydora/fedora_url_helpers.rb
|
262
252
|
- lib/rubydora/models_mixin.rb
|
253
|
+
- lib/rubydora/profile_parser.rb
|
263
254
|
- lib/rubydora/relationships_mixin.rb
|
264
255
|
- lib/rubydora/repository.rb
|
265
256
|
- lib/rubydora/resource_index.rb
|
@@ -291,12 +282,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
291
282
|
version: '0'
|
292
283
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
293
284
|
requirements:
|
294
|
-
- - '
|
285
|
+
- - '>'
|
295
286
|
- !ruby/object:Gem::Version
|
296
|
-
version:
|
287
|
+
version: 1.3.1
|
297
288
|
requirements: []
|
298
289
|
rubyforge_project:
|
299
|
-
rubygems_version: 2.
|
290
|
+
rubygems_version: 2.1.11
|
300
291
|
signing_key:
|
301
292
|
specification_version: 4
|
302
293
|
summary: Fedora Commons REST API ruby library
|