Skip to content

Commit

Permalink
Upgrade to blacklight-marc 7.2
Browse files Browse the repository at this point in the history
* Adjust file names and paths to match upstream
* Refactor our customizations
  • Loading branch information
sandbergja committed Apr 14, 2023
1 parent a66d9df commit b7d83e6
Show file tree
Hide file tree
Showing 12 changed files with 428 additions and 275 deletions.
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ gem 'jbuilder', '~> 2.0'
# jquery multiselect plugin for advanced search
gem 'chosen-rails'

gem 'blacklight-marc', '~> 7.1.0'
gem 'blacklight-marc', '~> 7.2.0'
# Capistrano
gem 'bcrypt_pbkdf'
gem 'capistrano', '~> 3.4'
Expand Down
8 changes: 4 additions & 4 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ GEM
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
addressable (2.8.1)
addressable (2.8.4)
public_suffix (>= 2.0.2, < 6.0)
airbrussh (1.4.1)
sshkit (>= 1.6.1, != 1.7.0)
Expand Down Expand Up @@ -124,7 +124,7 @@ GEM
ostruct (>= 0.3.2)
rails (>= 5.1, < 7.1)
view_component (~> 2.66)
blacklight-marc (7.1.1)
blacklight-marc (7.2.0)
blacklight (~> 7.0)
library_stdnums
marc (>= 0.4.3, < 2.0)
Expand Down Expand Up @@ -511,7 +511,7 @@ GEM
simplecov_json_formatter (~> 0.1)
simplecov-html (0.12.3)
simplecov_json_formatter (0.1.4)
slop (4.9.3)
slop (4.10.1)
sneakers (2.11.0)
bunny (~> 2.12)
concurrent-ruby (~> 1.0)
Expand Down Expand Up @@ -640,7 +640,7 @@ DEPENDENCIES
bcrypt_pbkdf
bixby (~> 5.0)
blacklight (~> 7.0)
blacklight-marc (~> 7.1.0)
blacklight-marc (~> 7.2.0)
blacklight_advanced_search (~> 7.0)
blacklight_dynamic_sitemap (~> 0.6.0)
blacklight_range_limit (~> 8.2)
Expand Down
33 changes: 33 additions & 0 deletions app/models/concerns/blacklight/marc/book_ctx_builder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true
require 'openurl/context_object'

module Blacklight
module Marc
# Create an OpenUrl ContextObject for a book
class BookCtxBuilder < CtxBuilder
def build
ctx.referent.set_format('book')
apply_metadata
ctx
end

private

def mapping
{
genre: 'book',
au: author,
aucorp: publisher,
pub: publisher,
edition:,
isbn:,
date:
}
end

def edition
@document['edition_display']&.first
end
end
end
end
78 changes: 78 additions & 0 deletions app/models/concerns/blacklight/marc/ctx_builder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# frozen_string_literal: true
require 'openurl/context_object'

module Blacklight
module Marc
# Create a generic OpenUrl ContextObject
class CtxBuilder
def initialize(document:, format:)
@document = document
@format = format
end

def build
ctx.referent.set_format(genre)
apply_metadata
ctx
end

def ctx
@ctx ||= OpenURL::ContextObject.new
end

private

def apply_metadata
mapping.each do |key, value|
ctx.referent.set_metadata(key.to_s, value)
end
add_identifiers
end

def add_identifiers
id = @document['id']
ctx.referent.add_identifier("https://bibdata.princeton.edu/bibliographic/#{id}")
ctx.referrer.add_identifier('info:sid/catalog.princeton.edu:generator')
ctx.referent.add_identifier("info:oclcnum/#{@document['oclc_s'].first}") unless @document['oclc_s'].nil?
ctx.referent.add_identifier("info:lccn/#{@document['lccn_s'].first}") unless @document['lccn_s'].nil?
end

def mapping
{
genre:,
creator: author,
aucorp: publisher,
pub: publisher,
format: @format,
issn:,
isbn:,
date:
}
end

def author
@document['author_citation_display']&.first
end

def date
@document['pub_date_display']&.first
end

def genre
@format == 'conference' ? @format : 'unknown'
end

def isbn
@document['isbn_s']&.first
end

def issn
@document['issn_s']&.first
end

def publisher
@document['pub_citation_display']&.first
end
end
end
end
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

module Blacklight::Solr::Document::MarcExportOverride
module Blacklight::MARC::Document::MarcExportOverride
# Override Blacklight's version to add nil check
# See https://github.com/projectblacklight/blacklight-marc/issues/95
def clean_end_punctuation(text)
Expand Down
214 changes: 214 additions & 0 deletions app/models/concerns/blacklight/marc/document_extension.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
# frozen_string_literal: true

require 'marc'
require 'openurl/context_object'

# rubocop:disable Metrics/ModuleLength
module Blacklight
module Marc
module DocumentExtension
include Blacklight::Marc::DocumentExport
include OpenURL

# Prepend our overloaded method to bypass bug in Blacklight
# See https://stackoverflow.com/questions/5944278/overriding-method-by-another-defined-in-module
prepend Blacklight::MARC::Document::MarcExportOverride

class UnsupportedMarcFormatType < RuntimeError; end

def self.extended(document)
Blacklight::Solr::Document::MarcExport.register_export_formats(document)
end

# Accesses the MARC::Record constructed from data retrieved over the HTTP
# @return [MARC::Record]
def to_marc
@_ruby_marc_obj ||= load_marc
end

