Skip to content

Commit

Permalink
Move PublicDescMetadataService from dor-services
Browse files Browse the repository at this point in the history
  • Loading branch information
jcoyne committed May 2, 2019
1 parent f188dd8 commit 712d87e
Show file tree
Hide file tree
Showing 13 changed files with 2,067 additions and 23 deletions.
2 changes: 1 addition & 1 deletion .rubocop.yml
Expand Up @@ -26,7 +26,7 @@ RSpec/ExampleLength:
Enabled: false

RSpec/MultipleExpectations:
Max: 8
Max: 11

RSpec/ExpectActual:
Exclude:
Expand Down
38 changes: 24 additions & 14 deletions .rubocop_todo.yml
@@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2019-05-01 14:31:04 -0500 using RuboCop version 0.65.0.
# on 2019-05-02 14:26:35 -0500 using RuboCop version 0.65.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
Expand Down Expand Up @@ -29,20 +29,20 @@ Lint/UriEscapeUnescape:
- 'app/controllers/sdr_controller.rb'
- 'spec/controllers/sdr_controller_spec.rb'

# Offense count: 19
# Offense count: 22
Metrics/AbcSize:
Max: 122

# Offense count: 2
# Offense count: 3
# Configuration parameters: CountComments.
Metrics/ClassLength:
Max: 139

# Offense count: 3
# Offense count: 4
Metrics/CyclomaticComplexity:
Max: 27

# Offense count: 24
# Offense count: 27
# Configuration parameters: CountComments, ExcludedMethods.
Metrics/MethodLength:
Max: 63
Expand Down Expand Up @@ -71,11 +71,12 @@ Naming/UncommunicativeMethodParamName:
Exclude:
- 'spec/rails_helper.rb'

# Offense count: 4
# Offense count: 6
# Configuration parameters: EnforcedStyle.
# SupportedStyles: snake_case, camelCase
Naming/VariableName:
Exclude:
- 'app/services/public_desc_metadata_service.rb'
- 'spec/rails_helper.rb'

# Offense count: 26
Expand All @@ -100,14 +101,15 @@ RSpec/BeforeAfterAll:
- 'spec/support/**/*.rb'
- 'spec/dor/update_marc_record_service_spec.rb'

# Offense count: 22
# Offense count: 25
# Configuration parameters: Prefixes.
# Prefixes: when, with, without
RSpec/ContextWording:
Exclude:
- 'spec/controllers/objects_controller_spec.rb'
- 'spec/controllers/sdr_controller_spec.rb'
- 'spec/dor/update_marc_record_service_spec.rb'
- 'spec/services/public_desc_metadata_service_spec.rb'
- 'spec/services/public_xml_service_spec.rb'
- 'spec/services/publish_metadata_service_spec.rb'
- 'spec/services/registration_service_spec.rb'
Expand Down Expand Up @@ -145,10 +147,11 @@ RSpec/EmptyLineAfterSubject:
Exclude:
- 'spec/models/symphony_reader_spec.rb'

# Offense count: 18
# Offense count: 20
RSpec/ExpectInHook:
Exclude:
- 'spec/dor/update_marc_record_service_spec.rb'
- 'spec/services/public_desc_metadata_service_spec.rb'
- 'spec/services/publish_metadata_service_spec.rb'
- 'spec/services/registration_service_spec.rb'

Expand All @@ -161,7 +164,7 @@ RSpec/InstanceVariable:
- 'spec/dor/update_marc_record_service_spec.rb'
- 'spec/services/registration_service_spec.rb'

# Offense count: 54
# Offense count: 56
# Configuration parameters: EnforcedStyle.
# SupportedStyles: have_received, receive
RSpec/MessageSpies:
Expand All @@ -171,10 +174,16 @@ RSpec/MessageSpies:
- 'spec/controllers/workflows_controller_spec.rb'
- 'spec/dor/goobi_spec.rb'
- 'spec/dor/update_marc_record_service_spec.rb'
- 'spec/services/public_desc_metadata_service_spec.rb'
- 'spec/services/registration_service_spec.rb'
- 'spec/services/version_service_spec.rb'

# Offense count: 19
# Offense count: 2
# Configuration parameters: AggregateFailuresByDefault.
RSpec/MultipleExpectations:
Max: 11

# Offense count: 22
RSpec/NestedGroups:
Max: 5

Expand All @@ -194,17 +203,19 @@ RSpec/ReturnFromStub:
Exclude:
- 'spec/controllers/workflows_controller_spec.rb'

# Offense count: 1
# Offense count: 2
RSpec/ScatteredLet:
Exclude:
- 'spec/services/public_desc_metadata_service_spec.rb'
- 'spec/services/public_xml_service_spec.rb'

