dor-services 6.8.0 → 7.0.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/config/config_defaults.yml +0 -27
- data/config/dev_console_env.rb.example +0 -17
- data/lib/dor-services.rb +9 -73
- data/lib/dor/config.rb +1 -30
- data/lib/dor/datastreams/content_metadata_ds.rb +8 -0
- data/lib/dor/datastreams/desc_metadata_ds.rb +19 -0
- data/lib/dor/datastreams/identity_metadata_ds.rb +65 -0
- data/lib/dor/datastreams/rights_metadata_ds.rb +14 -2
- data/lib/dor/datastreams/workflow_definition_ds.rb +1 -1
- data/lib/dor/datastreams/workflow_ds.rb +0 -15
- data/lib/dor/indexers/identifiable_indexer.rb +8 -4
- data/lib/dor/indexers/releasable_indexer.rb +7 -1
- data/lib/dor/models/abstract.rb +143 -8
- data/lib/dor/models/admin_policy_object.rb +0 -3
- data/lib/dor/models/collection.rb +0 -2
- data/lib/dor/models/concerns/embargoable.rb +7 -60
- data/lib/dor/models/etd.rb +100 -0
- data/lib/dor/models/item.rb +12 -28
- data/lib/dor/models/part.rb +18 -0
- data/lib/dor/models/set.rb +0 -2
- data/lib/dor/services/collection_service.rb +36 -0
- data/lib/dor/services/embargo_service.rb +93 -0
- data/lib/dor/services/ontology.rb +0 -18
- data/lib/dor/services/public_desc_metadata_service.rb +7 -11
- data/lib/dor/services/search_service.rb +0 -40
- data/lib/dor/version.rb +1 -1
- data/lib/dor/workflow/document.rb +0 -7
- metadata +15 -78
- data/lib/dor/models/concerns/assembleable.rb +0 -18
- data/lib/dor/models/concerns/contentable.rb +0 -185
- data/lib/dor/models/concerns/describable.rb +0 -82
- data/lib/dor/models/concerns/eventable.rb +0 -18
- data/lib/dor/models/concerns/geoable.rb +0 -14
- data/lib/dor/models/concerns/governable.rb +0 -101
- data/lib/dor/models/concerns/identifiable.rb +0 -172
- data/lib/dor/models/concerns/itemizable.rb +0 -42
- data/lib/dor/models/concerns/preservable.rb +0 -46
- data/lib/dor/models/concerns/processable.rb +0 -86
- data/lib/dor/models/concerns/publishable.rb +0 -76
- data/lib/dor/models/concerns/releaseable.rb +0 -118
- data/lib/dor/models/concerns/rightsable.rb +0 -25
- data/lib/dor/models/concerns/shelvable.rb +0 -15
- data/lib/dor/models/concerns/versionable.rb +0 -72
- data/lib/dor/services/ability.rb +0 -77
- data/lib/dor/services/cleanup_reset_service.rb +0 -103
- data/lib/dor/services/datastream_builder.rb +0 -96
- data/lib/dor/services/decommission_service.rb +0 -31
- data/lib/dor/services/digital_stacks_service.rb +0 -125
- data/lib/dor/services/dublin_core_service.rb +0 -45
- data/lib/dor/services/file_metadata_merge_service.rb +0 -71
- data/lib/dor/services/indexing_service.rb +0 -131
- data/lib/dor/services/merge_service.rb +0 -105
- data/lib/dor/services/public_xml_service.rb +0 -116
- data/lib/dor/services/publish_metadata_service.rb +0 -99
- data/lib/dor/services/reset_workspace_service.rb +0 -27
- data/lib/dor/services/sdr_ingest_service.rb +0 -172
- data/lib/dor/services/secondary_file_name_service.rb +0 -10
- data/lib/dor/services/shelving_service.rb +0 -69
- data/lib/dor/services/technical_metadata_service.rb +0 -232
- data/lib/dor/services/version_service.rb +0 -84
- data/lib/dor/utils/sdr_client.rb +0 -94
@@ -1,71 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Dor
|
4
|
-
# Merges contentMetadata from several objects into one.
|
5
|
-
class FileMetadataMergeService
|
6
|
-
extend Deprecation
|
7
|
-
self.deprecation_horizon = 'dor-services version 7.0.0'
|
8
|
-
|
9
|
-
# @param [Array<String>] secondary_druids ids of the secondary objects that will get their contentMetadata merged into this one
|
10
|
-
def self.copy_file_resources(primary, secondary_druids)
|
11
|
-
merge_service = FileMetadataMergeService.new primary, secondary_druids
|
12
|
-
merge_service.copy_file_resources
|
13
|
-
end
|
14
|
-
|
15
|
-
def initialize(primary, secondary_druids)
|
16
|
-
@pid = primary.pid
|
17
|
-
content_metadata = primary.contentMetadata
|
18
|
-
content_metadata.ng_xml_will_change!
|
19
|
-
@primary_cm = content_metadata.ng_xml
|
20
|
-
@secondary_druids = secondary_druids
|
21
|
-
end
|
22
|
-
|
23
|
-
# Appends contentMetadata file resources from the source objects to this object
|
24
|
-
def copy_file_resources
|
25
|
-
base_id = primary_cm.at_xpath('/contentMetadata/@objectId').value
|
26
|
-
max_sequence = primary_cm.at_xpath('/contentMetadata/resource[last()]/@sequence').value.to_i
|
27
|
-
|
28
|
-
secondary_druids.each do |src_pid|
|
29
|
-
source_obj = Dor.find src_pid
|
30
|
-
source_cm = source_obj.contentMetadata.ng_xml
|
31
|
-
|
32
|
-
# Copy the resources from each source object
|
33
|
-
source_cm.xpath('/contentMetadata/resource').each do |old_resource|
|
34
|
-
max_sequence += 1
|
35
|
-
resource_copy = old_resource.clone
|
36
|
-
resource_copy['sequence'] = max_sequence.to_s
|
37
|
-
|
38
|
-
# Append sequence number to each secondary filename, then
|
39
|
-
# look for filename collisions with the primary object
|
40
|
-
resource_copy.xpath('file').each do |secondary_file|
|
41
|
-
secondary_file['id'] = SecondaryFileNameService.create(secondary_file['id'], max_sequence)
|
42
|
-
|
43
|
-
if primary_cm.at_xpath("//file[@id = '#{secondary_file['id']}']")
|
44
|
-
raise Dor::Exception, "File '#{secondary_file['id']}' from secondary object #{src_pid} already exist in primary object: #{pid}"
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
if old_resource['type']
|
49
|
-
resource_copy['id'] = "#{old_resource['type']}_#{max_sequence}"
|
50
|
-
else
|
51
|
-
resource_copy['id'] = "#{base_id}_#{max_sequence}"
|
52
|
-
end
|
53
|
-
|
54
|
-
lbl = old_resource.at_xpath 'label'
|
55
|
-
resource_copy.at_xpath('label').content = "#{Regexp.last_match(1)} #{max_sequence}" if lbl && lbl.text =~ /^(.*)\s+\d+$/
|
56
|
-
|
57
|
-
primary_cm.at_xpath('/contentMetadata/resource[last()]').add_next_sibling resource_copy
|
58
|
-
attr_node = primary_cm.create_element 'attr', src_pid, name: 'mergedFromPid'
|
59
|
-
resource_copy.first_element_child.add_previous_sibling attr_node
|
60
|
-
attr_node = primary_cm.create_element 'attr', old_resource['id'], name: 'mergedFromResource'
|
61
|
-
resource_copy.first_element_child.add_previous_sibling attr_node
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
deprecation_deprecate copy_file_resources: 'No longer used by any DLSS code'
|
66
|
-
|
67
|
-
private
|
68
|
-
|
69
|
-
attr_reader :secondary_druids, :primary_cm, :pid
|
70
|
-
end
|
71
|
-
end
|
@@ -1,131 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'benchmark'
|
4
|
-
|
5
|
-
module Dor
|
6
|
-
class IndexingService
|
7
|
-
extend Deprecation
|
8
|
-
|
9
|
-
class ReindexError < RuntimeError; end
|
10
|
-
|
11
|
-
##
|
12
|
-
# Returns a Logger instance for recording info about indexing attempts
|
13
|
-
# @yield attempt to execute 'entry_id_block' and use the result as an extra identifier for the log
|
14
|
-
# entry. a placeholder will be used otherwise. 'request.uuid' might be useful in a Rails app.
|
15
|
-
def self.generate_index_logger(&entry_id_block)
|
16
|
-
Deprecation.warn(self, 'generate_index_logger is deprecated and will be removed in dor-services version 7')
|
17
|
-
index_logger = Logger.new(Config.indexing_svc.log, Config.indexing_svc.log_rotation_interval)
|
18
|
-
index_logger.formatter = proc do |_severity, datetime, _progname, msg|
|
19
|
-
date_format_str = Config.indexing_svc.log_date_format_str
|
20
|
-
entry_id = begin begin
|
21
|
-
entry_id_block.call
|
22
|
-
rescue StandardError
|
23
|
-
'---'
|
24
|
-
end end
|
25
|
-
"[#{entry_id}] [#{datetime.utc.strftime(date_format_str)}] #{msg}\n"
|
26
|
-
end
|
27
|
-
index_logger
|
28
|
-
end
|
29
|
-
|
30
|
-
# memoize the loggers we create in a hash, init with a nil default logger
|
31
|
-
@@loggers = { default: nil }
|
32
|
-
|
33
|
-
def self.default_index_logger
|
34
|
-
Deprecation.warn(self, 'default_index_logger is deprecated and will be removed in dor-services version 7')
|
35
|
-
@@loggers[:default] ||= generate_index_logger
|
36
|
-
end
|
37
|
-
|
38
|
-
# takes a Dor object and indexes it to solr. doesn't commit automatically.
|
39
|
-
def self.reindex_object(obj, options = {})
|
40
|
-
Deprecation.warn(self, 'reindex_pid is deprecated and will be removed in dor-services 7.')
|
41
|
-
solr_doc = obj.to_solr
|
42
|
-
Dor::SearchService.solr.add(solr_doc, options)
|
43
|
-
solr_doc
|
44
|
-
end
|
45
|
-
|
46
|
-
# Use the dor-indexing-app service to reindex a pid
|
47
|
-
# @param [String] pid the druid
|
48
|
-
# @raise [ReindexError] on failure
|
49
|
-
def self.reindex_pid_remotely(pid)
|
50
|
-
Deprecation.warn(self, 'reindex_pid_remotely is deprecated and will be removed in dor-services 7.')
|
51
|
-
|
52
|
-
pid = "druid:#{pid}" unless pid =~ /^druid:/
|
53
|
-
realtime = Benchmark.realtime do
|
54
|
-
with_retries(max_tries: 3, rescue: [RestClient::Exception, Errno::ECONNREFUSED]) do
|
55
|
-
RestClient.post("#{Config.dor_indexing_app.url}/reindex/#{pid}", '')
|
56
|
-
end
|
57
|
-
end
|
58
|
-
default_index_logger.info "successfully updated index for #{pid} in #{'%.3f' % realtime}s"
|
59
|
-
rescue RestClient::Exception, Errno::ECONNREFUSED => e
|
60
|
-
msg = "failed to reindex #{pid}: #{e}"
|
61
|
-
default_index_logger.error msg
|
62
|
-
raise ReindexError.new(msg)
|
63
|
-
rescue StandardError => e
|
64
|
-
default_index_logger.error "failed to reindex #{pid}: #{e}"
|
65
|
-
raise
|
66
|
-
end
|
67
|
-
|
68
|
-
# retrieves a single Dor object by pid, indexes the object to solr, does some logging
|
69
|
-
# (will use a default logger if one is not provided). doesn't commit automatically.
|
70
|
-
#
|
71
|
-
# WARNING/TODO: the tests indicate that the "rescue Exception" block at the end will
|
72
|
-
# get skipped, and the thrown exception (e.g. SystemStackError) will not be logged. since
|
73
|
-
# that's the only consequence, and the exception bubbles up as we would want anyway, it
|
74
|
-
# doesn't seem worth blocking refactoring. see https://github.com/sul-dlss/dor-services/issues/156
|
75
|
-
# extra logging in this case would be nice, but centralized indexing that's otherwise
|
76
|
-
# fully functional is nicer.
|
77
|
-
#
|
78
|
-
# @overload reindex_pid(pid, index_logger, options = {})
|
79
|
-
# @overload reindex_pid(pid, index_logger, should_raise_errors, options = {})
|
80
|
-
# @overload reindex_pid(pid, options = {})
|
81
|
-
def self.reindex_pid(pid, *args)
|
82
|
-
Deprecation.warn(self, 'reindex_pid is deprecated and will be removed in dor-services 7.')
|
83
|
-
options = {}
|
84
|
-
options = args.pop if args.last.is_a? Hash
|
85
|
-
|
86
|
-
if args.length > 0
|
87
|
-
warn 'Dor::IndexingService.reindex_pid with primitive arguments is deprecated; pass e.g. { logger: logger, raise_errors: bool } instead'
|
88
|
-
index_logger, should_raise_errors = args
|
89
|
-
index_logger ||= default_index_logger
|
90
|
-
should_raise_errors = true if should_raise_errors.nil?
|
91
|
-
else
|
92
|
-
index_logger = options.fetch(:logger, default_index_logger)
|
93
|
-
should_raise_errors = options.fetch(:raise_errors, true)
|
94
|
-
end
|
95
|
-
|
96
|
-
obj = nil
|
97
|
-
solr_doc = nil
|
98
|
-
|
99
|
-
# benchmark how long it takes to load the object
|
100
|
-
load_stats = Benchmark.measure('find') do
|
101
|
-
obj = Dor.find pid
|
102
|
-
end.format('%n realtime %rs total CPU %ts').gsub(/[\(\)]/, '')
|
103
|
-
|
104
|
-
# benchmark how long it takes to convert the object to a Solr document
|
105
|
-
to_solr_stats = Benchmark.measure('to_solr') do
|
106
|
-
solr_doc = reindex_object obj, options
|
107
|
-
end.format('%n realtime %rs total CPU %ts').gsub(/[\(\)]/, '')
|
108
|
-
|
109
|
-
index_logger.info "successfully updated index for #{pid} (metrics: #{load_stats}; #{to_solr_stats})"
|
110
|
-
|
111
|
-
solr_doc
|
112
|
-
rescue StandardError => se
|
113
|
-
if se.is_a? ActiveFedora::ObjectNotFoundError
|
114
|
-
index_logger.warn "failed to update index for #{pid}, object not found in Fedora"
|
115
|
-
else
|
116
|
-
index_logger.warn "failed to update index for #{pid}, unexpected StandardError, see main app log: #{se.backtrace}"
|
117
|
-
end
|
118
|
-
raise se if should_raise_errors
|
119
|
-
rescue Exception => ex
|
120
|
-
index_logger.error "failed to update index for #{pid}, unexpected Exception, see main app log: #{ex.backtrace}"
|
121
|
-
raise ex # don't swallow anything worse than StandardError
|
122
|
-
end
|
123
|
-
|
124
|
-
# given a list of pids, retrieve those objects from fedora, index each to solr, optionally commit
|
125
|
-
def self.reindex_pid_list(pid_list, should_commit = false)
|
126
|
-
Deprecation.warn(self, 'reindex_pid_list is deprecated and will be removed in dor-services 7')
|
127
|
-
pid_list.each { |pid| reindex_pid pid, raise_errors: false } # use the default logger, don't let individual errors nuke the rest of the batch
|
128
|
-
ActiveFedora.solr.conn.commit if should_commit
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
@@ -1,105 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Dor
|
4
|
-
class MergeService
|
5
|
-
extend Deprecation
|
6
|
-
self.deprecation_horizon = 'dor-services version 7.0.0'
|
7
|
-
|
8
|
-
def self.merge_into_primary(primary_druid, secondary_druids, tag, logger = nil)
|
9
|
-
# TODO: test the secondary_obj to see if we've processed it already
|
10
|
-
merge_service = Dor::MergeService.new primary_druid, secondary_druids, tag, logger
|
11
|
-
merge_service.check_objects_editable
|
12
|
-
merge_service.move_metadata_and_content
|
13
|
-
merge_service.decommission_secondaries
|
14
|
-
# kick off commonAccessioning for the primary?
|
15
|
-
end
|
16
|
-
|
17
|
-
def initialize(primary_druid, secondary_pids, tag, logger = nil)
|
18
|
-
@primary = Dor.find primary_druid
|
19
|
-
@secondary_pids = secondary_pids
|
20
|
-
@secondary_objs = secondary_pids.map { |pid| Dor.find pid }
|
21
|
-
if logger.nil?
|
22
|
-
@logger = Logger.new(STDERR)
|
23
|
-
else
|
24
|
-
@logger = logger
|
25
|
-
end
|
26
|
-
@tag = tag
|
27
|
-
end
|
28
|
-
|
29
|
-
def check_objects_editable
|
30
|
-
raise Dor::Exception, "Primary object is not editable: #{@primary.pid}" unless @primary.allows_modification?
|
31
|
-
|
32
|
-
non_editable = @secondary_objs.detect { |obj| !obj.allows_modification? }
|
33
|
-
raise Dor::Exception, "Secondary object is not editable: #{non_editable.pid}" if non_editable
|
34
|
-
end
|
35
|
-
deprecation_deprecate check_objects_editable: 'No longer used by any DLSS code'
|
36
|
-
|
37
|
-
def move_metadata_and_content
|
38
|
-
FileMetadataMergeService.copy_file_resources @primary, @secondary_pids
|
39
|
-
@primary.save
|
40
|
-
copy_workspace_content
|
41
|
-
end
|
42
|
-
deprecation_deprecate move_metadata_and_content: 'No longer used by any DLSS code'
|
43
|
-
|
44
|
-
# Copies the content from the secondary object workspace to the primary object's workspace
|
45
|
-
# Depends on Dor::Config.stacks.local_workspace_root
|
46
|
-
def copy_workspace_content
|
47
|
-
pri_file = @primary.contentMetadata.resource(0).file(0).id.first
|
48
|
-
pri_druid = DruidTools::Druid.new @primary.pid, Dor::Config.stacks.local_workspace_root
|
49
|
-
dest_path = pri_druid.find_filelist_parent 'content', pri_file
|
50
|
-
primary_cm = @primary.contentMetadata.ng_xml
|
51
|
-
|
52
|
-
@secondary_objs.each do |secondary|
|
53
|
-
sec_druid = DruidTools::Druid.new secondary.pid, Dor::Config.stacks.local_workspace_root
|
54
|
-
secondary.contentMetadata.ng_xml.xpath('//resource').each do |src_resource|
|
55
|
-
primary_resource = primary_cm.at_xpath "//resource[attr[@name = 'mergedFromPid']/text() = '#{secondary.pid}' and
|
56
|
-
attr[@name = 'mergedFromResource']/text() = '#{src_resource['id']}' ]"
|
57
|
-
sequence = primary_resource['sequence']
|
58
|
-
src_resource.xpath('//file/@id').map(&:value).each do |file_id|
|
59
|
-
copy_path = sec_druid.find_content file_id
|
60
|
-
new_name = SecondaryFileNameService.create(file_id, sequence)
|
61
|
-
# TODO: verify new_name exists in primary_cm?
|
62
|
-
FileUtils.cp(copy_path, File.join(dest_path, "/#{new_name}"))
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
deprecation_deprecate copy_workspace_content: 'No longer used by any DLSS code'
|
68
|
-
|
69
|
-
def decommission_secondaries
|
70
|
-
@secondary_objs.each do |secondary_obj|
|
71
|
-
begin
|
72
|
-
@current_secondary = secondary_obj
|
73
|
-
@current_secondary.decommission @tag
|
74
|
-
@current_secondary.save
|
75
|
-
|
76
|
-
unshelve
|
77
|
-
unpublish
|
78
|
-
Dor::CleanupService.cleanup_by_druid @current_secondary.pid
|
79
|
-
Dor::Config.workflow.client.archive_active_workflow 'dor', @current_secondary.pid
|
80
|
-
rescue StandardError => e
|
81
|
-
@logger.error "Unable to decommission #{@current_secondary.pid} with primary object #{@primary.pid}: #{e.inspect}"
|
82
|
-
@logger.error e.backtrace.join("\n")
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
deprecation_deprecate decommission_secondaries: 'No longer used by any DLSS code'
|
87
|
-
|
88
|
-
alias decomission_secondaries decommission_secondaries
|
89
|
-
deprecate decomission_secondaries: 'Use decommission_secondaries instead'
|
90
|
-
|
91
|
-
# Remove content from stacks
|
92
|
-
# TODO: might set workflow status in future for robot to do
|
93
|
-
def unshelve
|
94
|
-
DigitalStacksService.prune_stacks_dir @current_secondary.pid
|
95
|
-
end
|
96
|
-
deprecation_deprecate unshelve: 'No longer used by any DLSS code'
|
97
|
-
|
98
|
-
# Withdraw item from Purl
|
99
|
-
# TODO: might set workflow status in future for robot to do
|
100
|
-
def unpublish
|
101
|
-
@current_secondary.publish_metadata
|
102
|
-
end
|
103
|
-
deprecation_deprecate unpublish: 'No longer used by any DLSS code'
|
104
|
-
end
|
105
|
-
end
|
@@ -1,116 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Dor
|
4
|
-
class PublicXmlService
|
5
|
-
attr_reader :object
|
6
|
-
|
7
|
-
def initialize(object)
|
8
|
-
@object = object
|
9
|
-
end
|
10
|
-
|
11
|
-
def to_xml
|
12
|
-
pub = Nokogiri::XML('<publicObject/>').root
|
13
|
-
pub['id'] = object.pid
|
14
|
-
pub['published'] = Time.now.utc.xmlschema
|
15
|
-
pub['publishVersion'] = 'dor-services/' + Dor::VERSION
|
16
|
-
|
17
|
-
pub.add_child(public_identity_metadata.root) # add in modified identityMetadata datastream
|
18
|
-
pub.add_child(public_content_metadata.root) if public_content_metadata.xpath('//resource').any?
|
19
|
-
pub.add_child(public_rights_metadata.root)
|
20
|
-
|
21
|
-
pub.add_child(public_relationships.root) unless public_relationships.nil? # TODO: Should never be nil in practice; working around an ActiveFedora quirk for testing
|
22
|
-
pub.add_child(DublinCoreService.new(object).ng_xml.root)
|
23
|
-
pub.add_child(PublicDescMetadataService.new(object).ng_xml.root)
|
24
|
-
pub.add_child(release_xml.root) unless release_xml.xpath('//release').children.size == 0 # If there are no release_tags, this prevents an empty <releaseData/> from being added
|
25
|
-
# Note we cannot base this on if an individual object has release tags or not, because the collection may cause one to be generated for an item,
|
26
|
-
# so we need to calculate it and then look at the final result.
|
27
|
-
|
28
|
-
thumb = ThumbnailService.new(object).thumb
|
29
|
-
pub.add_child(Nokogiri("<thumb>#{thumb}</thumb>").root) unless thumb.nil?
|
30
|
-
|
31
|
-
new_pub = Nokogiri::XML(pub.to_xml, &:noblanks)
|
32
|
-
new_pub.encoding = 'UTF-8'
|
33
|
-
new_pub.to_xml
|
34
|
-
end
|
35
|
-
|
36
|
-
# Generate XML structure for inclusion to Purl
|
37
|
-
# @return [String] The XML release node as a string, with ReleaseDigest as the root document
|
38
|
-
def release_xml
|
39
|
-
@release_xml ||= begin
|
40
|
-
builder = Nokogiri::XML::Builder.new do |xml|
|
41
|
-
xml.releaseData do
|
42
|
-
object.released_for.each do |project, released_value|
|
43
|
-
xml.release(released_value['release'], to: project)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
Nokogiri::XML(builder.to_xml)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def public_relationships
|
52
|
-
@public_relationships ||= object.public_relationships.clone
|
53
|
-
end
|
54
|
-
|
55
|
-
def public_rights_metadata
|
56
|
-
@public_rights_metadata ||= object.datastreams['rightsMetadata'].ng_xml.clone
|
57
|
-
end
|
58
|
-
|
59
|
-
def public_identity_metadata
|
60
|
-
@public_identity_metadata ||= begin
|
61
|
-
im = object.datastreams['identityMetadata'].ng_xml.clone
|
62
|
-
im.search('//release').each(&:remove) # remove any <release> tags from public xml which have full history
|
63
|
-
im
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
# @return [Nokogiri::XML::Document] sanitized for public consumption
|
68
|
-
def public_content_metadata
|
69
|
-
return Nokogiri::XML::Document.new unless object.datastreams['contentMetadata']
|
70
|
-
|
71
|
-
@public_content_metadata ||= begin
|
72
|
-
result = object.datastreams['contentMetadata'].ng_xml.clone
|
73
|
-
|
74
|
-
# remove any resources or attributes that are not destined for the public XML
|
75
|
-
result.xpath('/contentMetadata/resource[not(file[(@deliver="yes" or @publish="yes")]|externalFile)]').each(&:remove)
|
76
|
-
result.xpath('/contentMetadata/resource/file[not(@deliver="yes" or @publish="yes")]').each(&:remove)
|
77
|
-
result.xpath('/contentMetadata/resource/file').xpath('@preserve|@shelve|@publish|@deliver').each(&:remove)
|
78
|
-
result.xpath('/contentMetadata/resource/file/checksum').each(&:remove)
|
79
|
-
|
80
|
-
# support for dereferencing links via externalFile element(s) to the source (child) item - see JUMBO-19
|
81
|
-
result.xpath('/contentMetadata/resource/externalFile').each do |external_file|
|
82
|
-
add_data_from_src(external_file)
|
83
|
-
end
|
84
|
-
|
85
|
-
result
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
def add_data_from_src(external_file)
|
90
|
-
# enforce pre-conditions that resourceId, objectId, fileId are required
|
91
|
-
src_resource_id = external_file['resourceId']
|
92
|
-
src_druid = external_file['objectId']
|
93
|
-
src_file_id = external_file['fileId']
|
94
|
-
raise DataError, "Malformed externalFile data: #{external_file.to_xml}" if [src_resource_id, src_file_id, src_druid].map(&:blank?).any?
|
95
|
-
|
96
|
-
# grab source item
|
97
|
-
src_item = Dor.find(src_druid)
|
98
|
-
|
99
|
-
# locate and extract the resourceId/fileId elements
|
100
|
-
doc = src_item.contentMetadata.ng_xml
|
101
|
-
src_resource = doc.at_xpath("//resource[@id=\"#{src_resource_id}\"]")
|
102
|
-
src_file = src_resource.at_xpath("file[@id=\"#{src_file_id}\"]")
|
103
|
-
raise DataError, "Unable to find a file node with id=\"#{src_file_id}\" (child of #{object.pid})" unless src_file
|
104
|
-
|
105
|
-
src_image_data = src_file.at_xpath('imageData')
|
106
|
-
|
107
|
-
# always use title regardless of whether a child label is present
|
108
|
-
src_label = doc.create_element('label')
|
109
|
-
src_label.content = src_item.full_title
|
110
|
-
|
111
|
-
# add the extracted label and imageData
|
112
|
-
external_file.add_previous_sibling(src_label)
|
113
|
-
external_file << src_image_data unless src_image_data.nil?
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
@@ -1,99 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Dor
|
4
|
-
# Merges contentMetadata from several objects into one.
|
5
|
-
class PublishMetadataService
|
6
|
-
# @param [Dor::Item] item the object to be publshed
|
7
|
-
def self.publish(item)
|
8
|
-
new(item).publish
|
9
|
-
end
|
10
|
-
|
11
|
-
def initialize(item)
|
12
|
-
@item = item
|
13
|
-
end
|
14
|
-
|
15
|
-
# Appends contentMetadata file resources from the source objects to this object
|
16
|
-
def publish
|
17
|
-
return unpublish unless world_discoverable?
|
18
|
-
|
19
|
-
transfer_metadata
|
20
|
-
publish_notify_on_success
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
attr_reader :item
|
26
|
-
|
27
|
-
def transfer_metadata
|
28
|
-
transfer_to_document_store(DublinCoreService.new(item).ng_xml.to_xml(&:no_declaration), 'dc')
|
29
|
-
%w(identityMetadata contentMetadata rightsMetadata).each do |stream|
|
30
|
-
transfer_to_document_store(item.datastreams[stream].content.to_s, stream) if item.datastreams[stream]
|
31
|
-
end
|
32
|
-
transfer_to_document_store(PublicXmlService.new(item).to_xml, 'public')
|
33
|
-
transfer_to_document_store(PublicDescMetadataService.new(item).to_xml, 'mods')
|
34
|
-
end
|
35
|
-
|
36
|
-
# Clear out the document cache for this item
|
37
|
-
def unpublish
|
38
|
-
purl_druid.prune!
|
39
|
-
publish_delete_on_success
|
40
|
-
end
|
41
|
-
|
42
|
-
def world_discoverable?
|
43
|
-
rights = item.rightsMetadata.ng_xml.clone.remove_namespaces!
|
44
|
-
rights.at_xpath("//rightsMetadata/access[@type='discover']/machine/world")
|
45
|
-
end
|
46
|
-
|
47
|
-
# Create a file inside the content directory under the stacks.local_document_cache_root
|
48
|
-
# @param [String] content The contents of the file to be created
|
49
|
-
# @param [String] filename The name of the file to be created
|
50
|
-
# @return [void]
|
51
|
-
def transfer_to_document_store(content, filename)
|
52
|
-
new_file = File.join(purl_druid.content_dir, filename)
|
53
|
-
File.open(new_file, 'w') { |f| f.write content }
|
54
|
-
end
|
55
|
-
|
56
|
-
def purl_druid
|
57
|
-
@purl_druid ||= DruidTools::PurlDruid.new item.pid, Config.stacks.local_document_cache_root
|
58
|
-
end
|
59
|
-
|
60
|
-
def prune_purl_dir
|
61
|
-
purl_druid.prune!
|
62
|
-
end
|
63
|
-
|
64
|
-
##
|
65
|
-
# When publishing a PURL, we notify purl-fetcher of changes.
|
66
|
-
# If the purl service isn't configured, instead we drop a `aa11bb2222` file into the `local_recent_changes` folder
|
67
|
-
# to notify other applications watching the filesystem (i.e., purl-fetcher).
|
68
|
-
# We also remove any .deletes entry that may have left over from a previous removal
|
69
|
-
def publish_notify_on_success
|
70
|
-
id = item.pid.gsub(/^druid:/, '')
|
71
|
-
if Dor::Config.purl_services.url
|
72
|
-
purl_services = Dor::Config.purl_services.rest_client
|
73
|
-
purl_services["purls/#{id}"].post ''
|
74
|
-
else
|
75
|
-
Deprecation.warn(self, 'You have not configured perl-fetcher (Dor::Config.purl_services.url). This will result in an error in dor-services 7 ')
|
76
|
-
local_recent_changes = Config.stacks.local_recent_changes
|
77
|
-
raise ArgumentError, "Missing local_recent_changes directory: #{local_recent_changes}" unless File.directory?(local_recent_changes)
|
78
|
-
|
79
|
-
FileUtils.touch(File.join(local_recent_changes, id))
|
80
|
-
begin
|
81
|
-
DruidTools::Druid.new(id, Dor::Config.stacks.local_document_cache_root).deletes_delete_record
|
82
|
-
rescue Errno::EACCES
|
83
|
-
Dor.logger.warn "Access denied while trying to remove .deletes file for druid:#{id}"
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
##
|
89
|
-
# When publishing a PURL, we notify purl-fetcher of changes.
|
90
|
-
def publish_delete_on_success
|
91
|
-
return unless Dor::Config.purl_services.url
|
92
|
-
|
93
|
-
id = item.pid.gsub(/^druid:/, '')
|
94
|
-
|
95
|
-
purl_services = Dor::Config.purl_services.rest_client
|
96
|
-
purl_services["purls/#{id}"].delete
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|