rof 0.0.1.pre → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/.travis.yml +12 -2
  4. data/Gemfile +1 -0
  5. data/README.md +87 -0
  6. data/bin/.ruby-version +1 -0
  7. data/bin/csv_to_rof +26 -0
  8. data/bin/fedora_to_rof +57 -0
  9. data/bin/osf_to_rof +40 -0
  10. data/bin/rof +78 -0
  11. data/bulk-ingest.md +242 -0
  12. data/labels.md +111 -0
  13. data/lib/rof.rb +20 -1
  14. data/lib/rof/access.rb +57 -0
  15. data/lib/rof/cli.rb +122 -0
  16. data/lib/rof/collection.rb +109 -0
  17. data/lib/rof/compare_rof.rb +92 -0
  18. data/lib/rof/filters/bendo.rb +33 -0
  19. data/lib/rof/filters/date_stamp.rb +36 -0
  20. data/lib/rof/filters/file_to_url.rb +27 -0
  21. data/lib/rof/filters/label.rb +153 -0
  22. data/lib/rof/filters/work.rb +111 -0
  23. data/lib/rof/get_from_fedora.rb +196 -0
  24. data/lib/rof/ingest.rb +204 -0
  25. data/lib/rof/ingesters/rels_ext_ingester.rb +78 -0
  26. data/lib/rof/ingesters/rights_metadata_ingester.rb +68 -0
  27. data/lib/rof/osf_context.rb +19 -0
  28. data/lib/rof/osf_to_rof.rb +122 -0
  29. data/lib/rof/rdf_context.rb +36 -0
  30. data/lib/rof/translate_csv.rb +112 -0
  31. data/lib/rof/utility.rb +84 -0
  32. data/lib/rof/version.rb +2 -2
  33. data/rof.gemspec +17 -0
  34. data/spec/fixtures/a.json +4 -0
  35. data/spec/fixtures/label.json +20 -0
  36. data/spec/fixtures/osf/b6psa.tar.gz +0 -0
  37. data/spec/fixtures/rof/dev0012829m.rof +45 -0
  38. data/spec/fixtures/vcr_tests/fedora_to_rof1.yml +5274 -0
  39. data/spec/fixtures/vecnet-citation.json +73 -0
  40. data/spec/lib/rof/access_spec.rb +36 -0
  41. data/spec/lib/rof/cli_spec.rb +66 -0
  42. data/spec/lib/rof/collection_spec.rb +90 -0
  43. data/spec/lib/rof/compare_rof_spec.rb +263 -0
  44. data/spec/lib/rof/filters/date_stamp_spec.rb +90 -0
  45. data/spec/lib/rof/filters/file_to_url_spec.rb +70 -0
  46. data/spec/lib/rof/filters/label_spec.rb +94 -0
  47. data/spec/lib/rof/filters/work_spec.rb +87 -0
  48. data/spec/lib/rof/ingest_spec.rb +117 -0
  49. data/spec/lib/rof/ingesters/rels_ext_ingester_spec.rb +62 -0
  50. data/spec/lib/rof/ingesters/rights_metadata_ingester_spec.rb +114 -0
  51. data/spec/lib/rof/osf_to_rof_spec.rb +76 -0
  52. data/spec/lib/rof/translate_csv_spec.rb +109 -0
  53. data/spec/lib/rof/utility_spec.rb +64 -0
  54. data/spec/lib/rof_spec.rb +14 -0
  55. data/spec/spec_helper.rb +11 -11
  56. metadata +283 -18
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ module ROF
4
+ module Ingesters
5
+ describe RelsExtIngester do
6
+ let(:models) { ["info:fedora/afmodel:Shoe"] }
7
+ let(:item) {
8
+ { "pid" => '1234', "rels-ext" => { "isPartOf" => ["vecnet:d217qs82g"] } }
9
+ }
10
+ let(:fedora_document) { nil }
11
+ let(:expected_content) { "<?xml version='1.0' encoding='utf-8' ?>\n<rdf:RDF xmlns:ns0='info:fedora/fedora-system:def/model#' xmlns:ns1='info:fedora/fedora-system:def/relations-external#' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>\n <rdf:Description rdf:about='info:fedora/1234'>\n <ns0:hasModel rdf:resource='info:fedora/afmodel:Shoe' />\n <ns1:isPartOf rdf:resource='info:fedora/vecnet:d217qs82g' />\n </rdf:Description>\n</rdf:RDF>\n" }
12
+
13
+ subject { described_class.new(models: models, item: item, fedora_document: fedora_document) }
14
+
15
+ context 'without a fedora document' do
16
+ its(:call) { should be_equivalent_to(expected_content) }
17
+ end
18
+
19
+ context 'with a fedora document' do
20
+ let(:fedora_document) { double }
21
+ let(:rels_ext) { double }
22
+ it 'should save the document' do
23
+ expect(fedora_document).to receive(:[]).with('RELS-EXT').and_return(rels_ext)
24
+ expect(rels_ext).to receive(:content=).with(be_equivalent_to(expected_content))
25
+ expect(rels_ext).to receive(:mimeType=).with("application/rdf+xml")
26
+ expect(rels_ext).to receive(:save)
27
+ subject.call
28
+ end
29
+ end
30
+
31
+ context 'it supports other namespaces' do
32
+ let(:item) {
33
+ { "pid" => '1234', "rels-ext" => {
34
+ "@context" => { "ex" => "http://example.com/" },
35
+ "isPartOf" => ["vecnet:d217qs82g", "vecnet:123"],
36
+ "ex:hasAccessCopy" => ["vecnet:234"]
37
+ }
38
+ }
39
+ }
40
+ let(:expected_content) {
41
+ %Q{<?xml version='1.0' encoding='utf-8' ?>
42
+ <rdf:RDF xmlns:ns0='http://example.com/' xmlns:ns1='info:fedora/fedora-system:def/model#' xmlns:ns2='info:fedora/fedora-system:def/relations-external#' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
43
+ <rdf:Description rdf:about='info:fedora/1234'>
44
+ <ns0:hasAccessCopy rdf:resource='info:fedora/vecnet:234' />
45
+ <ns1:hasModel rdf:resource='info:fedora/afmodel:Shoe' />
46
+ <ns2:isPartOf rdf:resource='info:fedora/vecnet:d217qs82g' />
47
+ <ns2:isPartOf rdf:resource='info:fedora/vecnet:123' />
48
+ </rdf:Description>
49
+ </rdf:RDF>\n} }
50
+ let(:fedora_document) { double }
51
+ let(:rels_ext) { double }
52
+ it 'should save the document' do
53
+ expect(fedora_document).to receive(:[]).with('RELS-EXT').and_return(rels_ext)
54
+ expect(rels_ext).to receive(:content=).with(be_equivalent_to(expected_content))
55
+ expect(rels_ext).to receive(:mimeType=).with("application/rdf+xml")
56
+ expect(rels_ext).to receive(:save)
57
+ subject.call
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,114 @@
1
+ require 'spec_helper'
2
+
3
+ module ROF
4
+ module Ingesters
5
+
6
+ describe RightsMetadataIngester do
7
+ before(:all) do
8
+ @rights_ingestor = RightsMetadataIngester.new(item:{})
9
+ end
10
+
11
+ it "formats people and groups" do
12
+ s = @rights_ingestor.format_rights_section("qwerty", "alice", ["bob", "carol"])
13
+ expect(s).to eq <<-EOS
14
+ <access type="qwerty">
15
+ <human/>
16
+ <machine>
17
+ <person>alice</person>
18
+ <group>bob</group>
19
+ <group>carol</group>
20
+ </machine>
21
+ </access>
22
+ EOS
23
+ end
24
+
25
+ it "handles no people or groups" do
26
+ s = @rights_ingestor.format_rights_section("qwerty", nil, nil)
27
+ expect(s).to eq <<-EOS
28
+ <access type="qwerty">
29
+ <human/>
30
+ <machine/>
31
+ </access>
32
+ EOS
33
+ end
34
+
35
+ it "works with simple cases" do
36
+ item = {"rights" => {"read-groups" => ["restricted", "abc"],
37
+ "read" => ["joe"],
38
+ "edit" => ["anna"],
39
+ "edit-groups" => ["admins"]
40
+ }}
41
+ expected_content = %q{<rightsMetadata xmlns="http://hydra-collab.stanford.edu/schemas/rightsMetadata/v1" version="0.1">
42
+ <copyright>
43
+ <human type="title"/>
44
+ <human type="description"/>
45
+ <machine type="uri"/>
46
+ </copyright>
47
+ <access type="discover">
48
+ <human/>
49
+ <machine/>
50
+ </access>
51
+ <access type="read">
52
+ <human/>
53
+ <machine>
54
+ <person>joe</person>
55
+ <group>restricted</group>
56
+ <group>abc</group>
57
+ </machine>
58
+ </access>
59
+ <access type="edit">
60
+ <human/>
61
+ <machine>
62
+ <person>anna</person>
63
+ <group>admins</group>
64
+ </machine>
65
+ </access>
66
+ <embargo>
67
+ <human/>
68
+ <machine/>
69
+ </embargo>
70
+ </rightsMetadata>
71
+ }
72
+ expect(RightsMetadataIngester.call(item: item)).to eq(expected_content)
73
+ end
74
+
75
+ it "handles embargo dates" do
76
+ item = {"rights" => {"read-groups" => ["public"],
77
+ "edit" => ["rbalekai"],
78
+ "embargo-date" => "2015-01-01"
79
+ }}
80
+ expected_content = %q{<rightsMetadata xmlns="http://hydra-collab.stanford.edu/schemas/rightsMetadata/v1" version="0.1">
81
+ <copyright>
82
+ <human type="title"/>
83
+ <human type="description"/>
84
+ <machine type="uri"/>
85
+ </copyright>
86
+ <access type="discover">
87
+ <human/>
88
+ <machine/>
89
+ </access>
90
+ <access type="read">
91
+ <human/>
92
+ <machine>
93
+ <group>public</group>
94
+ </machine>
95
+ </access>
96
+ <access type="edit">
97
+ <human/>
98
+ <machine>
99
+ <person>rbalekai</person>
100
+ </machine>
101
+ </access>
102
+ <embargo>
103
+ <human/>
104
+ <machine>
105
+ <date>2015-01-01</date>
106
+ </machine>
107
+ </embargo>
108
+ </rightsMetadata>
109
+ }
110
+ expect(RightsMetadataIngester.call(item: item)).to eq(expected_content)
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe ROF::OsfToRof do
4
+ it "converts an OSF Archive tar,gz to an ROF", memfs: true do
5
+ #Test file dirs
6
+ test_dir = Dir.mktmpdir('FROM_OSF')
7
+ ttl_dir = FileUtils.mkdir_p(File.join(test_dir, 'b6psa/data/obj/root'))
8
+
9
+ # tar and ttl files
10
+ tar_file = File.join(test_dir, 'b6psa.tar.gz')
11
+ proj_ttl_file = File.join(ttl_dir, 'b6psa.ttl')
12
+ user_ttl_file = File.join(ttl_dir, 'qpru8.ttl')
13
+
14
+ config = { 'package_dir' => "#{test_dir}" }
15
+ osf_project = {
16
+ "project_identifier" => "b6psa",
17
+ "administrative_unit" => "Library",
18
+ "owner" => "msuhovec",
19
+ "affiliation" => "OddFellows Local 151",
20
+ "status" => "submitted",
21
+ }
22
+
23
+ expected_rof = [{"owner"=>"msuhovec",
24
+ "type"=>"OsfArchive",
25
+ "rights"=>{"read-groups"=>["public"]},
26
+ "rels-ext"=> {"@context"=> {"@vocab"=>"info:fedora/fedora-system:def/relations-external#",
27
+ "fedora-model"=>"info:fedora/fedora-system:def/model#",
28
+ "hydra"=>"http://projecthydra.org/ns/relations#",
29
+ "hasModel"=>{"@id"=>"fedora-model:hasModel", "@type"=>"@id"},
30
+ "hasEditor"=>{"@id"=>"hydra:hasEditor", "@type"=>"@id"},
31
+ "hasEditorGroup"=>{"@id"=>"hydra:hasEditorGroup", "@type"=>"@id"},
32
+ "isPartOf"=>{"@type"=>"@id"},
33
+ "isMemberOfCollection"=>{"@type"=>"@id"},
34
+ "isEditorOf"=>{"@id"=>"hydra:isEditorOf", "@type"=>"@id"},
35
+ "hasMember"=>{"@type"=>"@id"},
36
+ "previousVersion"=>"http://purl.org/pav/previousVersion"}},
37
+ "metadata"=> {"@context"=> {"bibo"=>"http://purl.org/ontology/bibo/",
38
+ "dc"=>"http://purl.org/dc/terms/",
39
+ "ebucore"=>"http://www.ebu.ch/metadata/ontologies/ebucore/ebucore#",
40
+ "foaf"=>"http://xmlns.com/foaf/0.1/",
41
+ "mrel"=>"http://id.loc.gov/vocabulary/relators/",
42
+ "nd"=>"https://library.nd.edu/ns/terms/",
43
+ "rdfs"=>"http://www.w3.org/2000/01/rdf-schema#",
44
+ "vracore"=>"http://purl.org/vra/",
45
+ "dc:dateSubmitted"=>{"@type"=>"http://www.w3.org/2001/XMLSchema#date"},
46
+ "dc:created"=>{"@type"=>"http://www.w3.org/2001/XMLSchema#date"},
47
+ "dc:modified"=>{"@type"=>"http://www.w3.org/2001/XMLSchema#date"}},
48
+ "dc:created"=>"2016-09-06Z",
49
+ "dc:title"=>"OSFNonInstProj1",
50
+ "dc:description"=>"",
51
+ "dc:subject"=>"",
52
+ "dc:source"=>"https://osf.io/b6psa",
53
+ "dc:creator#adminstrative_unit"=>"Library",
54
+ "dc:creator#affiliation"=>"OddFellows Local 151",
55
+ "dc:creator"=>"Mark Suhovecky"},
56
+ "files"=>["b6psa.tar.gz"]}]
57
+
58
+ FileUtils.cp('spec/fixtures/osf/b6psa.tar.gz', tar_file)
59
+
60
+ begin
61
+ expect(File.exists?(proj_ttl_file)).to be false
62
+ expect(File.exists?(user_ttl_file)).to be false
63
+
64
+ rof = ROF::OsfToRof.osf_to_rof(config, osf_project)
65
+
66
+ expect(rof).to eq( expected_rof )
67
+
68
+ # ingested history should be created
69
+ expect(File.exists?(proj_ttl_file)).to be true
70
+ expect(File.exists?(user_ttl_file)).to be true
71
+ ensure
72
+ # remove the directory.
73
+ FileUtils.remove_entry test_dir
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,109 @@
1
+ require 'spec_helper'
2
+
3
+ module ROF
4
+ describe "translate CSV" do
5
+ it "requires the columns type and owner" do
6
+ s = "dc:title,access,owner"
7
+ expect{TranslateCSV.run(s)}.to raise_error(ROF::TranslateCSV::MissingOwnerOrType)
8
+
9
+ s = "dc:title,access,type"
10
+ expect{TranslateCSV.run(s)}.to raise_error(ROF::TranslateCSV::MissingOwnerOrType)
11
+
12
+ s = "dc:title,type,owner,access"
13
+ expect(TranslateCSV.run(s)).to eq([])
14
+ end
15
+
16
+ it "requires rows to have an owner and type" do
17
+ s = %q{type,owner
18
+ Work,
19
+ }
20
+ expect{TranslateCSV.run(s)}.to raise_error(ROF::TranslateCSV::MissingOwnerOrType)
21
+ end
22
+
23
+ it "deocdes the access field into rights" do
24
+ s = %q{type,owner,access
25
+ Work,user1,"private;edit=user2,user3"
26
+ }
27
+ rof = TranslateCSV.run(s)
28
+ expect(rof).to eq([{"type" => "Work", "owner" => "user1", "rights" => {"edit" => ["user1", "user2", "user3"]}}])
29
+ end
30
+
31
+ it "puts metadata into substructure" do
32
+ s = %q{type,owner,dc:title,foaf:name
33
+ Work,user1,"Q, A Letter",Jane Smith|Zander
34
+ }
35
+ rof = TranslateCSV.run(s)
36
+ expect(rof).to eq([{
37
+ "type" => "Work",
38
+ "owner" => "user1",
39
+ "rights" => {"edit" => ["user1"]},
40
+ "metadata" => {
41
+ "@context" => RdfContext,
42
+ "dc:title" => "Q, A Letter",
43
+ "foaf:name" => ["Jane Smith", "Zander"]}
44
+ }])
45
+ end
46
+
47
+ it "renames curate_id to pid" do
48
+ s = %q{type,owner,curate_id
49
+ Work,user1,abcdefg
50
+ }
51
+ rof = TranslateCSV.run(s)
52
+ expect(rof).to eq([{
53
+ "type" => "Work",
54
+ "owner" => "user1",
55
+ "pid" => "abcdefg",
56
+ "rights" => {"edit" => ["user1"]}
57
+ }])
58
+ end
59
+
60
+ it "strips space around pipes" do
61
+ s = %q{type,owner,dc:title,foaf:name
62
+ Work,user1,"Q, A Letter",Jane Smith | Zander
63
+ }
64
+ rof = TranslateCSV.run(s)
65
+ expect(rof).to eq([{
66
+ "type" => "Work",
67
+ "owner" => "user1",
68
+ "rights" => {"edit" => ["user1"]},
69
+ "metadata" => {
70
+ "@context" => RdfContext,
71
+ "dc:title" => "Q, A Letter",
72
+ "foaf:name" => ["Jane Smith", "Zander"]}
73
+ }])
74
+ end
75
+
76
+ it "handles follow-on generic files" do
77
+ s = %q{type,owner,dc:title,files
78
+ Work,user1,"Q, A Letter",thumb
79
+ +,user1,,extra file.txt
80
+ }
81
+ rof = TranslateCSV.run(s)
82
+ expect(rof).to eq([{
83
+ "type" => "Work",
84
+ "owner" => "user1",
85
+ "rights" => {"edit" => ["user1"]},
86
+ "metadata" => {
87
+ "@context" => RdfContext,
88
+ "dc:title" => "Q, A Letter"},
89
+ "files" => [
90
+ "thumb",
91
+ {
92
+ "type" => "+",
93
+ "owner" => "user1",
94
+ "files" => ["extra file.txt"],
95
+ "rights" => {"edit" => ["user1"]}
96
+ }]
97
+ }])
98
+ end
99
+
100
+ it "raises an error if a follow-on file has no preceeding work" do
101
+ s = %q{type,owner,dc:title,files
102
+ +,user1,,extra file.txt
103
+ }
104
+ expect {TranslateCSV.run(s)}.to raise_error(ROF::TranslateCSV::NoPriorWork)
105
+ end
106
+
107
+
108
+ end
109
+ end
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ module ROF
4
+ RSpec.describe Utility do
5
+ let(:util) { described_class.new }
6
+
7
+ describe 'prop_ds' do
8
+ context 'set properties with representative' do
9
+ subject { described_class.prop_ds('msuhovec', 'temp:1234') }
10
+ it { is_expected.to eq "<fields><depositor>batch_ingest</depositor>\n<owner>msuhovec</owner>\n<representative>temp:1234</representative>\n</fields>\n" }
11
+ end
12
+
13
+ context 'set properties without representative' do
14
+ subject { described_class.prop_ds('msuhovec') }
15
+ it { is_expected.to eq "<fields><depositor>batch_ingest</depositor>\n<owner>msuhovec</owner>\n</fields>\n" }
16
+ end
17
+ end
18
+ describe 'next_label' do
19
+ let(:id) { util.next_label}
20
+
21
+ it 'assigns initial label' do
22
+ expect(id).to eq '$(pid--0)'
23
+ end
24
+ end
25
+
26
+ describe 'decode_work_type' do
27
+
28
+ context 'decode article' do
29
+ subject { util.decode_work_type({'type' => 'article'}) }
30
+ it { is_expected.to eq('Article')}
31
+ end
32
+
33
+ context 'decode dataset' do
34
+ subject { util.decode_work_type({'type' => 'dataset'}) }
35
+ it { is_expected.to eq('Dataset')}
36
+ end
37
+
38
+ context 'decode document' do
39
+ subject { util.decode_work_type({'type' => 'document'}) }
40
+ it { is_expected.to eq('Document')}
41
+ end
42
+
43
+ context 'decode collection' do
44
+ subject { util.decode_work_type({'type' => 'collection'}) }
45
+ it { is_expected.to eq('Collection')}
46
+ end
47
+
48
+ context 'decode etd' do
49
+ subject { util.decode_work_type({'type' => 'etd'}) }
50
+ it { is_expected.to eq('Etd')}
51
+ end
52
+
53
+ context 'test downcase etd' do
54
+ subject { util.decode_work_type({'type' => 'ETD'}) }
55
+ it { is_expected.to eq('Etd')}
56
+ end
57
+
58
+ context 'test image' do
59
+ subject { util.decode_work_type({'type' => 'image'}) }
60
+ it { is_expected.to eq('Image')}
61
+ end
62
+ end
63
+ end
64
+ end
@@ -1,5 +1,19 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe ROF do
4
+ context '.validate' do
4
5
 
6
+ end
7
+
8
+ context '.create' do
9
+
10
+ end
11
+
12
+ context '.update' do
13
+
14
+ end
15
+
16
+ context '.patch' do
17
+
18
+ end
5
19
  end