# Offense count: 8
# Offense count: 10
RSpec/ScatteredSetup:
Exclude:
- 'spec/controllers/objects_controller_spec.rb'
- 'spec/controllers/sdr_controller_spec.rb'
- 'spec/controllers/versions_controller_spec.rb'
- 'spec/services/public_desc_metadata_service_spec.rb'
- 'spec/services/publish_metadata_service_spec.rb'

# Offense count: 5
Expand Down Expand Up @@ -250,7 +261,7 @@ Style/ConditionalAssignment:
Exclude:
- 'spec/support/foxml_helper.rb'

# Offense count: 14
# Offense count: 13
Style/Documentation:
Exclude:
- 'spec/**/*'
Expand All @@ -264,7 +275,6 @@ Style/Documentation:
- 'app/models/dor/service_item.rb'
- 'app/models/dor/update_marc_record_service.rb'
- 'app/services/dublin_core_service.rb'
- 'app/services/public_xml_service.rb'
- 'app/services/registration_service.rb'
- 'config/application.rb'
- 'config/initializers/okcomputer.rb'
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/metadata_controller.rb
Expand Up @@ -10,7 +10,7 @@ def dublin_core
end

def descriptive
service = Dor::PublicDescMetadataService.new(@item)
service = PublicDescMetadataService.new(@item)
render xml: service
end
end
2 changes: 1 addition & 1 deletion app/services/dublin_core_service.rb
Expand Up @@ -29,7 +29,7 @@ def ng_xml
private

def desc_md
return Dor::PublicDescMetadataService.new(work).ng_xml(include_access_conditions: false) if include_collection?
return PublicDescMetadataService.new(work).ng_xml(include_access_conditions: false) if include_collection?

work.descMetadata.ng_xml
end
Expand Down
178 changes: 178 additions & 0 deletions app/services/public_desc_metadata_service.rb
@@ -0,0 +1,178 @@
# frozen_string_literal: true

# Creates the descriptive XML that we display on purl.stanford.edu
class PublicDescMetadataService
attr_reader :object

NOKOGIRI_DEEP_COPY = 1

def initialize(object)
@object = object
end

# @return [Nokogiri::XML::Document] A copy of the descriptiveMetadata of the object, to be modified
def doc
@doc ||= object.descMetadata.ng_xml.dup(NOKOGIRI_DEEP_COPY)
end

# @return [String] Public descriptive medatada XML
def to_xml(include_access_conditions: true)
ng_xml(include_access_conditions: include_access_conditions).to_xml
end

# @return [Nokogiri::XML::Document]
def ng_xml(include_access_conditions: true)
@ng_xml ||= begin
add_collection_reference!
add_access_conditions! if include_access_conditions
add_constituent_relations!
strip_comments!

new_doc = Nokogiri::XML(doc.to_xml, &:noblanks)
new_doc.encoding = 'UTF-8'
new_doc
end
end

private

def strip_comments!
doc.xpath('//comment()').remove
end

# Create MODS accessCondition statements from rightsMetadata
def add_access_conditions!
# clear out any existing accessConditions
doc.xpath('//mods:accessCondition', 'mods' => 'http://www.loc.gov/mods/v3').each(&:remove)
rights = object.datastreams['rightsMetadata'].ng_xml

rights.xpath('//use/human[@type="useAndReproduction"]').each do |use|
txt = use.text.strip
next if txt.empty?

doc.root.element_children.last.add_next_sibling doc.create_element('accessCondition', txt, type: 'useAndReproduction')
end
rights.xpath('//copyright/human[@type="copyright"]').each do |cr|
txt = cr.text.strip
next if txt.empty?

doc.root.element_children.last.add_next_sibling doc.create_element('accessCondition', txt, type: 'copyright')
end
rights.xpath("//use/machine[#{ci_compare('type', 'creativecommons')}]").each do |lic_type|
next if lic_type.text =~ /none/i

lic_text = rights.at_xpath("//use/human[#{ci_compare('type', 'creativecommons')}]").text.strip
next if lic_text.empty?

new_text = "CC #{lic_type.text}: #{lic_text}"
doc.root.element_children.last.add_next_sibling doc.create_element('accessCondition', new_text, type: 'license')
end
rights.xpath("//use/machine[#{ci_compare('type', 'opendatacommons')}]").each do |lic_type|
next if lic_type.text =~ /none/i

lic_text = rights.at_xpath("//use/human[#{ci_compare('type', 'opendatacommons')}]").text.strip
next if lic_text.empty?

new_text = "ODC #{lic_type.text}: #{lic_text}"
doc.root.element_children.last.add_next_sibling doc.create_element('accessCondition', new_text, type: 'license')
end
end