# These are registered by default
# @see Blacklight::Solr::Document::MarcExport.register_export_formats

# Generate the string-serialized XML from the remote MARC record
# @see Blacklight::Solr::Document::MarcExport#export_as_marcxml
# @return [String]
def export_as_marcxml
return '' unless to_marc
super
end

# @see Blacklight::Solr::Document::MarcExport#export_as_marc
# @return [String]
def export_as_marc
return '' unless to_marc
super
end

# @see Blacklight::Solr::Document::MarcExport#export_as_openurl_ctx_kev
# @return [String]
def export_as_openurl_ctx_kev(format = nil)
ctx = to_ctx(format)
# send back the encoded string
ctx.kev
end

# Generate the refworks citation format from the remote MARC record
# @see Blacklight::Solr::Document::MarcExport#export_as_refworks_marc_txt
# @return [String]
def export_as_refworks_marc_txt
return '' unless to_marc
super
end

# These are not registered by default, but still provided as public methods

# @see Blacklight::Solr::Document::MarcExport#export_as_apa_citation_txt
# @return [String]
def export_as_apa_citation_txt
return '' unless to_marc
super
end

# @see Blacklight::Solr::Document::MarcExport#export_as_mla_citation_txt
# @return [String]
def export_as_mla_citation_txt
return '' unless to_marc
super
end

# @see Blacklight::Solr::Document::MarcExport#export_as_chicago_citation_txt
# @return [String]
def export_as_chicago_citation_txt
return '' unless to_marc
super
end

# @see Blacklight::Solr::Document::MarcExport#export_as_endnote
# @return [String]
def export_as_endnote
return '' unless to_marc
super
end

# return openurl ctx object
def to_ctx(format)
@_ctx || build_ctx(format)
end

# We allow the user to retry in very specific scenarios.
def can_retry?
@can_retry
end

protected

def build_ctx(format = nil)
format ||= first('format')&.downcase
unless format.nil?
format = format.is_a?(Array) ? format[0].downcase.strip : format.downcase.strip
end
if format == 'book'
BookCtxBuilder.new(document: self, format:).build
elsif /journal/i.match?(format) # checking using include because institutions may use formats like Journal or Journal/Magazine
JournalCtxBuilder.new(document: self, format:).build
else
CtxBuilder.new(document: self, format:).build
end
end

# Retrieves the bib. ID from the Solr Document
# @return [String]
def marc_source
@_marc_source ||= fetch(_marc_source_field)
end

# Retrieve the MARC 21 bitstream over the HTTP
# @return [MARC::Record]
def marc_record_from_marc21
return if marc_source.blank?
MARC::Record.new_from_marc marc_source
end

# Retrieve the MARC JSON over the HTTP
# @return [MARC::Record]
def marc_record_from_json
return if marc_source.blank?

begin
marc_json = JSON.parse(marc_source)
rescue JSON::ParserError => json_error
Rails.logger.error "#{self.class}: Failed to parse the MARC JSON: #{json_error}"
return
end
MARC::Record.new_from_hash marc_json
end

# Construct a MARC::Record using MARC record data retrieved over the HTTP
# @return [MARC::Record]
def load_marc
marc_format = _marc_format_type.to_s

case marc_format
when 'marcxml'
marc_record_from_marcxml
when 'marc21'
marc_record_from_marc21
when 'json'
marc_record_from_json
else
raise UnsupportedMarcFormatType, "Only marcxml, marc21, and json are supported, this documents format is #{_marc_format_type} and the current extension parameters are #{self.class.extension_parameters.inspect}"
end
rescue StandardError => e
Rails.logger.error("Blacklight failed to parse MARC record. Exception was: #{e}")
nil
end

# Construct a MARC::Record using MARC-XML data retrieved over the HTTP
# @return [MARC::Record]
def marc_record_from_marcxml
id = fetch(_marc_source_field)

response = Faraday.get("#{Requests.config['bibdata_base']}/bibliographic/#{id}")
@can_retry = response.status == 429
response_stream = StringIO.new(response.body)
marc_reader = ::MARC::XMLReader.new(response_stream)
marc_records = marc_reader.to_a
marc_records.first
end

def _marc_helper
@_marc_helper ||= Blacklight::Marc::Document.new fetch(_marc_source_field), _marc_format_type
end

def _marc_source_field
self.class.extension_parameters[:marc_source_field]
end

def _marc_format_type
# TODO: Raise if not present
self.class.extension_parameters[:marc_format_type]
end

# Overwites the get_author_list(record) method from the module Blacklight::Solr::Document::MarcExport
def get_author_list(record)
author_list = []
authors_primary = record.find { |f| f.tag == '100' }
begin
author_primary = authors_primary.find { |s| s.code == 'a' }.value unless authors_primary.nil?
rescue StandardError
''
end
author_list.push(clean_end_punctuation(author_primary)) unless author_primary.nil?
authors_secondary = record.find_all { |f| f.tag == '700' }
authors_secondary&.each do |l|
unless l.find { |s| s.code == 'a' }.nil?
author_list.push(clean_end_punctuation(l.find { |s| s.code == 'a' }.value)) unless l.find { |s| s.code == 'a' }.value.nil?
end
end
author_list.uniq!
author_list
end
end
# rubocop:enable Metrics/ModuleLength
end
end
Loading

0 comments on commit b7d83e6

Please sign in to comment.