rubydora 1.6.3 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.mailmap +8 -0
- data/.travis.yml +6 -2
- data/CONTRIBUTING.md +113 -0
- data/Gemfile +0 -4
- 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.rails3 +11 -0
- data/gemfiles/gemfile.rails4 +10 -0
- data/lib/rubydora/audit_trail.rb +5 -5
- data/lib/rubydora/datastream.rb +15 -53
- data/lib/rubydora/digital_object.rb +19 -44
- data/lib/rubydora/fc3_service.rb +89 -0
- data/lib/rubydora/fedora_url_helpers.rb +23 -4
- data/lib/rubydora/profile_parser.rb +59 -0
- data/lib/rubydora/repository.rb +24 -26
- data/lib/rubydora/rest_api_client.rb +61 -7
- data/lib/rubydora/transactions.rb +8 -7
- data/lib/rubydora.rb +2 -0
- data/rubydora.gemspec +1 -2
- data/spec/audit_trail_spec.rb +1 -1
- data/spec/lib/datastream_spec.rb +54 -15
- data/spec/lib/digital_object_spec.rb +86 -32
- data/spec/lib/integration_test_spec.rb +31 -31
- data/spec/lib/repository_spec.rb +19 -6
- data/spec/lib/resource_index_spec.rb +2 -2
- data/spec/lib/rest_api_client_spec.rb +62 -37
- data/spec/lib/transactions_spec.rb +7 -8
- metadata +14 -21
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: be337fe4d014e05130587d975c1388050ab192e6
|
|
4
|
+
data.tar.gz: 6eca752e25d923e8832c0b24cb2e724a90b932fc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 48229e6eeee8bb507b7914aee56244ba2bf179c75bcb7f61b9c1711860c27cd9cf27ac0f7bff6ced99221c021868f05dd54278a15da897801964abe26857ee0f
|
|
7
|
+
data.tar.gz: 87b6f2cc39e89dd69c39c15f6b5003ae5c99dee2cc04159ab06ff839117289bba4ce70a42c7692c9214624f8a9a27d6d1c9381d9d5009cf0ae9e941a932214b5
|
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/.travis.yml
CHANGED
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/Gemfile
CHANGED
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
|
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
|
|
@@ -100,7 +100,7 @@ module Rubydora
|
|
|
100
100
|
# @param [String] Datastream ID
|
|
101
101
|
# @param [Hash] default attribute values (used esp. for creating new datastreams)
|
|
102
102
|
def initialize digital_object, dsid, options = {}, default_instance_attributes = {}
|
|
103
|
-
|
|
103
|
+
run_callbacks :initialize do
|
|
104
104
|
@digital_object = digital_object
|
|
105
105
|
@dsid = dsid
|
|
106
106
|
@options = options
|
|
@@ -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,62 +260,25 @@ 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
|
|
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
|
|
286
269
|
end
|
|
287
270
|
|
|
288
|
-
def
|
|
289
|
-
|
|
290
|
-
|
|
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
|
|
271
|
+
def versions
|
|
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)
|
|
302
275
|
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
|
|
309
276
|
end
|
|
310
277
|
|
|
311
|
-
def
|
|
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
|
|
318
|
-
end
|
|
278
|
+
def current_version?
|
|
279
|
+
return true if new?
|
|
280
|
+
vers = versions
|
|
281
|
+
return vers.empty? || dsVersionID == vers.first.dsVersionID
|
|
319
282
|
end
|
|
320
283
|
|
|
321
284
|
# Add datastream to Fedora
|
|
@@ -406,7 +369,6 @@ module Rubydora
|
|
|
406
369
|
# @return [Hash]
|
|
407
370
|
def reset_profile_attributes
|
|
408
371
|
@profile = nil
|
|
409
|
-
@profile_xml = nil
|
|
410
372
|
@datastream_content = nil
|
|
411
373
|
@content = nil
|
|
412
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
|
|
|
@@ -40,6 +39,12 @@ module Rubydora
|
|
|
40
39
|
RUBY
|
|
41
40
|
end
|
|
42
41
|
|
|
42
|
+
def state= val
|
|
43
|
+
raise ArgumentError, "Allowed values for state are 'I', 'A' and 'D'. You provided '#{val}'" unless ['I', 'A', 'D'].include?(val)
|
|
44
|
+
state_will_change! unless val == state
|
|
45
|
+
@state = val
|
|
46
|
+
end
|
|
47
|
+
|
|
43
48
|
# Find an existing Fedora object
|
|
44
49
|
#
|
|
45
50
|
# @param [String] pid
|
|
@@ -83,7 +88,7 @@ module Rubydora
|
|
|
83
88
|
# @param [Rubydora::Repository] repository context
|
|
84
89
|
# @param [Hash] options default attribute values (used esp. for creating new datastreams
|
|
85
90
|
def initialize pid, repository = nil, options = {}
|
|
86
|
-
|
|
91
|
+
run_callbacks :initialize do
|
|
87
92
|
self.pid = pid
|
|
88
93
|
@repository = repository
|
|
89
94
|
@options = options
|
|
@@ -94,6 +99,11 @@ module Rubydora
|
|
|
94
99
|
end
|
|
95
100
|
end
|
|
96
101
|
|
|
102
|
+
def audit_trail
|
|
103
|
+
@audit_trail ||= repository.audit_trail(self.pid)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
|
|
97
107
|
##
|
|
98
108
|
# Return a full uri pid (for use in relations, etc
|
|
99
109
|
def uri
|
|
@@ -104,9 +114,10 @@ module Rubydora
|
|
|
104
114
|
|
|
105
115
|
# Does this object already exist?
|
|
106
116
|
# @return [Boolean]
|
|
107
|
-
def
|
|
108
|
-
self.
|
|
117
|
+
def new_record?
|
|
118
|
+
self.profile.empty?
|
|
109
119
|
end
|
|
120
|
+
alias :new? :new_record?
|
|
110
121
|
|
|
111
122
|
def asOfDateTime asOfDateTime = nil
|
|
112
123
|
if asOfDateTime == nil
|
|
@@ -123,49 +134,15 @@ module Rubydora
|
|
|
123
134
|
# Retrieve the object profile as a hash (and cache it)
|
|
124
135
|
# @return [Hash] see Fedora #getObject documentation for keys
|
|
125
136
|
def profile
|
|
126
|
-
return {} if profile_xml.nil?
|
|
127
|
-
|
|
128
137
|
@profile ||= begin
|
|
129
|
-
profile_xml.gsub! '<objectProfile', '<objectProfile xmlns="http://www.fedora.info/definitions/1/0/access/"' unless profile_xml =~ /xmlns=/
|
|
130
|
-
doc = Nokogiri::XML(profile_xml)
|
|
131
|
-
h = doc.xpath('/access:objectProfile/*', {'access' => "http://www.fedora.info/definitions/1/0/access/"} ).inject({}) do |sum, node|
|
|
132
|
-
sum[node.name] ||= []
|
|
133
|
-
sum[node.name] << node.text
|
|
134
|
-
|
|
135
|
-
if node.name == "objModels"
|
|
136
|
-
sum[node.name] = node.xpath('access:model', {'access' => "http://www.fedora.info/definitions/1/0/access/"}).map { |x| x.text }
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
sum
|
|
140
|
-
end.reject { |key, values| values.empty? }
|
|
141
|
-
|
|
142
|
-
h.select { |key, values| values.length == 1 }.each do |key, values|
|
|
143
|
-
next if key == "objModels"
|
|
144
|
-
h[key] = values.reject { |x| x.empty? }.first
|
|
145
|
-
end
|
|
146
138
|
@new = false
|
|
147
|
-
|
|
148
|
-
h
|
|
149
|
-
|
|
139
|
+
repository.object_profile(pid, asOfDateTime)
|
|
150
140
|
end.freeze
|
|
151
141
|
end
|
|
152
142
|
|
|
153
|
-
def profile_xml
|
|
154
|
-
@profile_xml ||= begin
|
|
155
|
-
options = { :pid => pid }
|
|
156
|
-
options[:asOfDateTime] = asOfDateTime if asOfDateTime
|
|
157
|
-
repository.object(options)
|
|
158
|
-
rescue RestClient::ResourceNotFound => e
|
|
159
|
-
''
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
|
|
163
143
|
def versions
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
doc = Nokogiri::XML(versions_xml)
|
|
167
|
-
doc.xpath('//access:objectChangeDate', {'access' => 'http://www.fedora.info/definitions/1/0/access/' } ).map do |changeDate|
|
|
168
|
-
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
|
|
169
146
|
end
|
|
170
147
|
end
|
|
171
148
|
|
|
@@ -212,7 +189,6 @@ module Rubydora
|
|
|
212
189
|
if self.new?
|
|
213
190
|
self.pid = repository.ingest to_api_params.merge(:pid => pid)
|
|
214
191
|
@profile = nil #will cause a reload with updated data
|
|
215
|
-
@profile_xml = nil
|
|
216
192
|
else
|
|
217
193
|
p = to_api_params
|
|
218
194
|
repository.modify_object p.merge(:pid => pid) unless p.empty?
|
|
@@ -231,7 +207,6 @@ module Rubydora
|
|
|
231
207
|
run_callbacks :destroy do
|
|
232
208
|
@datastreams = nil
|
|
233
209
|
@profile = nil
|
|
234
|
-
@profile_xml = nil
|
|
235
210
|
@pid = nil
|
|
236
211
|
nil
|
|
237
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
|