Skip to content

Commit 7b79f1e

Browse files
Merge pull request #431 from NYPL/noref-nypl-core-objects-async
specRequest update and async update
2 parents c257110 + dfa867e commit 7b79f1e

File tree

7 files changed

+525
-33
lines changed

7 files changed

+525
-33
lines changed

config/test.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ NYPL_OAUTH_URL=http://oauth.example.com
99
ENCRYPTED_NYPL_OAUTH_ID=encrypted-nypl-oauth-id
1010
ENCRYPTED_NYPL_OAUTH_SECRET=encrypted-nypl-oauth-id
1111

12-
NYPL_CORE_VERSION=v2.21
12+
NYPL_CORE_VERSION=v2.23
1313

1414
LOG_LEVEL=error
1515
FEATURES=on-site-edd

lib/delivery-locations-resolver.js

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class DeliveryLocationsResolver {
1212
}
1313

1414
static requestableBasedOnHoldingLocation (item) {
15-
const locationCode = this.extractLocationCode(item)
15+
const locationCode = DeliveryLocationsResolver.extractLocationCode(item)
1616

1717
if (!DeliveryLocationsResolver.nyplCoreLocation(locationCode)) {
1818
logger.warn(`DeliveryLocationsResolver: Unrecognized holdingLocation for ${item.uri}: ${locationCode}`)
@@ -166,7 +166,7 @@ class DeliveryLocationsResolver {
166166
return {
167167
id: `loc:${location.code}`,
168168
label: location.label,
169-
sortPosition: this.sortPosition(location)
169+
sortPosition: DeliveryLocationsResolver.sortPosition(location)
170170
}
171171
})
172172
// Either way, sort deliveryLocation entries by name:
@@ -191,14 +191,14 @@ class DeliveryLocationsResolver {
191191
}
192192

193193
static attachRecapDeliveryInfo (item) {
194-
const info = this.getRecapDeliveryInfo(item)
194+
const info = DeliveryLocationsResolver.getRecapDeliveryInfo(item)
195195
item.eddRequestable = info.eddRequestable
196196
item.deliveryLocation = info.deliveryLocation
197197
return item
198198
}
199199

200200
static attachOnsiteDeliveryInfo (item) {
201-
const info = this.getOnsiteDeliveryInfo(item)
201+
const info = DeliveryLocationsResolver.getOnsiteDeliveryInfo(item)
202202
item.eddRequestable = info.eddRequestable
203203
item.deliveryLocation = info.deliveryLocation
204204
return item
@@ -212,15 +212,15 @@ class DeliveryLocationsResolver {
212212
const hasRecapCustomerCode = item.recapCustomerCode && item.recapCustomerCode[0]
213213
const nyplItem = isItemNyplOwned(item)
214214
if (!hasRecapCustomerCode) {
215-
const requestableBasedOnHoldingLocation = nyplItem ? this.requestableBasedOnHoldingLocation(item) : true
215+
const requestableBasedOnHoldingLocation = nyplItem ? DeliveryLocationsResolver.requestableBasedOnHoldingLocation(item) : true
216216
// the length of the list of delivery locations is checked later to determine physical requestability
217217
// In case of an offsite item with no recap customer code, we want this to be based on holding location
218218
// so we put a placeholder '' in case it is requestable based on holding location
219219
deliveryLocation = requestableBasedOnHoldingLocation ? [''] : []
220220
eddRequestable = requestableBasedOnHoldingLocation
221-
} else if (!nyplItem || this.requestableBasedOnHoldingLocation(item)) {
222-
deliveryLocation = this.deliveryLocationsByRecapCustomerCode(item.recapCustomerCode[0])
223-
eddRequestable = this.__eddRequestableByCustomerCode(item.recapCustomerCode[0])
221+
} else if (!nyplItem || DeliveryLocationsResolver.requestableBasedOnHoldingLocation(item)) {
222+
deliveryLocation = DeliveryLocationsResolver.deliveryLocationsByRecapCustomerCode(item.recapCustomerCode[0])
223+
eddRequestable = DeliveryLocationsResolver.__eddRequestableByCustomerCode(item.recapCustomerCode[0])
224224
} else {
225225
deliveryLocation = []
226226
eddRequestable = false
@@ -233,7 +233,7 @@ class DeliveryLocationsResolver {
233233
eddRequestable: false,
234234
deliveryLocation: []
235235
}
236-
const holdingLocationCode = this.extractLocationCode(item)
236+
const holdingLocationCode = DeliveryLocationsResolver.extractLocationCode(item)
237237
const sierraData = DeliveryLocationsResolver.nyplCoreLocation(holdingLocationCode)
238238
if (!sierraData) {
239239
// This case is mainly to satisfy a test which wants eddRequestable = false
@@ -243,15 +243,15 @@ class DeliveryLocationsResolver {
243243
}
244244
// if nypl core says it's unrequestable, it can still be eddRequestable,
245245
// but its definitely not phys requestable.
246-
deliveryInfo.eddRequestable = this.eddRequestableByOnSiteCriteria(item)
247-
if (!this.requestableBasedOnHoldingLocation(item)) {
246+
deliveryInfo.eddRequestable = DeliveryLocationsResolver.eddRequestableByOnSiteCriteria(item)
247+
if (!DeliveryLocationsResolver.requestableBasedOnHoldingLocation(item)) {
248248
return deliveryInfo
249249
}
250250
// if nypl-core reports that a holding location's delivery locations
251251
// should be found by M2 code, but only if the item has an M2 customer code
252252
const deliverableToResolution = sierraData.deliverableToResolution
253253
if (deliverableToResolution === 'm2-customer-code' && item.m2CustomerCode && item.m2CustomerCode[0]) {
254-
deliveryInfo.deliveryLocation = this.deliveryLocationsByM2CustomerCode(item.m2CustomerCode[0])
254+
deliveryInfo.deliveryLocation = DeliveryLocationsResolver.deliveryLocationsByM2CustomerCode(item.m2CustomerCode[0])
255255
}
256256
// if no value, default to sierra location lookup
257257
if (!deliverableToResolution) {
@@ -275,15 +275,15 @@ class DeliveryLocationsResolver {
275275
}
276276

277277
/**
278-
* Given an array of items (ES hits), returns the same items with `eddRequestable` & `deliveryLocations`
278+
* 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.
279279
*
280280
* @return Promise<Array<items>> A Promise that resolves and array of items, modified to include `eddRequestable` & `deliveryLocations`
281281
*/
282282
static attachDeliveryLocationsAndEddRequestability (items, scholarRoom) {
283283
// Extract ReCAP barcodes from items:
284-
const recapBarcodes = this.extractRecapBarcodes(items)
284+
const recapBarcodes = DeliveryLocationsResolver.extractRecapBarcodes(items)
285285
// Get a map from barcodes to ReCAP customercodes:
286-
return this.__recapCustomerCodesByBarcodes(recapBarcodes)
286+
return DeliveryLocationsResolver.__recapCustomerCodesByBarcodes(recapBarcodes)
287287
.then((barcodeToRecapCustomerCode) => {
288288
// Now map over items to affix deliveryLocations:
289289
return items.map((item) => {
@@ -292,15 +292,15 @@ class DeliveryLocationsResolver {
292292
item.recapCustomerCode = [barcodeToRecapCustomerCode[barcode]]
293293
// If recap has a customer code for this barcode, map it by recap cust code:
294294
if (item.recapCustomerCode[0]) {
295-
item = this.attachRecapDeliveryInfo(item)
295+
item = DeliveryLocationsResolver.attachRecapDeliveryInfo(item)
296296
// Otherwise, it's an onsite item
297297
} else {
298-
item = this.attachOnsiteDeliveryInfo(item)
298+
item = DeliveryLocationsResolver.attachOnsiteDeliveryInfo(item)
299299
}
300300
// Establish default for Electronic Document Delivery flag:
301301
item.eddRequestable = !!item.eddRequestable
302-
const filteredDeliveryLocationsWithScholarRoom = this.filterLocations(item.deliveryLocation, scholarRoom)
303-
item.deliveryLocation = this.formatLocations(filteredDeliveryLocationsWithScholarRoom)
302+
const filteredDeliveryLocationsWithScholarRoom = DeliveryLocationsResolver.filterLocations(item.deliveryLocation, scholarRoom)
303+
item.deliveryLocation = DeliveryLocationsResolver.formatLocations(filteredDeliveryLocationsWithScholarRoom)
304304
return item
305305
})
306306
})

lib/requestability_resolver.js

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,46 +2,57 @@ const DeliveryLocationsResolver = require('./delivery-locations-resolver')
22
const { isItemNyplOwned } = require('./ownership_determination')
33
const { isInRecap } = require('./util')
44
const logger = require('./logger')
5+
56
class RequestabilityResolver {
67
static fixItemRequestability (elasticSearchResponse) {
78
elasticSearchResponse.hits.hits
89
.forEach((hit) => {
10+
const parentBibHasFindingAid = !!hit._source.supplementaryContent?.find((el) => el.label.toLowerCase() === 'finding aid')
911
hit._source.items = hit._source.items.map((item) => {
1012
if (item.electronicLocator) return item
1113
let deliveryInfo
1214
const itemIsInRecap = isInRecap(item)
1315
let physRequestableCriteria
14-
const hasRecapCustomerCode = item.recapCustomerCode && item.recapCustomerCode[0]
16+
const hasRecapCustomerCode = item.recapCustomerCode?.[0]
1517
if (itemIsInRecap) {
1618
// recap items missing codes should default to true for phys and edd
1719
// requestable, unless it has a non-requestable holding location
1820
deliveryInfo = DeliveryLocationsResolver.getRecapDeliveryInfo(item)
1921
physRequestableCriteria = hasRecapCustomerCode
20-
? `${(deliveryInfo.deliveryLocation &&
21-
deliveryInfo.deliveryLocation.length) || 0} delivery locations.`
22+
? `${(deliveryInfo.deliveryLocation?.length) || 0} delivery locations.`
2223
: 'Missing customer code'
2324
} else if (!itemIsInRecap) {
2425
deliveryInfo = DeliveryLocationsResolver.getOnsiteDeliveryInfo(item)
25-
physRequestableCriteria = `${(deliveryInfo.deliveryLocation &&
26-
deliveryInfo.deliveryLocation.length) || 0} delivery locations.`
26+
physRequestableCriteria = `${(deliveryInfo.deliveryLocation?.length) || 0} delivery locations.`
2727
}
28-
item.eddRequestable = !!deliveryInfo.eddRequestable
29-
item.physRequestable = !!(deliveryInfo.deliveryLocation &&
30-
deliveryInfo.deliveryLocation.length)
31-
item.specRequestable = !!item.aeonUrl
28+
item.specRequestable = this.buildSpecRequestable(item, parentBibHasFindingAid)
29+
item.physRequestable = !!deliveryInfo.deliveryLocation?.length
30+
item.eddRequestable = !!deliveryInfo.eddRequestable && !item.specRequestable
3231
// items without barcodes should not be requestable
3332
const hasBarcode = (item.identifier || []).some((identifier) => /^(urn|bf):[bB]arcode:\w+/.test(identifier))
3433
if (isItemNyplOwned(item) && !hasBarcode) {
3534
physRequestableCriteria = 'NYPL item missing barcode'
3635
item.physRequestable = false
3736
}
37+
if (item.specRequestable && item.physRequestable) {
38+
item.physRequestable = false
39+
physRequestableCriteria = 'specRequestable overrides physRequestable location'
40+
}
3841
logger.debug(`item ${item.uri}: `, { physRequestable: item.physRequestable, physRequestableCriteria })
3942
item.requestable = [item.eddRequestable || item.physRequestable || item.specRequestable]
43+
console.log({ specRequestable: item.specRequestable, physRequestable: item.physRequestable, eddRequestable: item.eddRequestable, physRequestableCriteria })
4044
return item
4145
})
4246
})
4347
return elasticSearchResponse
4448
}
49+
50+
static buildSpecRequestable (item, parentBibHasFindingAid) {
51+
const holdingLocation = DeliveryLocationsResolver.extractLocationCode(item)
52+
const nyplCoreLocation = DeliveryLocationsResolver.nyplCoreLocation(holdingLocation)
53+
const isSpecialCollectionsOnlyAccessType = !!(nyplCoreLocation?.collectionAccessType === 'special')
54+
return !!item.aeonUrl || parentBibHasFindingAid || isSpecialCollectionsOnlyAccessType
55+
}
4556
}
4657

4758
module.exports = RequestabilityResolver
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
module.exports = () => {
2+
return {
3+
_shards: {
4+
failed: 0,
5+
successful: 1,
6+
total: 1
7+
},
8+
took: 1,
9+
hits: {
10+
total: 1,
11+
max_score: 1.3862944,
12+
hits: [
13+
{
14+
_id: 'b10980129',
15+
_source: {
16+
supplementaryContent: [{
17+
label: 'Finding aid',
18+
url: 'spaghetti.com'
19+
}],
20+
items: [
21+
{
22+
holdingLocation: [
23+
{
24+
label: 'OFFSITE - Request in Advance',
25+
id: 'loc:rc2ma'
26+
}
27+
],
28+
status_packed: [
29+
'status:na||Not Available'
30+
],
31+
owner: [
32+
{
33+
id: 'orgs:1000',
34+
label: 'Stephen A. Schwarzman Building'
35+
}
36+
],
37+
deliveryLocation: [
38+
{
39+
id: 'loc:mala',
40+
label: 'SASB - Allen Scholar Room'
41+
}
42+
],
43+
deliveryLocation_packed: [
44+
'loc:mala||SASB - Allen Scholar Room'
45+
],
46+
uri: 'i10283664',
47+
accessMessage_packed: [
48+
'accessMessage:2||ADV REQUEST'
49+
],
50+
accessMessage: [
51+
{
52+
id: 'accessMessage:2',
53+
label: 'ADV REQUEST'
54+
}
55+
],
56+
status: [
57+
{
58+
id: 'status:na',
59+
label: 'Not available'
60+
}
61+
],
62+
owner_packed: [
63+
'orgs:1000||Stephen A. Schwarzman Building'
64+
],
65+
requestable: [
66+
false
67+
],
68+
identifier: [
69+
'urn:barcode:1000546836'
70+
],
71+
holdingLocation_packed: [
72+
'loc:rc2ma||OFFSITE - Request in Advance'
73+
],
74+
shelfMark: [
75+
'*OFC 90-2649'
76+
],
77+
suppressed: [
78+
false
79+
]
80+
},
81+
{
82+
holdingLocation: [
83+
{
84+
label: 'OFFSITE - Request in Advance',
85+
id: 'loc:rc2ma'
86+
}
87+
],
88+
status_packed: [
89+
'status:a||Available'
90+
],
91+
owner: [
92+
{
93+
id: 'orgs:1000',
94+
label: 'Stephen A. Schwarzman Building'
95+
}
96+
],
97+
deliveryLocation: [
98+
{
99+
id: 'loc:mala',
100+
label: 'SASB - Allen Scholar Room'
101+
}
102+
],
103+
deliveryLocation_packed: [
104+
'loc:mala||SASB - Allen Scholar Room'
105+
],
106+
uri: 'i102836649',
107+
accessMessage_packed: [
108+
'accessMessage:2||ADV REQUEST'
109+
],
110+
accessMessage: [
111+
{
112+
id: 'accessMessage:2',
113+
label: 'ADV REQUEST'
114+
}
115+
],
116+
status: [
117+
{
118+
id: 'status:a',
119+
label: 'Available'
120+
}
121+
],
122+
owner_packed: [
123+
'orgs:1000||Stephen A. Schwarzman Building'
124+
],
125+
requestable: [
126+
false
127+
],
128+
identifier: [
129+
'urn:barcode:10005468369'
130+
],
131+
holdingLocation_packed: [
132+
'loc:rc2ma||OFFSITE - Request in Advance'
133+
],
134+
shelfMark: [
135+
'*OFC 90-2649 2'
136+
],
137+
suppressed: [
138+
false
139+
]
140+
}
141+
]
142+
143+
},
144+
_type: 'resource',
145+
_index: 'resources-2017-06-13',
146+
_score: 154.93451
147+
}
148+
]
149+
},
150+
timed_out: false
151+
}
152+
}

0 commit comments

Comments
 (0)