rubydora 1.6.5 → 1.7.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|