active-fedora 9.10.4 → 9.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/History.txt +0 -13
- data/lib/active_fedora.rb +7 -0
- data/lib/active_fedora/aggregation.rb +11 -0
- data/lib/active_fedora/aggregation/base_extension.rb +17 -0
- data/lib/active_fedora/aggregation/list_source.rb +103 -0
- data/lib/active_fedora/aggregation/ordered_reader.rb +27 -0
- data/lib/active_fedora/aggregation/proxy.rb +18 -0
- data/lib/active_fedora/associations.rb +40 -0
- data/lib/active_fedora/associations/builder/aggregation.rb +51 -0
- data/lib/active_fedora/associations/builder/filter.rb +18 -0
- data/lib/active_fedora/associations/builder/orders.rb +63 -0
- data/lib/active_fedora/associations/filter_association.rb +71 -0
- data/lib/active_fedora/associations/orders_association.rb +149 -0
- data/lib/active_fedora/attached_files.rb +2 -1
- data/lib/active_fedora/attribute_methods.rb +4 -4
- data/lib/active_fedora/autosave_association.rb +14 -0
- data/lib/active_fedora/base.rb +1 -0
- data/lib/active_fedora/cleaner.rb +1 -1
- data/lib/active_fedora/errors.rb +3 -0
- data/lib/active_fedora/fedora.rb +17 -7
- data/lib/active_fedora/file/streaming.rb +13 -4
- data/lib/active_fedora/orders.rb +12 -0
- data/lib/active_fedora/orders/collection_proxy.rb +8 -0
- data/lib/active_fedora/orders/list_node.rb +161 -0
- data/lib/active_fedora/orders/ordered_list.rb +264 -0
- data/lib/active_fedora/orders/target_proxy.rb +60 -0
- data/lib/active_fedora/reflection.rb +215 -42
- data/lib/active_fedora/validations.rb +1 -1
- data/lib/active_fedora/version.rb +1 -1
- data/lib/generators/active_fedora/config/solr/templates/solr/config/schema.xml +1 -1
- data/solr/config/schema.xml +1 -1
- data/spec/integration/attributes_spec.rb +8 -0
- data/spec/integration/file_spec.rb +22 -0
- data/spec/integration/has_many_associations_spec.rb +23 -0
- data/spec/integration/versionable_spec.rb +6 -6
- data/spec/unit/active_fedora_spec.rb +1 -1
- data/spec/unit/aggregation/list_source_spec.rb +134 -0
- data/spec/unit/aggregation/ordered_reader_spec.rb +43 -0
- data/spec/unit/fedora_spec.rb +1 -1
- data/spec/unit/filter_spec.rb +133 -0
- data/spec/unit/ordered_spec.rb +369 -0
- data/spec/unit/orders/list_node_spec.rb +151 -0
- data/spec/unit/orders/ordered_list_spec.rb +335 -0
- data/spec/unit/orders/reflection_spec.rb +22 -0
- data/spec/unit/reflection_spec.rb +2 -4
- metadata +25 -3
@@ -103,7 +103,7 @@
|
|
103
103
|
http://wiki.apache.org/solr/SolrAdaptersForLuceneSpatial4
|
104
104
|
-->
|
105
105
|
<fieldType name="location_rpt" class="solr.SpatialRecursivePrefixTreeFieldType"
|
106
|
-
geo="true" distErrPct="0.025" maxDistErr="0.000009"
|
106
|
+
geo="true" distErrPct="0.025" maxDistErr="0.000009" distanceUnits="degrees" />
|
107
107
|
|
108
108
|
<fieldType name="text" class="solr.TextField" omitNorms="false">
|
109
109
|
<analyzer>
|
data/solr/config/schema.xml
CHANGED
@@ -103,7 +103,7 @@
|
|
103
103
|
http://wiki.apache.org/solr/SolrAdaptersForLuceneSpatial4
|
104
104
|
-->
|
105
105
|
<fieldType name="location_rpt" class="solr.SpatialRecursivePrefixTreeFieldType"
|
106
|
-
geo="true" distErrPct="0.025" maxDistErr="0.000009"
|
106
|
+
geo="true" distErrPct="0.025" maxDistErr="0.000009" distanceUnits="degrees" />
|
107
107
|
|
108
108
|
<fieldType name="text" class="solr.TextField" omitNorms="false">
|
109
109
|
<analyzer>
|
@@ -147,4 +147,12 @@ describe "delegating attributes" do
|
|
147
147
|
end
|
148
148
|
end
|
149
149
|
end
|
150
|
+
|
151
|
+
describe 'dangerous attributes' do
|
152
|
+
it 'raises an exception if a dangerous attribute is defined' do
|
153
|
+
Deprecation.silence(ActiveFedora::Attributes) do
|
154
|
+
expect { TitledObject.has_attributes :save, datastream: 'foo', multiple: false }.to raise_error ActiveFedora::DangerousAttributeError
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
150
158
|
end
|
@@ -149,6 +149,28 @@ describe ActiveFedora::File do
|
|
149
149
|
it { should eq 'two2thre' }
|
150
150
|
end
|
151
151
|
end
|
152
|
+
|
153
|
+
context "when the request results in a redirect" do
|
154
|
+
before do
|
155
|
+
test_object.add_file('one1two2threfour', path: 'webm', mime_type: 'video/webm')
|
156
|
+
test_object.add_file('', path: 'redirector', mime_type: "message/external-body; access-type=URL; url=\"#{test_object.webm.uri}\"")
|
157
|
+
test_object.save!
|
158
|
+
end
|
159
|
+
subject { str = ''; test_object.redirector.stream.each { |chunk| str << chunk }; str }
|
160
|
+
it { should eq 'one1two2threfour' }
|
161
|
+
end
|
162
|
+
|
163
|
+
context "when there are more than 3 requests because of redirects" do
|
164
|
+
before do
|
165
|
+
test_object.add_file('', path: 'one', mime_type: "message/external-body; access-type=URL; url=\"#{test_object.attached_files[path].uri}\"")
|
166
|
+
test_object.add_file('', path: 'two', mime_type: "message/external-body; access-type=URL; url=\"#{test_object.one.uri}\"")
|
167
|
+
test_object.add_file('', path: 'three', mime_type: "message/external-body; access-type=URL; url=\"#{test_object.two.uri}\"")
|
168
|
+
test_object.save!
|
169
|
+
end
|
170
|
+
it "raises a HTTP redirect too deep Error" do
|
171
|
+
expect { test_object.three.stream.each { |chunk| chunk } }.to raise_error('HTTP redirect too deep')
|
172
|
+
end
|
173
|
+
end
|
152
174
|
end
|
153
175
|
end
|
154
176
|
end
|
@@ -423,4 +423,27 @@ describe ActiveFedora::Associations::HasManyAssociation do
|
|
423
423
|
end
|
424
424
|
end
|
425
425
|
end
|
426
|
+
|
427
|
+
describe "when destroying the owner" do
|
428
|
+
before do
|
429
|
+
class Book < ActiveFedora::Base
|
430
|
+
has_many :permissions, dependent: :destroy
|
431
|
+
end
|
432
|
+
|
433
|
+
class Permission < ActiveFedora::Base
|
434
|
+
belongs_to :book, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.hasConstituent
|
435
|
+
end
|
436
|
+
end
|
437
|
+
let(:book) { Book.create! }
|
438
|
+
let!(:permissions) { Permission.create!(book: book) }
|
439
|
+
|
440
|
+
after do
|
441
|
+
Object.send(:remove_const, :Book)
|
442
|
+
Object.send(:remove_const, :Permission)
|
443
|
+
end
|
444
|
+
|
445
|
+
it "the object is destroyed" do
|
446
|
+
expect { book.destroy }.to change { Permission.count }.by(-1)
|
447
|
+
end
|
448
|
+
end
|
426
449
|
end
|
@@ -179,8 +179,8 @@ describe ActiveFedora::Versionable do
|
|
179
179
|
@original_size = subject.size
|
180
180
|
end
|
181
181
|
|
182
|
-
it "
|
183
|
-
expect(subject.
|
182
|
+
it "links to versions endpoint" do
|
183
|
+
expect(subject.metadata.ldp_source.graph.query(predicate: ::RDF::Vocab::Fcrepo4.hasVersions).objects).to_not be_empty
|
184
184
|
end
|
185
185
|
|
186
186
|
it "has one version" do
|
@@ -305,8 +305,8 @@ describe ActiveFedora::Versionable do
|
|
305
305
|
@original_size = subject.size
|
306
306
|
end
|
307
307
|
|
308
|
-
it "
|
309
|
-
expect(subject.
|
308
|
+
it "links to versions endpoint" do
|
309
|
+
expect(subject.metadata.ldp_source.graph.query(predicate: ::RDF::Vocab::Fcrepo4.hasVersions).objects).to_not be_empty
|
310
310
|
end
|
311
311
|
|
312
312
|
it "has one version" do
|
@@ -427,8 +427,8 @@ describe ActiveFedora::Versionable do
|
|
427
427
|
subject.create_version
|
428
428
|
end
|
429
429
|
|
430
|
-
it "
|
431
|
-
expect(subject.
|
430
|
+
it "links to versions endpoint" do
|
431
|
+
expect(subject.metadata.ldp_source.graph.query(predicate: ::RDF::Vocab::Fcrepo4.hasVersions).objects).to_not be_empty
|
432
432
|
end
|
433
433
|
|
434
434
|
it "has one version" do
|
@@ -28,7 +28,7 @@ describe ActiveFedora do
|
|
28
28
|
it "does not connect and warn" do
|
29
29
|
expect(ActiveFedora::Base.logger).to receive(:warn)
|
30
30
|
expect {
|
31
|
-
ActiveFedora::Fedora.new(url: bad_url, base_path: '/test', user: user, password: password)
|
31
|
+
ActiveFedora::Fedora.new(url: bad_url, base_path: '/test', user: user, password: password).connection
|
32
32
|
}.to raise_error Ldp::HttpError
|
33
33
|
end
|
34
34
|
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe ActiveFedora::Aggregation::ListSource do
|
4
|
+
subject { described_class.new }
|
5
|
+
|
6
|
+
describe "#head" do
|
7
|
+
it "is nil by default" do
|
8
|
+
expect(subject.head).to eq nil
|
9
|
+
end
|
10
|
+
|
11
|
+
it "is settable" do
|
12
|
+
subject.head = RDF::URI("test.org")
|
13
|
+
|
14
|
+
expect(subject.head_id.first).to eq RDF::URI("test.org")
|
15
|
+
end
|
16
|
+
|
17
|
+
it "maps to IANA.first" do
|
18
|
+
expect(subject.class.properties["head"].predicate).to eq ::RDF::Vocab::IANA["first"]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#order_will_change!" do
|
23
|
+
it "marks it as changed" do
|
24
|
+
expect(subject).not_to be_changed
|
25
|
+
subject.order_will_change!
|
26
|
+
expect(subject).to be_changed
|
27
|
+
expect(subject.ordered_self).to be_changed
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#tail" do
|
32
|
+
it "is nil by default" do
|
33
|
+
expect(subject.tail).to eq nil
|
34
|
+
end
|
35
|
+
|
36
|
+
it "is settable" do
|
37
|
+
subject.tail = RDF::URI("test.org")
|
38
|
+
|
39
|
+
expect(subject.tail_id.first).to eq RDF::URI("test.org")
|
40
|
+
end
|
41
|
+
|
42
|
+
it "maps to IANA.last" do
|
43
|
+
expect(subject.class.properties["tail"].predicate).to eq ::RDF::Vocab::IANA["last"]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#changed?" do
|
48
|
+
context "when nothing has changed" do
|
49
|
+
it "is false" do
|
50
|
+
expect(subject).not_to be_changed
|
51
|
+
end
|
52
|
+
end
|
53
|
+
context "when the ordered list is changed" do
|
54
|
+
it "is true" do
|
55
|
+
allow(subject.ordered_self).to receive(:changed?).and_return(true)
|
56
|
+
|
57
|
+
expect(subject).to be_changed
|
58
|
+
end
|
59
|
+
end
|
60
|
+
context "when the ordered list is not changed" do
|
61
|
+
it "is false" do
|
62
|
+
allow(subject.ordered_self).to receive(:changed?).and_return(false)
|
63
|
+
|
64
|
+
expect(subject).not_to be_changed
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "#save" do
|
70
|
+
context "when nothing has changed" do
|
71
|
+
it "does not persist ordered_self" do
|
72
|
+
allow(subject.ordered_self).to receive(:to_graph)
|
73
|
+
|
74
|
+
subject.save
|
75
|
+
|
76
|
+
expect(subject.ordered_self).not_to have_received(:to_graph)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
context "when attributes have changed, but not ordered list" do
|
80
|
+
it "does not persist ordered self" do
|
81
|
+
allow(subject.ordered_self).to receive(:to_graph)
|
82
|
+
subject.nodes += [RDF::URI("http://test.org")]
|
83
|
+
|
84
|
+
subject.save
|
85
|
+
|
86
|
+
expect(subject.ordered_self).not_to have_received(:to_graph)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
context "when ordered list has changed" do
|
90
|
+
it "persists it" do
|
91
|
+
allow(subject.ordered_self).to receive(:to_graph).and_call_original
|
92
|
+
allow(subject.ordered_self).to receive(:changed?).and_return(true)
|
93
|
+
|
94
|
+
subject.save
|
95
|
+
|
96
|
+
expect(subject.ordered_self).to have_received(:to_graph)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "#serializable_hash" do
|
102
|
+
it "does not serialize nodes" do
|
103
|
+
subject.nodes += [RDF::URI("http://test.org")]
|
104
|
+
|
105
|
+
expect(subject.serializable_hash).not_to have_key "nodes"
|
106
|
+
end
|
107
|
+
it "does not serialize head" do
|
108
|
+
subject.head = RDF::URI("http://test.org")
|
109
|
+
|
110
|
+
expect(subject.serializable_hash).not_to have_key "head"
|
111
|
+
end
|
112
|
+
it "does not serialize tail" do
|
113
|
+
subject.tail = RDF::URI("http://test.org")
|
114
|
+
|
115
|
+
expect(subject.serializable_hash).not_to have_key "tail"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "#to_solr" do
|
120
|
+
before do
|
121
|
+
class Member < ActiveFedora::Base
|
122
|
+
end
|
123
|
+
end
|
124
|
+
after do
|
125
|
+
Object.send(:remove_const, :Member)
|
126
|
+
end
|
127
|
+
it "can index" do
|
128
|
+
m = Member.create
|
129
|
+
proxy_in = RDF::URI(ActiveFedora::Base.translate_id_to_uri.call("banana"))
|
130
|
+
subject.ordered_self.append_target m, proxy_in: proxy_in
|
131
|
+
expect(subject.to_solr).to include ordered_targets_ssim: [m.id], proxy_in_ssi: "banana"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe ActiveFedora::Aggregation::OrderedReader do
|
4
|
+
subject { described_class.new(root) }
|
5
|
+
let(:root) { instance_double(ActiveFedora::Aggregation::ListSource) }
|
6
|
+
|
7
|
+
describe "#each" do
|
8
|
+
it "iterates a linked list" do
|
9
|
+
head = build_node
|
10
|
+
tail = build_node(prev_node: head)
|
11
|
+
allow(head).to receive(:next).and_return(tail)
|
12
|
+
allow(root).to receive(:head).and_return(head)
|
13
|
+
expect(subject.to_a).to eq [head, tail]
|
14
|
+
end
|
15
|
+
it "only goes as deep as necessary" do
|
16
|
+
head = build_node
|
17
|
+
tail = build_node(prev_node: head)
|
18
|
+
allow(head).to receive(:next).and_return(tail)
|
19
|
+
allow(root).to receive(:head).and_return(head)
|
20
|
+
expect(subject.first).to eq head
|
21
|
+
expect(head).not_to have_received(:next)
|
22
|
+
end
|
23
|
+
context "when the prev is wrong" do
|
24
|
+
it "fixes it up" do
|
25
|
+
head = build_node
|
26
|
+
bad_node = build_node
|
27
|
+
tail = build_node(prev_node: bad_node)
|
28
|
+
allow(head).to receive(:next).and_return(tail)
|
29
|
+
allow(root).to receive(:head).and_return(head)
|
30
|
+
allow(tail).to receive(:prev=)
|
31
|
+
expect(subject.to_a).to eq [head, tail]
|
32
|
+
expect(tail).to have_received(:prev=).with(head)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def build_node(prev_node: nil, next_node: nil)
|
38
|
+
node = instance_double(ActiveFedora::Orders::ListNode)
|
39
|
+
allow(node).to receive(:next).and_return(next_node)
|
40
|
+
allow(node).to receive(:prev).and_return(prev_node)
|
41
|
+
node
|
42
|
+
end
|
43
|
+
end
|
data/spec/unit/fedora_spec.rb
CHANGED
@@ -12,7 +12,7 @@ describe ActiveFedora::Fedora do
|
|
12
12
|
}
|
13
13
|
}
|
14
14
|
specify {
|
15
|
-
expect(Faraday).to receive(:new).with("https://example.com", ssl: { ca_path: '/path/to/certs' }).
|
15
|
+
expect(Faraday).to receive(:new).with("https://example.com", ssl: { ca_path: '/path/to/certs' }).and_call_original
|
16
16
|
subject.authorized_connection
|
17
17
|
}
|
18
18
|
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveFedora::Associations::FilterAssociation do
|
4
|
+
before do
|
5
|
+
class Image < ActiveFedora::Base
|
6
|
+
ordered_aggregation :members, through: :list_source, class_name: 'ActiveFedora::Base'
|
7
|
+
|
8
|
+
filters_association :members, as: :child_objects, condition: :pcdm_object?
|
9
|
+
filters_association :members, as: :child_collections, condition: :pcdm_collection?
|
10
|
+
end
|
11
|
+
|
12
|
+
class TestObject < ActiveFedora::Base
|
13
|
+
def pcdm_object?
|
14
|
+
true
|
15
|
+
end
|
16
|
+
|
17
|
+
def pcdm_collection?
|
18
|
+
false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class TestCollection < ActiveFedora::Base
|
23
|
+
def pcdm_object?
|
24
|
+
false
|
25
|
+
end
|
26
|
+
|
27
|
+
def pcdm_collection?
|
28
|
+
true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
after do
|
34
|
+
Object.send(:remove_const, :Image)
|
35
|
+
Object.send(:remove_const, :TestObject)
|
36
|
+
Object.send(:remove_const, :TestCollection)
|
37
|
+
end
|
38
|
+
|
39
|
+
let(:image) { Image.new }
|
40
|
+
let(:test_object) { TestObject.new }
|
41
|
+
let(:test_collection) { TestCollection.new }
|
42
|
+
|
43
|
+
describe "setting" do
|
44
|
+
context "when an incorrect object type is sent" do
|
45
|
+
it "raises an error" do
|
46
|
+
image.child_collections
|
47
|
+
expect { image.child_collections = [test_object] }.to raise_error ArgumentError
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when the parent is already loaded" do
|
52
|
+
let(:another_collection) { TestCollection.new }
|
53
|
+
before do
|
54
|
+
image.members = [test_object, test_collection]
|
55
|
+
image.child_collections = [another_collection]
|
56
|
+
end
|
57
|
+
it "overwrites existing matches" do
|
58
|
+
expect(image.members).to eq [test_object, another_collection]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "appending" do
|
64
|
+
context "when an incorrect object type is sent" do
|
65
|
+
it "raises an error" do
|
66
|
+
expect { image.child_collections << test_object }.to raise_error ArgumentError
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context "when the parent is already loaded" do
|
71
|
+
let(:another_collection) { TestCollection.new }
|
72
|
+
before do
|
73
|
+
image.members = [test_object, test_collection]
|
74
|
+
image.child_collections << [another_collection]
|
75
|
+
end
|
76
|
+
|
77
|
+
it "updates the parent" do
|
78
|
+
expect(image.members).to eq [test_object, test_collection, another_collection]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "#size" do
|
84
|
+
it "returns the size" do
|
85
|
+
# Need to persist so that count_records will be called.
|
86
|
+
image.save
|
87
|
+
test_object.save
|
88
|
+
image.members = [test_object]
|
89
|
+
|
90
|
+
expect(image.reload.child_objects.size).to eq 1
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "reading" do
|
95
|
+
before do
|
96
|
+
image.members = [test_object, test_collection]
|
97
|
+
end
|
98
|
+
|
99
|
+
it "returns the objects of the correct type" do
|
100
|
+
expect(image.child_objects).to eq [test_object]
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "when the parent association is changed" do
|
104
|
+
before do
|
105
|
+
image.child_objects = [test_object]
|
106
|
+
image.child_objects.to_a # this would cause the @target of the association to be populated
|
107
|
+
image.members = [test_collection]
|
108
|
+
end
|
109
|
+
|
110
|
+
it "updates the filtered relation" do
|
111
|
+
expect(image.child_objects).to eq []
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "#_ids" do
|
116
|
+
it "returns just the ids" do
|
117
|
+
expect(image.child_object_ids).to eq [test_object.id]
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe "#delete" do
|
123
|
+
let(:another_object) { TestObject.new }
|
124
|
+
before do
|
125
|
+
image.members = [test_object, test_collection, another_object]
|
126
|
+
image.child_objects.delete(test_object)
|
127
|
+
end
|
128
|
+
|
129
|
+
subject { image.members }
|
130
|
+
|
131
|
+
it { is_expected.to eq [test_collection, another_object] }
|
132
|
+
end
|
133
|
+
end
|