# expand constituent relations into relatedItem references -- see JUMBO-18
# @return [Void]
def add_constituent_relations!
object.relationships(:is_constituent_of).each do |parent|
# fetch the parent object to get title
druid = parent.gsub(%r{^info:fedora/}, '')
parent_item = Dor.find(druid)

# create the MODS relation
relatedItem = doc.create_element 'relatedItem'
relatedItem['type'] = 'host'
relatedItem['displayLabel'] = 'Appears in'

# load the title from the parent's DC.title
titleInfo = doc.create_element 'titleInfo'
title = doc.create_element 'title'
title.content = parent_item.full_title
titleInfo << title
relatedItem << titleInfo

# point to the PURL for the parent
location = doc.create_element 'location'
url = doc.create_element 'url'
url.content = "http://#{Dor::Config.stacks.document_cache_host}/#{druid.split(':').last}"
location << url
relatedItem << location

# finish up by adding relation to public MODS
doc.root << relatedItem
end
end

# Adds to desc metadata a relatedItem with information about the collection this object belongs to.
# For use in published mods and mods-to-DC conversion.
# @return [Void]
def add_collection_reference!
collections = object.relationships(:is_member_of_collection)
return if collections.empty?

remove_related_item_nodes_for_collections!

collections.each do |collection_uri|
collection_druid = collection_uri.gsub('info:fedora/', '')
add_related_item_node_for_collection! collection_druid
end
end

# Remove existing relatedItem entries for collections from descMetadata
def remove_related_item_nodes_for_collections!
doc.search('/mods:mods/mods:relatedItem[@type="host"]/mods:typeOfResource[@collection=\'yes\']', 'mods' => 'http://www.loc.gov/mods/v3').each do |node|
node.parent.remove
end
end

def add_related_item_node_for_collection!(collection_druid)
begin
collection_obj = Dor.find(collection_druid)
rescue ActiveFedora::ObjectNotFoundError
return nil
end

title_node = Nokogiri::XML::Node.new('title', doc)
title_node.content = collection_obj.full_title

title_info_node = Nokogiri::XML::Node.new('titleInfo', doc)
title_info_node.add_child(title_node)

# e.g.:
# <location>
# <url>http://purl.stanford.edu/rh056sr3313</url>
# </location>
loc_node = doc.create_element('location')
url_node = doc.create_element('url')
url_node.content = "https://#{Dor::Config.stacks.document_cache_host}/#{collection_druid.split(':').last}"
loc_node << url_node

type_node = Nokogiri::XML::Node.new('typeOfResource', doc)
type_node['collection'] = 'yes'

related_item_node = Nokogiri::XML::Node.new('relatedItem', doc)
related_item_node['type'] = 'host'

related_item_node.add_child(title_info_node)
related_item_node.add_child(loc_node)
related_item_node.add_child(type_node)

doc.root.add_child(related_item_node)
end

# Builds case-insensitive xpath translate function call that will match the attribute to a value
def ci_compare(attribute, value)
"translate(
@#{attribute},
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
'abcdefghijklmnopqrstuvwxyz'
) = '#{value}' "
end
end
3 changes: 2 additions & 1 deletion app/services/public_xml_service.rb
@@ -1,5 +1,6 @@
# frozen_string_literal: true

# Exports the full object XML that we display on purl.stanford.edu
class PublicXmlService
attr_reader :object

Expand All @@ -18,7 +19,7 @@ def to_xml
pub.add_child(public_rights_metadata.root)
pub.add_child(public_relationships.root)
pub.add_child(DublinCoreService.new(object).ng_xml.root)
pub.add_child(Dor::PublicDescMetadataService.new(object).ng_xml.root)
pub.add_child(PublicDescMetadataService.new(object).ng_xml.root)
pub.add_child(release_xml.root) unless release_xml.xpath('//release').children.empty? # If there are no release_tags, this prevents an empty <releaseData/> from being added
# 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,
# so we need to calculate it and then look at the final result.
Expand Down
2 changes: 1 addition & 1 deletion app/services/publish_metadata_service.rb
Expand Up @@ -29,7 +29,7 @@ def transfer_metadata
transfer_to_document_store(item.datastreams[stream].content.to_s, stream) if item.datastreams[stream]
end
transfer_to_document_store(PublicXmlService.new(item).to_xml, 'public')
transfer_to_document_store(Dor::PublicDescMetadataService.new(item).to_xml, 'mods')
transfer_to_document_store(PublicDescMetadataService.new(item).to_xml, 'mods')
end

# Clear out the document cache for this item
Expand Down

0 comments on commit 712d87e

Please sign in to comment.