Skip to content

Commit

Permalink
Add Barcode lookup model
Browse files Browse the repository at this point in the history
The returned information from the Primo API is sent to the user in the same details block that other lookups use. We do not have a standard model for this, though.

Updates to barcode lookup model

New controller test

Refactor barcode lookup method
  • Loading branch information
matt-bernhardt committed Jan 9, 2025
1 parent cc39da7 commit 0c80867
Show file tree
Hide file tree
Showing 6 changed files with 294 additions and 2 deletions.
6 changes: 4 additions & 2 deletions app/graphql/types/standard_identifiers_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@

module Types
class StandardIdentifiersType < Types::BaseObject
description 'A detector for standard identifiers in search terms. Currently supported: ISBN, ISSN, PMID, DOI'
description 'A detector for standard identifiers in search terms. Currently supported: Barcode, ISBN, ISSN, PMID, DOI'

field :details, DetailsType, description: 'Additional information about the detected identifier(s)'
field :kind, String, null: false, description: 'The type of identifier detected (one of ISBN, ISSN, PMID, DOI)'
field :kind, String, null: false, description: 'The type of identifier detected (one of Barcode, ISBN, ISSN, PMID, DOI)'
field :value, String, null: false, description: 'The identifier detected in the search term'

# details does external lookups and should only be run if the fields
# have been explicitly requested
def details
case @object[:kind]
when :barcode
LookupBarcode.new.info(@object[:value])
when :doi
LookupDoi.new.info(@object[:value])
when :isbn
Expand Down
56 changes: 56 additions & 0 deletions app/models/lookup_barcode.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# frozen_string_literal: true

class LookupBarcode
def info(barcode)
xml = fetch(barcode)

return if xml == 'Error'

# return if xml.xpath('//numberOfRecords').text.to_i.zero?

metadata = extract_metadata(xml)

if metadata.reject { |_k, v| v.empty? }.present?
metadata[:barcode] = barcode
metadata[:link_resolver_url] = link_resolver_url(metadata)
metadata
else
Rails.logger.debug { "Barcode lookup error. Barcode #{barcode} detected by Primo returned no data" }
nil
end
end

private

def extract_metadata(xml)
{
recordId: xml.xpath('//recordIdentifier').text,
title: xml.xpath('//title').text,
date: xml.xpath('//date').text,
publisher: xml.xpath('//publisher').text,
authors: xml.xpath('//contributor').text
}
end

def url(barcode)
"https://mit.alma.exlibrisgroup.com/view/sru/01MIT_INST?version=1.2&operation=searchRetrieve&recordSchema=dc&query=alma.all_for_ui=#{barcode}"
end

def fetch(barcode)
resp = HTTP.headers(accept: 'application/xml').get(url(barcode))

if resp.status == 200
Nokogiri::XML(resp.to_s).remove_namespaces!
else
Rails.logger.debug do
"Barcode lookup error. Barcode #{barcode} detected but Primo returned an error status"
end
Rails.logger.debug { "URL: #{url(barcode)}" }
'Error'
end
end

def link_resolver_url(metadata)
"https://mit.primo.exlibrisgroup.com/discovery/fulldisplay?vid=01MIT_INST:MIT&docid=alma#{metadata[:recordId]}"
end
end
18 changes: 18 additions & 0 deletions test/controllers/graphql_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,24 @@ class GraphqlControllerTest < ActionDispatch::IntegrationTest
assert_equal('10.1038/nphys1170', json['data']['logSearchEvent']['detectors']['standardIdentifiers'].first['value'])
end

test 'search event query can return detected barcodes' do
post '/graphql', params: { query: '{
logSearchEvent(sourceSystem: "timdex", searchTerm: "39080678901234") {
detectors {
standardIdentifiers {
kind
value
}
}
}
}'}

json = response.parsed_body

assert_equal('barcode', json['data']['logSearchEvent']['detectors']['standardIdentifiers'].first['kind'])
assert_equal('39080678901234', json['data']['logSearchEvent']['detectors']['standardIdentifiers'].first['value'])
end

test 'search event query can return detected journals' do
post '/graphql', params: { query: '{
logSearchEvent(sourceSystem: "timdex", searchTerm: "nature") {
Expand Down
35 changes: 35 additions & 0 deletions test/models/lookup_barcode_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# frozen_string_literal: true

require 'test_helper'

class LookupBarcodeTest < ActiveSupport::TestCase
test 'metadata object is returned with expected fields' do
VCR.use_cassette('barcode 39080027236626') do
metadata = LookupBarcode.new.info('39080027236626')

expected_keys = %i[title date publisher authors link_resolver_url]

expected_keys.each do |key|
assert_includes(metadata.keys, key)
end
end
end

test 'link resolver URL returns a simple item URL' do
VCR.use_cassette('barcode 39080027236626') do
metadata = LookupBarcode.new.info('39080027236626')

expected_url = 'https://mit.primo.exlibrisgroup.com/discovery/fulldisplay?vid=01MIT_INST:MIT&docid=alma990002933430106761'

assert_equal(expected_url, metadata[:link_resolver_url])
end
end

test 'barcode not found' do
VCR.use_cassette('barcode not found') do
metadata = LookupBarcode.new.info('this-is-not-a-barcode')

assert_nil(metadata)
end
end
end
107 changes: 107 additions & 0 deletions test/vcr_cassettes/barcode_39080027236626.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

74 changes: 74 additions & 0 deletions test/vcr_cassettes/barcode_not_found.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 0c80867

Please sign in to comment.