-
Notifications
You must be signed in to change notification settings - Fork 2
/
registration_service.rb
155 lines (131 loc) · 6.25 KB
/
registration_service.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# frozen_string_literal: true
# Registers an object. Creates a skeleton object in Fedora with a Druid.
class RegistrationService
class << self
# @param [Hash] params
# @see register_object similar but different
def create_from_request(params)
other_ids = Array(params[:other_id]).map do |id|
if id =~ /^symphony:(.+)$/
"#{$1.length < 14 ? 'catkey' : 'barcode'}:#{$1}"
else
id
end
end
if params[:label] == ':auto'
params.delete(:label)
params.delete('label')
metadata_id = MetadataService.resolvable(other_ids).first
params[:label] = MetadataService.label_for(metadata_id)
end
dor_params = {
pid: params[:pid],
admin_policy: params[:admin_policy],
content_model: params[:model],
label: params[:label],
object_type: params[:object_type],
other_ids: ids_to_hash(other_ids),
parent: params[:parent],
source_id: ids_to_hash(params[:source_id]),
tags: params[:tag] || [],
seed_datastream: params[:seed_datastream],
initiate_workflow: Array(params[:initiate_workflow]) + Array(params[:workflow_id]),
rights: params[:rights],
metadata_source: params[:metadata_source],
collection: params[:collection],
workflow_priority: params[:workflow_priority]
}
dor_params.delete_if { |_k, v| v.nil? }
request = RegistrationRequest.new(dor_params)
dor_obj = register_object(request)
pid = dor_obj.pid
location = URI.parse(Dor::Config.fedora.safeurl.sub(%r{/*$}, '/')).merge("objects/#{pid}").to_s
dor_params.dup.merge(location: location, pid: pid)
end
private
# @TODO: these duplicate checks could be combined into 1 query
# @param [String] pid an ID to check, if desired. If not passed (or nil), a new ID is minted
# @return [String] a pid you can use immidately, either freshly minted or your checked value
# @raise [Dor::DuplicateIdError]
def unduplicated_pid(pid = nil)
return Dor::SuriService.mint_id unless pid
existing_pid = Dor::SearchService.query_by_id(pid).first
raise Dor::DuplicateIdError.new(existing_pid), "An object with the PID #{pid} has already been registered." unless existing_pid.nil?
pid
end
# @param [String] source_id_string a fully qualified source:val or empty string
# @return [String] the same qualified source:id for immediate use
# @raise [Dor::DuplicateIdError]
def check_source_id(source_id_string)
return '' if source_id_string == ''
unless Dor::SearchService.query_by_id(source_id_string.to_s).first.nil?
raise Dor::DuplicateIdError.new(source_id_string), "An object with the source ID '#{source_id_string}' has already been registered."
end
source_id_string
end
# @param [RegistrationRequest] RegistrationRequest
def register_object(request)
request.validate!
# Check for sourceId conflict *before* potentially minting PID
source_id_string = check_source_id [request.source_id.keys.first, request.source_id[request.source_id.keys.first]].compact.join(':')
pid = unduplicated_pid(request.pid)
apo_object = Dor.find(request.admin_policy)
new_item = request.item_class.new(pid: pid)
new_item.label = request.label.length > 254 ? request.label[0, 254] : request.label
idmd = new_item.identityMetadata
idmd.sourceId = source_id_string
idmd.add_value(:objectId, pid)
idmd.add_value(:objectCreator, 'DOR')
idmd.add_value(:objectLabel, request.label)
idmd.add_value(:objectType, request.object_type)
request.other_ids.each_pair { |name, value| idmd.add_otherId("#{name}:#{value}") }
request.tags.each { |tag| idmd.add_value(:tag, tag) }
new_item.admin_policy_object = apo_object
apo_object.administrativeMetadata.ng_xml.xpath('/administrativeMetadata/relationships/*').each do |rel|
short_predicate = ActiveFedora::RelsExtDatastream.short_predicate rel.namespace.href + rel.name
if short_predicate.nil?
ix = 0
ix += 1 while ActiveFedora::Predicates.predicate_mappings[rel.namespace.href].key?(short_predicate = :"extra_predicate_#{ix}")
ActiveFedora::Predicates.predicate_mappings[rel.namespace.href][short_predicate] = rel.name
end
new_item.add_relationship short_predicate, rel['rdf:resource']
end
new_item.add_collection(request.collection) if request.collection
if request.rights && %w(item collection).include?(request.object_type)
rights_xml = apo_object.defaultObjectRights.ng_xml
new_item.datastreams['rightsMetadata'].content = rights_xml.to_s
new_item.read_rights = request.rights unless request.rights == 'default' # already defaulted to default!
end
# create basic mods from the label
build_desc_metadata_from_label(new_item, request.label) if request.metadata_source == 'label'
RefreshMetadataAction.run(new_item) if request.seed_desc_metadata
new_item.class.ancestors.select { |x| x.respond_to?(:to_class_uri) && x != ActiveFedora::Base }.each do |parent_class|
new_item.add_relationship(:has_model, parent_class.to_class_uri)
end
new_item.save
# Once we save, then it's safe to start any workflows. Otherwise there could be a race condition
initiate_workflow(workflows: request.initiate_workflow, item: new_item, priority: request.workflow_priority)
new_item
end
def ids_to_hash(ids)
return nil if ids.nil?
Hash[Array(ids).map { |id| id.split(':', 2) }]
end
def initiate_workflow(workflows:, item:, priority:)
Honeybadger.notify("RegistrationService received deprecated parameter `initiate_workflow' with: `#{workflows.inspect}'") if workflows.present?
workflows.each do |workflow_id|
Dor::Config.workflow.client.create_workflow_by_name(item.pid, workflow_id, priority: priority)
end
end
def build_desc_metadata_from_label(new_item, label)
builder = Nokogiri::XML::Builder.new do |xml|
xml.mods(Dor::DescMetadataDS::MODS_HEADER_CONFIG) do
xml.titleInfo do
xml.title label
end
end
end
new_item.descMetadata.content = builder.to_xml
end
end
end