rof 0.0.1.pre → 1.0.4

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.
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