Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update build spec requestable #430

Merged
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const app = express()
app.set('trust proxy', 'loopback')

app.init = async () => {
console.log('heeeeere')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove

await loadConfig.loadConfig()
await loadNyplCoreData()
preflightCheck()
Expand Down
2 changes: 1 addition & 1 deletion config/test.env
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ NYPL_OAUTH_URL=http://oauth.example.com
ENCRYPTED_NYPL_OAUTH_ID=encrypted-nypl-oauth-id
ENCRYPTED_NYPL_OAUTH_SECRET=encrypted-nypl-oauth-id

NYPL_CORE_VERSION=v2.21
NYPL_CORE_VERSION=v2.23

LOG_LEVEL=error
FEATURES=on-site-edd
Expand Down
38 changes: 19 additions & 19 deletions lib/delivery-locations-resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class DeliveryLocationsResolver {
}

static requestableBasedOnHoldingLocation (item) {
const locationCode = this.extractLocationCode(item)
const locationCode = DeliveryLocationsResolver.extractLocationCode(item)

if (!DeliveryLocationsResolver.nyplCoreLocation(locationCode)) {
logger.warn(`DeliveryLocationsResolver: Unrecognized holdingLocation for ${item.uri}: ${locationCode}`)
Expand Down Expand Up @@ -166,7 +166,7 @@ class DeliveryLocationsResolver {
return {
id: `loc:${location.code}`,
label: location.label,
sortPosition: this.sortPosition(location)
sortPosition: DeliveryLocationsResolver.sortPosition(location)
}
})
// Either way, sort deliveryLocation entries by name:
Expand All @@ -191,14 +191,14 @@ class DeliveryLocationsResolver {
}

static attachRecapDeliveryInfo (item) {
const info = this.getRecapDeliveryInfo(item)
const info = DeliveryLocationsResolver.getRecapDeliveryInfo(item)
item.eddRequestable = info.eddRequestable
item.deliveryLocation = info.deliveryLocation
return item
}

static attachOnsiteDeliveryInfo (item) {
const info = this.getOnsiteDeliveryInfo(item)
const info = DeliveryLocationsResolver.getOnsiteDeliveryInfo(item)
item.eddRequestable = info.eddRequestable
item.deliveryLocation = info.deliveryLocation
return item
Expand All @@ -212,15 +212,15 @@ class DeliveryLocationsResolver {
const hasRecapCustomerCode = item.recapCustomerCode && item.recapCustomerCode[0]
const nyplItem = isItemNyplOwned(item)
if (!hasRecapCustomerCode) {
const requestableBasedOnHoldingLocation = nyplItem ? this.requestableBasedOnHoldingLocation(item) : true
const requestableBasedOnHoldingLocation = nyplItem ? DeliveryLocationsResolver.requestableBasedOnHoldingLocation(item) : true
// the length of the list of delivery locations is checked later to determine physical requestability
// In case of an offsite item with no recap customer code, we want this to be based on holding location
// so we put a placeholder '' in case it is requestable based on holding location
deliveryLocation = requestableBasedOnHoldingLocation ? [''] : []
eddRequestable = requestableBasedOnHoldingLocation
} else if (!nyplItem || this.requestableBasedOnHoldingLocation(item)) {
deliveryLocation = this.deliveryLocationsByRecapCustomerCode(item.recapCustomerCode[0])
eddRequestable = this.__eddRequestableByCustomerCode(item.recapCustomerCode[0])
} else if (!nyplItem || DeliveryLocationsResolver.requestableBasedOnHoldingLocation(item)) {
deliveryLocation = DeliveryLocationsResolver.deliveryLocationsByRecapCustomerCode(item.recapCustomerCode[0])
eddRequestable = DeliveryLocationsResolver.__eddRequestableByCustomerCode(item.recapCustomerCode[0])
} else {
deliveryLocation = []
eddRequestable = false
Expand All @@ -233,7 +233,7 @@ class DeliveryLocationsResolver {
eddRequestable: false,
deliveryLocation: []
}
const holdingLocationCode = this.extractLocationCode(item)
const holdingLocationCode = DeliveryLocationsResolver.extractLocationCode(item)
const sierraData = DeliveryLocationsResolver.nyplCoreLocation(holdingLocationCode)
if (!sierraData) {
// This case is mainly to satisfy a test which wants eddRequestable = false
Expand All @@ -243,15 +243,15 @@ class DeliveryLocationsResolver {
}
// if nypl core says it's unrequestable, it can still be eddRequestable,
// but its definitely not phys requestable.
deliveryInfo.eddRequestable = this.eddRequestableByOnSiteCriteria(item)
if (!this.requestableBasedOnHoldingLocation(item)) {
deliveryInfo.eddRequestable = DeliveryLocationsResolver.eddRequestableByOnSiteCriteria(item)
if (!DeliveryLocationsResolver.requestableBasedOnHoldingLocation(item)) {
return deliveryInfo
}
// if nypl-core reports that a holding location's delivery locations
// should be found by M2 code, but only if the item has an M2 customer code
const deliverableToResolution = sierraData.deliverableToResolution
if (deliverableToResolution === 'm2-customer-code' && item.m2CustomerCode && item.m2CustomerCode[0]) {
deliveryInfo.deliveryLocation = this.deliveryLocationsByM2CustomerCode(item.m2CustomerCode[0])
deliveryInfo.deliveryLocation = DeliveryLocationsResolver.deliveryLocationsByM2CustomerCode(item.m2CustomerCode[0])
}
// if no value, default to sierra location lookup
if (!deliverableToResolution) {
Expand All @@ -275,15 +275,15 @@ class DeliveryLocationsResolver {
}

/**
* Given an array of items (ES hits), returns the same items with `eddRequestable` & `deliveryLocations`
* Given an array of items (ES hits), returns the same items with `eddRequestable` & `deliveryLocations`. We verify all recap customer codes because our indexed data may be stale.
*
* @return Promise<Array<items>> A Promise that resolves and array of items, modified to include `eddRequestable` & `deliveryLocations`
*/
static attachDeliveryLocationsAndEddRequestability (items, scholarRoom) {
// Extract ReCAP barcodes from items:
const recapBarcodes = this.extractRecapBarcodes(items)
const recapBarcodes = DeliveryLocationsResolver.extractRecapBarcodes(items)
// Get a map from barcodes to ReCAP customercodes:
return this.__recapCustomerCodesByBarcodes(recapBarcodes)
return DeliveryLocationsResolver.__recapCustomerCodesByBarcodes(recapBarcodes)
.then((barcodeToRecapCustomerCode) => {
// Now map over items to affix deliveryLocations:
return items.map((item) => {
Expand All @@ -292,15 +292,15 @@ class DeliveryLocationsResolver {
item.recapCustomerCode = [barcodeToRecapCustomerCode[barcode]]
// If recap has a customer code for this barcode, map it by recap cust code:
if (item.recapCustomerCode[0]) {
item = this.attachRecapDeliveryInfo(item)
item = DeliveryLocationsResolver.attachRecapDeliveryInfo(item)
// Otherwise, it's an onsite item
} else {
item = this.attachOnsiteDeliveryInfo(item)
item = DeliveryLocationsResolver.attachOnsiteDeliveryInfo(item)
}
// Establish default for Electronic Document Delivery flag:
item.eddRequestable = !!item.eddRequestable
const filteredDeliveryLocationsWithScholarRoom = this.filterLocations(item.deliveryLocation, scholarRoom)
item.deliveryLocation = this.formatLocations(filteredDeliveryLocationsWithScholarRoom)
const filteredDeliveryLocationsWithScholarRoom = DeliveryLocationsResolver.filterLocations(item.deliveryLocation, scholarRoom)
item.deliveryLocation = DeliveryLocationsResolver.formatLocations(filteredDeliveryLocationsWithScholarRoom)
return item
})
})
Expand Down
29 changes: 20 additions & 9 deletions lib/requestability_resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,57 @@ const DeliveryLocationsResolver = require('./delivery-locations-resolver')
const { isItemNyplOwned } = require('./ownership_determination')
const { isInRecap } = require('./util')
const logger = require('./logger')

class RequestabilityResolver {
static fixItemRequestability (elasticSearchResponse) {
elasticSearchResponse.hits.hits
.forEach((hit) => {
const parentBibHasFindingAid = !!hit._source.supplementaryContent?.find((el) => el.label.toLowerCase() === 'finding aid')
hit._source.items = hit._source.items.map((item) => {
if (item.electronicLocator) return item
let deliveryInfo
const itemIsInRecap = isInRecap(item)
let physRequestableCriteria
const hasRecapCustomerCode = item.recapCustomerCode && item.recapCustomerCode[0]
const hasRecapCustomerCode = item.recapCustomerCode?.[0]
if (itemIsInRecap) {
// recap items missing codes should default to true for phys and edd
// requestable, unless it has a non-requestable holding location
deliveryInfo = DeliveryLocationsResolver.getRecapDeliveryInfo(item)
physRequestableCriteria = hasRecapCustomerCode
? `${(deliveryInfo.deliveryLocation &&
deliveryInfo.deliveryLocation.length) || 0} delivery locations.`
? `${(deliveryInfo.deliveryLocation?.length) || 0} delivery locations.`
: 'Missing customer code'
} else if (!itemIsInRecap) {
deliveryInfo = DeliveryLocationsResolver.getOnsiteDeliveryInfo(item)
physRequestableCriteria = `${(deliveryInfo.deliveryLocation &&
deliveryInfo.deliveryLocation.length) || 0} delivery locations.`
physRequestableCriteria = `${(deliveryInfo.deliveryLocation?.length) || 0} delivery locations.`
}
item.eddRequestable = !!deliveryInfo.eddRequestable
item.physRequestable = !!(deliveryInfo.deliveryLocation &&
deliveryInfo.deliveryLocation.length)
item.specRequestable = !!item.aeonUrl
item.specRequestable = this.buildSpecRequestable(item, parentBibHasFindingAid)
item.physRequestable = !!deliveryInfo.deliveryLocation?.length
item.eddRequestable = !!deliveryInfo.eddRequestable && !item.specRequestable
// items without barcodes should not be requestable
const hasBarcode = (item.identifier || []).some((identifier) => /^(urn|bf):[bB]arcode:\w+/.test(identifier))
if (isItemNyplOwned(item) && !hasBarcode) {
physRequestableCriteria = 'NYPL item missing barcode'
item.physRequestable = false
}
if (item.specRequestable && item.physRequestable) {
item.physRequestable = false
physRequestableCriteria = 'specRequestable overrides physRequestable location'
}
logger.debug(`item ${item.uri}: `, { physRequestable: item.physRequestable, physRequestableCriteria })
item.requestable = [item.eddRequestable || item.physRequestable || item.specRequestable]
console.log({ specRequestable: item.specRequestable, physRequestable: item.physRequestable, eddRequestable: item.eddRequestable, physRequestableCriteria })
return item
})
})
return elasticSearchResponse
}

static buildSpecRequestable (item, parentBibHasFindingAid) {
const holdingLocation = DeliveryLocationsResolver.extractLocationCode(item)
const nyplCoreLocation = DeliveryLocationsResolver.nyplCoreLocation(holdingLocation)
const isSpecialCollectionsOnlyAccessType = !!(nyplCoreLocation?.collectionAccessType === 'special')
return !!item.aeonUrl || parentBibHasFindingAid || isSpecialCollectionsOnlyAccessType
}
}

module.exports = RequestabilityResolver
152 changes: 152 additions & 0 deletions test/fixtures/specRequestable/findingAid-es-response.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
module.exports = () => {
return {
_shards: {
failed: 0,
successful: 1,
total: 1
},
took: 1,
hits: {
total: 1,
max_score: 1.3862944,
hits: [
{
_id: 'b10980129',
_source: {
supplementaryContent: [{
label: 'Finding aid',
url: 'spaghetti.com'
}],
items: [
{
holdingLocation: [
{
label: 'OFFSITE - Request in Advance',
id: 'loc:rc2ma'
}
],
status_packed: [
'status:na||Not Available'
],
owner: [
{
id: 'orgs:1000',
label: 'Stephen A. Schwarzman Building'
}
],
deliveryLocation: [
{
id: 'loc:mala',
label: 'SASB - Allen Scholar Room'
}
],
deliveryLocation_packed: [
'loc:mala||SASB - Allen Scholar Room'
],
uri: 'i10283664',
accessMessage_packed: [
'accessMessage:2||ADV REQUEST'
],
accessMessage: [
{
id: 'accessMessage:2',
label: 'ADV REQUEST'
}
],
status: [
{
id: 'status:na',
label: 'Not available'
}
],
owner_packed: [
'orgs:1000||Stephen A. Schwarzman Building'
],
requestable: [
false
],
identifier: [
'urn:barcode:1000546836'
],
holdingLocation_packed: [
'loc:rc2ma||OFFSITE - Request in Advance'
],
shelfMark: [
'*OFC 90-2649'
],
suppressed: [
false
]
},
{
holdingLocation: [
{
label: 'OFFSITE - Request in Advance',
id: 'loc:rc2ma'
}
],
status_packed: [
'status:a||Available'
],
owner: [
{
id: 'orgs:1000',
label: 'Stephen A. Schwarzman Building'
}
],
deliveryLocation: [
{
id: 'loc:mala',
label: 'SASB - Allen Scholar Room'
}
],
deliveryLocation_packed: [
'loc:mala||SASB - Allen Scholar Room'
],
uri: 'i102836649',
accessMessage_packed: [
'accessMessage:2||ADV REQUEST'
],
accessMessage: [
{
id: 'accessMessage:2',
label: 'ADV REQUEST'
}
],
status: [
{
id: 'status:a',
label: 'Available'
}
],
owner_packed: [
'orgs:1000||Stephen A. Schwarzman Building'
],
requestable: [
false
],
identifier: [
'urn:barcode:10005468369'
],
holdingLocation_packed: [
'loc:rc2ma||OFFSITE - Request in Advance'
],
shelfMark: [
'*OFC 90-2649 2'
],
suppressed: [
false
]
}
]

},
_type: 'resource',
_index: 'resources-2017-06-13',
_score: 154.93451
}
]
},
timed_out: false
}
}
Loading
Loading