dor-services 6.0.0 → 6.0.1
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/lib/dor-services.rb +7 -6
- data/lib/dor/certificate_authenticated_rest_resource_factory.rb +2 -1
- data/lib/dor/config.rb +38 -37
- data/lib/dor/datastreams/administrative_metadata_ds.rb +98 -98
- data/lib/dor/datastreams/content_metadata_ds.rb +26 -17
- data/lib/dor/datastreams/datastream_spec_solrizer.rb +4 -2
- data/lib/dor/datastreams/default_object_rights_ds.rb +10 -7
- data/lib/dor/datastreams/desc_metadata_ds.rb +6 -6
- data/lib/dor/datastreams/embargo_metadata_ds.rb +94 -94
- data/lib/dor/datastreams/events_ds.rb +55 -54
- data/lib/dor/datastreams/geo_metadata_ds.rb +7 -6
- data/lib/dor/datastreams/identity_metadata_ds.rb +128 -125
- data/lib/dor/datastreams/provenance_metadata_ds.rb +3 -1
- data/lib/dor/datastreams/rights_metadata_ds.rb +4 -4
- data/lib/dor/datastreams/role_metadata_ds.rb +42 -42
- data/lib/dor/datastreams/simple_dublin_core_ds.rb +45 -43
- data/lib/dor/datastreams/technical_metadata_ds.rb +3 -1
- data/lib/dor/datastreams/version_metadata_ds.rb +12 -5
- data/lib/dor/datastreams/workflow_definition_ds.rb +74 -73
- data/lib/dor/datastreams/workflow_ds.rb +12 -7
- data/lib/dor/exceptions.rb +2 -0
- data/lib/dor/indexers/data_indexer.rb +16 -0
- data/lib/dor/indexers/describable_indexer.rb +2 -0
- data/lib/dor/indexers/editable_indexer.rb +2 -0
- data/lib/dor/indexers/identifiable_indexer.rb +23 -8
- data/lib/dor/indexers/processable_indexer.rb +2 -0
- data/lib/dor/indexers/releasable_indexer.rb +2 -0
- data/lib/dor/models/abstract.rb +2 -0
- data/lib/dor/models/admin_policy_object.rb +2 -0
- data/lib/dor/models/agreement.rb +2 -0
- data/lib/dor/models/collection.rb +3 -0
- data/lib/dor/models/concerns/assembleable.rb +2 -0
- data/lib/dor/models/concerns/contentable.rb +5 -2
- data/lib/dor/models/concerns/describable.rb +7 -2
- data/lib/dor/models/concerns/editable.rb +28 -21
- data/lib/dor/models/concerns/embargoable.rb +4 -0
- data/lib/dor/models/concerns/eventable.rb +2 -0
- data/lib/dor/models/concerns/geoable.rb +2 -0
- data/lib/dor/models/concerns/governable.rb +7 -2
- data/lib/dor/models/concerns/identifiable.rb +33 -34
- data/lib/dor/models/concerns/itemizable.rb +4 -1
- data/lib/dor/models/concerns/preservable.rb +2 -0
- data/lib/dor/models/concerns/processable.rb +15 -9
- data/lib/dor/models/concerns/publishable.rb +9 -4
- data/lib/dor/models/concerns/releaseable.rb +21 -11
- data/lib/dor/models/concerns/rightsable.rb +2 -0
- data/lib/dor/models/concerns/shelvable.rb +6 -2
- data/lib/dor/models/concerns/versionable.rb +8 -4
- data/lib/dor/models/item.rb +2 -0
- data/lib/dor/models/set.rb +2 -0
- data/lib/dor/models/workflow_object.rb +5 -1
- data/lib/dor/rest_resource_factory.rb +2 -0
- data/lib/dor/services/cleanup_reset_service.rb +2 -1
- data/lib/dor/services/cleanup_service.rb +2 -1
- data/lib/dor/services/digital_stacks_service.rb +3 -1
- data/lib/dor/services/indexing_service.rb +3 -1
- data/lib/dor/services/merge_service.rb +6 -4
- data/lib/dor/services/metadata_handlers/catalog_handler.rb +2 -0
- data/lib/dor/services/metadata_service.rb +4 -4
- data/lib/dor/services/public_desc_metadata_service.rb +16 -8
- data/lib/dor/services/public_xml_service.rb +7 -4
- data/lib/dor/services/registration_service.rb +25 -20
- data/lib/dor/services/reset_workspace_service.rb +4 -4
- data/lib/dor/services/sdr_ingest_service.rb +4 -2
- data/lib/dor/services/search_service.rb +8 -9
- data/lib/dor/services/suri_service.rb +3 -2
- data/lib/dor/services/technical_metadata_service.rb +15 -9
- data/lib/dor/services/thumbnail_service.rb +14 -10
- data/lib/dor/utils/hydrus_shims.rb +2 -0
- data/lib/dor/utils/ng_tidy.rb +3 -7
- data/lib/dor/utils/predicate_patch.rb +2 -0
- data/lib/dor/utils/sdr_client.rb +3 -0
- data/lib/dor/utils/solr_doc_helper.rb +4 -2
- data/lib/dor/version.rb +3 -1
- data/lib/dor/workflow/document.rb +113 -108
- data/lib/dor/workflow/process.rb +90 -87
- data/lib/tasks/rdoc.rake +4 -3
- metadata +4 -4
@@ -1,10 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dor
|
2
4
|
# Represents the Fedora 3 datastream that hold technical metadata
|
3
5
|
class TechnicalMetadataDS < ActiveFedora::OmDatastream
|
4
6
|
# This provides the prefix for the solr fields generated by ActiveFedora.
|
5
7
|
# Since we don't want a prefix, we override this to return an empty string.
|
6
8
|
def prefix
|
7
|
-
''
|
9
|
+
''
|
8
10
|
end
|
9
11
|
end
|
10
12
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dor
|
2
4
|
class VersionTag
|
3
5
|
include Comparable
|
@@ -7,14 +9,17 @@ module Dor
|
|
7
9
|
def <=>(other)
|
8
10
|
diff = @major <=> other.major
|
9
11
|
return diff if diff != 0
|
12
|
+
|
10
13
|
diff = @minor <=> other.minor
|
11
14
|
return diff if diff != 0
|
15
|
+
|
12
16
|
@admin <=> other.admin
|
13
17
|
end
|
14
18
|
|
15
19
|
# @param [String] raw_tag the value of the tag attribute from a Version node
|
16
20
|
def self.parse(raw_tag)
|
17
21
|
return nil unless raw_tag =~ /(\d+)\.(\d+)\.(\d+)/
|
22
|
+
|
18
23
|
VersionTag.new $1, $2, $3
|
19
24
|
end
|
20
25
|
|
@@ -81,7 +86,7 @@ module Dor
|
|
81
86
|
ng_xml_will_change!
|
82
87
|
if find_by_terms(:version).size == 0
|
83
88
|
v = ng_xml.create_element 'version',
|
84
|
-
|
89
|
+
:versionId => '1', :tag => '1.0.0'
|
85
90
|
d = ng_xml.create_element 'description', 'Initial Version'
|
86
91
|
ng_xml.root['objectId'] = pid
|
87
92
|
ng_xml.root.add_child(v)
|
@@ -123,6 +128,7 @@ module Dor
|
|
123
128
|
ng_xml.root['objectId'] = pid
|
124
129
|
return if find_by_terms(:version).size == 1
|
125
130
|
return if opts.empty?
|
131
|
+
|
126
132
|
ng_xml_will_change!
|
127
133
|
current = current_version_node
|
128
134
|
if opts.include? :description
|
@@ -141,8 +147,8 @@ module Dor
|
|
141
147
|
else
|
142
148
|
# get rid of the current tag
|
143
149
|
tags = find_by_terms(:version, :tag)
|
144
|
-
sorted_tags = tags.map {|t| VersionTag.parse(t.value)}.sort
|
145
|
-
current_tag = sorted_tags[sorted_tags.length - 2]
|
150
|
+
sorted_tags = tags.map { |t| VersionTag.parse(t.value) }.sort
|
151
|
+
current_tag = sorted_tags[sorted_tags.length - 2] # Get the second greatest tag since we are dropping the current, greatest
|
146
152
|
current[:tag] = current_tag.increment(opts[:significance]).to_s
|
147
153
|
end
|
148
154
|
|
@@ -187,6 +193,7 @@ module Dor
|
|
187
193
|
def current_description
|
188
194
|
desc_node = current_version_node.at_xpath('description')
|
189
195
|
return desc_node.content if desc_node
|
196
|
+
|
190
197
|
''
|
191
198
|
end
|
192
199
|
|
@@ -222,12 +229,12 @@ module Dor
|
|
222
229
|
# @return [Nokogiri::XML::Node] Node representing the current version
|
223
230
|
def current_version_node
|
224
231
|
versions = find_by_terms(:version)
|
225
|
-
versions.max_by {|v| v[:versionId].to_i }
|
232
|
+
versions.max_by { |v| v[:versionId].to_i }
|
226
233
|
end
|
227
234
|
|
228
235
|
def newest_tag
|
229
236
|
tags = find_by_terms(:version, :tag)
|
230
|
-
tags.map {|t| VersionTag.parse(t.value)}.max
|
237
|
+
tags.map { |t| VersionTag.parse(t.value) }.max
|
231
238
|
end
|
232
239
|
end
|
233
240
|
end
|
@@ -1,91 +1,92 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dor
|
2
|
-
class WorkflowDefinitionDs < ActiveFedora::OmDatastream
|
3
|
-
|
4
|
+
class WorkflowDefinitionDs < ActiveFedora::OmDatastream
|
5
|
+
include SolrDocHelper
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
7
|
+
set_terminology do |t|
|
8
|
+
t.root(:path => 'workflow-def', :index_as => [:not_searchable])
|
9
|
+
t.process(:index_as => [:not_searchable])
|
10
|
+
end
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
12
|
+
define_template :process do |builder, workflow, attrs|
|
13
|
+
prereqs = attrs.delete('prerequisite')
|
14
|
+
prereqs = prereqs.split(/\s*,\s*/) if prereqs.is_a?(String)
|
15
|
+
attrs.keys.each { |k| attrs[k.to_s.dasherize.to_sym] = attrs.delete(k) }
|
16
|
+
builder.process(attrs) do |node|
|
17
|
+
Array(prereqs).each do |prereq|
|
18
|
+
(repo, wf, prereq_name) = prereq.split(/:/)
|
19
|
+
if prereq_name.nil?
|
20
|
+
prereq_name = repo
|
21
|
+
repo = nil
|
22
|
+
end
|
23
|
+
if repo == workflow.repo && wf = workflow.name
|
24
|
+
repo = nil
|
25
|
+
wf = nil
|
26
|
+
end
|
27
|
+
attrs = (repo.nil? && wf.nil?) ? {} : { :repository => repo, :workflow => wf }
|
28
|
+
node.prereq(attrs) { node.text prereq_name }
|
20
29
|
end
|
21
|
-
if repo == workflow.repo && wf = workflow.name
|
22
|
-
repo = nil
|
23
|
-
wf = nil
|
24
|
-
end
|
25
|
-
attrs = (repo.nil? && wf.nil?) ? {} : { :repository => repo, :workflow => wf }
|
26
|
-
node.prereq(attrs) { node.text prereq_name }
|
27
30
|
end
|
28
31
|
end
|
29
|
-
end
|
30
32
|
|
31
|
-
|
32
|
-
|
33
|
-
|
33
|
+
def self.xml_template
|
34
|
+
Nokogiri::XML('<workflow-def/>')
|
35
|
+
end
|
34
36
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
37
|
+
def add_process(attributes)
|
38
|
+
ng_xml_will_change!
|
39
|
+
add_child_node(ng_xml.at_xpath('/workflow-def'), :process, self, attributes)
|
40
|
+
end
|
39
41
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
42
|
+
def processes
|
43
|
+
ng_xml.xpath('/workflow-def/process').collect do |node|
|
44
|
+
Workflow::Process.new(repo, name, node)
|
45
|
+
end.sort { |a, b| (a.sequence || 0) <=> (b.sequence || 0) }
|
46
|
+
end
|
45
47
|
|
46
|
-
|
47
|
-
|
48
|
-
|
48
|
+
def name
|
49
|
+
ng_xml.at_xpath('/workflow-def/@id').to_s
|
50
|
+
end
|
49
51
|
|
50
|
-
|
51
|
-
|
52
|
-
|
52
|
+
def repo
|
53
|
+
ng_xml.at_xpath('/workflow-def/@repository').to_s
|
54
|
+
end
|
53
55
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
56
|
+
# Creates the xml used by Dor::WorkflowService#create_workflow
|
57
|
+
# @return [String] An object's initial workflow as defined by the <workflow-def> in content
|
58
|
+
def initial_workflow
|
59
|
+
doc = Nokogiri::XML('<workflow/>')
|
60
|
+
root = doc.root
|
61
|
+
root['id'] = name
|
62
|
+
processes.each { |proc|
|
63
|
+
doc.create_element 'process' do |node|
|
64
|
+
node['name'] = proc.name
|
65
|
+
if proc.status
|
66
|
+
node['status'] = proc.status
|
67
|
+
node['attempts'] = '1'
|
68
|
+
else
|
69
|
+
node['status'] = 'waiting'
|
70
|
+
end
|
71
|
+
node['lifecycle'] = proc.lifecycle if proc.lifecycle
|
72
|
+
root.add_child node
|
68
73
|
end
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
}
|
73
|
-
Nokogiri::XML(doc.to_xml) { |x| x.noblanks }.to_xml { |config| config.no_declaration }
|
74
|
-
end
|
74
|
+
}
|
75
|
+
Nokogiri::XML(doc.to_xml) { |x| x.noblanks }.to_xml { |config| config.no_declaration }
|
76
|
+
end
|
75
77
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
78
|
+
def to_solr(solr_doc = {}, *args)
|
79
|
+
solr_doc = super(solr_doc, *args)
|
80
|
+
add_solr_value(solr_doc, 'workflow_name', name, :symbol, [:symbol])
|
81
|
+
processes.each do |p|
|
82
|
+
add_solr_value(solr_doc, 'process', "#{p.name}|#{p.label}", :symbol, [:displayable])
|
83
|
+
end
|
84
|
+
solr_doc
|
81
85
|
end
|
82
|
-
solr_doc
|
83
|
-
end
|
84
86
|
|
85
|
-
|
86
|
-
|
87
|
-
|
87
|
+
# maintain AF < 8 indexing behavior
|
88
|
+
def prefix
|
89
|
+
''
|
90
|
+
end
|
88
91
|
end
|
89
|
-
|
90
|
-
end
|
91
92
|
end
|
@@ -1,17 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dor
|
2
4
|
# TODO: class docs
|
3
5
|
class WorkflowDs < ActiveFedora::OmDatastream
|
4
6
|
set_terminology do |t|
|
5
7
|
t.root(:path => 'workflows')
|
6
8
|
t.workflow {
|
7
|
-
t.workflowId(
|
9
|
+
t.workflowId(:path => { :attribute => 'id' })
|
8
10
|
t.process {
|
9
|
-
t.name_(
|
10
|
-
t.status(
|
11
|
-
t.timestamp(:path => {:attribute => 'datetime' }, :index_as => [:displayable, :not_searchable]
|
12
|
-
t.elapsed(
|
13
|
-
t.lifecycle(:path => {:attribute => 'lifecycle'}, :index_as => [:displayable, :not_searchable]
|
14
|
-
t.attempts(
|
11
|
+
t.name_(:path => { :attribute => 'name' }, :index_as => [:displayable, :not_searchable])
|
12
|
+
t.status(:path => { :attribute => 'status' }, :index_as => [:displayable, :not_searchable])
|
13
|
+
t.timestamp(:path => { :attribute => 'datetime' }, :index_as => [:displayable, :not_searchable]) # , :data_type => :date)
|
14
|
+
t.elapsed(:path => { :attribute => 'elapsed' }, :index_as => [:displayable, :not_searchable])
|
15
|
+
t.lifecycle(:path => { :attribute => 'lifecycle' }, :index_as => [:displayable, :not_searchable])
|
16
|
+
t.attempts(:path => { :attribute => 'attempts' }, :index_as => [:displayable, :not_searchable])
|
15
17
|
}
|
16
18
|
}
|
17
19
|
end
|
@@ -20,6 +22,7 @@ module Dor
|
|
20
22
|
xml = Dor::Config.workflow.client.get_workflow_xml(repo, pid, wf)
|
21
23
|
xml = Nokogiri::XML(xml)
|
22
24
|
return nil if xml.xpath('workflow').length == 0
|
25
|
+
|
23
26
|
Workflow::Document.new(xml.to_s)
|
24
27
|
end
|
25
28
|
|
@@ -39,6 +42,7 @@ module Dor
|
|
39
42
|
xml = Nokogiri::XML(%(<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<workflows objectId="#{pid}"/>))
|
40
43
|
digital_object.datastreams.keys.each do |dsid|
|
41
44
|
next unless dsid =~ /WF$/
|
45
|
+
|
42
46
|
ds_content = Nokogiri::XML(Dor::Config.workflow.client.get_workflow_xml('dor', pid, dsid))
|
43
47
|
xml.root.add_child(ds_content.root)
|
44
48
|
end
|
@@ -55,6 +59,7 @@ module Dor
|
|
55
59
|
def current_priority
|
56
60
|
cp = workflows.detect(&:expedited?)
|
57
61
|
return 0 if cp.nil?
|
62
|
+
|
58
63
|
cp.priority.to_i
|
59
64
|
end
|
60
65
|
|
data/lib/dor/exceptions.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dor
|
2
4
|
# Indexing provided by ActiveFedora
|
3
5
|
class DataIndexer
|
@@ -8,6 +10,20 @@ module Dor
|
|
8
10
|
@resource = resource
|
9
11
|
end
|
10
12
|
|
13
|
+
# we need to override this until https://github.com/samvera/active_fedora/pull/1371
|
14
|
+
# has been released
|
15
|
+
def to_solr(solr_doc = {}, opts = {})
|
16
|
+
super.tap do |doc|
|
17
|
+
doc['active_fedora_model_ssi'] = has_model
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# rubocop:disable Naming/PredicateName
|
22
|
+
def has_model
|
23
|
+
resource.class.inspect
|
24
|
+
end
|
25
|
+
# rubocop:enable Naming/PredicateName
|
26
|
+
|
11
27
|
delegate :create_date, :modified_date, :state, :pid, :inner_object,
|
12
28
|
:datastreams, :relationships, to: :resource
|
13
29
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Dor
|
2
4
|
class IdentifiableIndexer
|
3
5
|
include SolrDocHelper
|
@@ -26,7 +28,7 @@ module Dor
|
|
26
28
|
add_solr_value(solr_doc, 'title_sort', resource.label, :string, [:stored_sortable])
|
27
29
|
|
28
30
|
rels_doc = Nokogiri::XML(resource.datastreams['RELS-EXT'].content)
|
29
|
-
ns_hash = {'hydra' => 'http://projecthydra.org/ns/relations#', 'fedora' => 'info:fedora/fedora-system:def/relations-external#', 'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'}
|
31
|
+
ns_hash = { 'hydra' => 'http://projecthydra.org/ns/relations#', 'fedora' => 'info:fedora/fedora-system:def/relations-external#', 'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' }
|
30
32
|
apos = rels_doc.search('//rdf:RDF/rdf:Description/hydra:isGovernedBy', ns_hash)
|
31
33
|
collections = rels_doc.search('//rdf:RDF/rdf:Description/fedora:isMemberOfCollection', ns_hash)
|
32
34
|
solrize_related_obj_titles(solr_doc, apos, @@apo_hash, 'apo_title', 'nonhydrus_apo_title', 'hydrus_apo_title')
|
@@ -46,28 +48,35 @@ module Dor
|
|
46
48
|
end
|
47
49
|
end
|
48
50
|
|
51
|
+
# Clears out the cache of items. Used primarily in testing.
|
52
|
+
def self.reset_cache!
|
53
|
+
@@collection_hash = {}
|
54
|
+
@@apo_hash = {}
|
55
|
+
end
|
56
|
+
|
49
57
|
private
|
50
58
|
|
51
59
|
def solrize_related_obj_titles(solr_doc, relationships, title_hash, union_field_name, nonhydrus_field_name, hydrus_field_name)
|
52
60
|
# TODO: if you wanted to get a little fancier, you could also solrize a 2 level hierarchy and display using hierarchial facets, like
|
53
61
|
# ["SOURCE", "SOURCE : TITLE"] (e.g. ["Hydrus", "Hydrus : Special Collections"], see (exploded) tags in IdentityMetadataDS#to_solr).
|
54
|
-
title_type = :symbol
|
55
|
-
title_attrs = [:stored_searchable]
|
62
|
+
title_type = :symbol # we'll get an _ssim because of the type
|
63
|
+
title_attrs = [:stored_searchable] # we'll also get a _tesim from this attr
|
56
64
|
relationships.each do |rel_node|
|
57
65
|
rel_druid = rel_node['rdf:resource']
|
58
|
-
next unless rel_druid
|
66
|
+
next unless rel_druid # TODO: warning here would also be useful
|
67
|
+
|
59
68
|
rel_druid = rel_druid.gsub('info:fedora/', '')
|
60
69
|
|
61
70
|
# populate cache if necessary
|
62
71
|
unless title_hash.key?(rel_druid)
|
63
72
|
begin
|
64
73
|
related_obj = Dor.find(rel_druid)
|
65
|
-
related_obj_title =
|
66
|
-
is_from_hydrus = (related_obj
|
67
|
-
title_hash[rel_druid] = {'related_obj_title' => related_obj_title, 'is_from_hydrus' => is_from_hydrus}
|
74
|
+
related_obj_title = related_obj_display_title(related_obj, rel_druid)
|
75
|
+
is_from_hydrus = (related_obj&.tags&.include?('Project : Hydrus'))
|
76
|
+
title_hash[rel_druid] = { 'related_obj_title' => related_obj_title, 'is_from_hydrus' => is_from_hydrus }
|
68
77
|
rescue ActiveFedora::ObjectNotFoundError
|
69
78
|
# This may happen if the given APO or Collection does not exist (bad data)
|
70
|
-
title_hash[rel_druid] = {'related_obj_title' => rel_druid, 'is_from_hydrus' => false}
|
79
|
+
title_hash[rel_druid] = { 'related_obj_title' => rel_druid, 'is_from_hydrus' => false }
|
71
80
|
end
|
72
81
|
end
|
73
82
|
|
@@ -80,5 +89,11 @@ module Dor
|
|
80
89
|
add_solr_value(solr_doc, union_field_name, title_hash[rel_druid]['related_obj_title'], title_type, title_attrs)
|
81
90
|
end
|
82
91
|
end
|
92
|
+
|
93
|
+
def related_obj_display_title(related_obj, default_title)
|
94
|
+
return default_title unless related_obj
|
95
|
+
|
96
|
+
related_obj.full_title || default_title
|
97
|
+
end
|
83
98
|
end
|
84
99
|
end
|
data/lib/dor/models/abstract.rb
CHANGED