Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
136 commits
Select commit Hold shift + click to select a range
8f91050
Merge pull request #469 from NYPL/qa
charmingduchess Apr 3, 2025
81f1cd6
Merge pull request #474 from NYPL/qa
charmingduchess Apr 7, 2025
6b80c68
Merge pull request #479 from NYPL/qa
charmingduchess Apr 21, 2025
9ce9279
Merge pull request #488 from NYPL/main
danamansana May 21, 2025
cd77f64
Merge pull request #495 from NYPL/main
charmingduchess Jun 5, 2025
0db738a
Merge pull request #501 from NYPL/qa
danamansana Jun 16, 2025
a4497ba
Merge pull request #504 from NYPL/main
yossariano Jun 26, 2025
8fb5fae
Merge branch 'main' into production
nonword Jul 17, 2025
23f299b
Merge pull request #525 from NYPL/main
danamansana Aug 12, 2025
712bed2
Merge pull request #543 from NYPL/qa
nonword Sep 16, 2025
c4621dc
Merge branch 'qa' into production
nonword Sep 17, 2025
dc96175
Merge pull request #555 from NYPL/main
charmingduchess Sep 24, 2025
c702b91
rm test property
charmingduchess Sep 24, 2025
2a1ff64
Merge branch 'main' into qa
7emansell Oct 2, 2025
dbc251f
Merge pull request #559 from NYPL/main
danamansana Oct 6, 2025
217d876
bump to nypl-core 2.34
7emansell Oct 8, 2025
315133e
Replace wrong cased formats
7emansell Oct 8, 2025
5ec7e2d
Merge pull request #561 from NYPL/qa
charmingduchess Oct 8, 2025
265093d
Merge branch 'main' into qa
yossariano Oct 9, 2025
8c6352e
Merge pull request #566 from NYPL/main
yossariano Oct 10, 2025
e5bc2ce
Merge branch 'main' into qa
7emansell Oct 16, 2025
db3b9d2
Merge pull request #570 from NYPL/main
danamansana Oct 17, 2025
bd0abd4
Merge branch 'main' into qa
7emansell Oct 17, 2025
10ffa1f
Merge pull request #574 from NYPL/main
charmingduchess Oct 24, 2025
ecd309d
Merge pull request #577 from NYPL/main
yossariano Oct 30, 2025
c412c3a
Merge pull request #578 from NYPL/main
danamansana Oct 30, 2025
9b076da
Remove schomburg edd
danamansana Oct 31, 2025
0ef2b32
Fix broken tests
nonword Oct 31, 2025
a33792c
Merge pull request #582 from NYPL/HOTFIX/remove-schomburg-button
danamansana Oct 31, 2025
0e082b9
Merge pull request #585 from NYPL/main
yossariano Nov 4, 2025
c4f0355
Merge branch 'main' into qa
7emansell Nov 4, 2025
6d52047
Merge pull request #588 from NYPL/main
danamansana Nov 14, 2025
3cc90b1
Merge pull request #590 from NYPL/main
danamansana Nov 17, 2025
fdbb3c3
Merge pull request #591 from NYPL/main
danamansana Nov 18, 2025
1caf235
Merge branch 'main' into qa
nonword Nov 21, 2025
fe1f31f
Add null checks to address common errors
yossariano Dec 2, 2025
9dd4aeb
Update lib/jsonld_serializers.js
yossariano Dec 2, 2025
06f1ca1
Merge pull request #595 from NYPL/SCC-5041-fix-alarm-noise
yossariano Dec 2, 2025
61c1ef6
Throw error in case of decryption failure
danamansana Dec 4, 2025
c7d3fa7
decrease inputs on buildphysrequetsable
charmingduchess Dec 10, 2025
0ac6279
move requestability to item model
charmingduchess Dec 10, 2025
fd67e54
start location model and move edd to one place
charmingduchess Dec 10, 2025
88e94bd
item model correctly returns edd values
charmingduchess Dec 10, 2025
2a38583
Merge pull request #596 from NYPL/scc-4908
danamansana Dec 11, 2025
7219094
Merge pull request #598 from NYPL/main
danamansana Dec 11, 2025
c63162b
Update packages, enable sso for local dev
nonword Dec 15, 2025
5e06ae7
Revert scsb-client debugging code
nonword Dec 15, 2025
853881d
Merge pull request #599 from NYPL/NOREF-sso-and-package-updates
nonword Dec 16, 2025
e651002
Bump fast-xml-parser and @aws-sdk/client-cloudwatch-logs in /logs-to-tsv
dependabot[bot] Dec 16, 2025
6e66206
Bones of browse/contributors
yossariano Dec 16, 2025
53c0245
start location model tests
charmingduchess Dec 17, 2025
63ecd38
fix recap check
charmingduchess Dec 17, 2025
657061e
fix recap check
charmingduchess Dec 17, 2025
579e5b9
fix recap check
charmingduchess Dec 17, 2025
c278a12
fix some edd biz
charmingduchess Dec 17, 2025
c44e000
fix some edd biz
charmingduchess Dec 17, 2025
89c674d
mock scsb client fixes tests
charmingduchess Dec 17, 2025
65c9aa4
mock scsb client fixes tests
charmingduchess Dec 17, 2025
553c316
all tests passing!!!
charmingduchess Dec 17, 2025
9fa6cde
file capitalizaiton fix
charmingduchess Dec 17, 2025
f05da86
make item factory
charmingduchess Dec 18, 2025
e78345f
make item factory
charmingduchess Dec 18, 2025
8564c5b
replace attach tests with item model tests
charmingduchess Dec 19, 2025
7fab45a
rm extra barcode munger
charmingduchess Dec 19, 2025
92d1468
add and rms
charmingduchess Dec 19, 2025
986a9a0
formatting
charmingduchess Dec 19, 2025
45759f6
rm requestability resolver class
charmingduchess Dec 19, 2025
525a622
fix instance variable access
charmingduchess Dec 19, 2025
6727716
rm console.log
charmingduchess Dec 19, 2025
e82d42e
only fetch recap data for recap items
charmingduchess Dec 19, 2025
d1f27ba
rm duplicated logic
charmingduchess Dec 19, 2025
9c15cbd
test holding location requestability
charmingduchess Dec 19, 2025
351d775
rm more from old delivery locations resolver
charmingduchess Dec 19, 2025
643605f
rm unused
charmingduchess Dec 29, 2025
1b60095
mid
7emansell Dec 29, 2025
fd6a1dd
rename file
charmingduchess Dec 29, 2025
d056e5e
Cant test first try
7emansell Dec 29, 2025
56adb1a
Progress but can't test properly yet
7emansell Dec 30, 2025
51a71bf
sort
7emansell Dec 30, 2025
e17ec22
Unit tests
7emansell Dec 30, 2025
a999561
correct test syntax to run on GH
7emansell Dec 30, 2025
dbfbce2
update dependencies
charmingduchess Dec 30, 2025
b60340c
Fighting marc serializer unit test demons
7emansell Jan 5, 2026
5ba17c6
clean up
7emansell Jan 5, 2026
a3e86b0
more clean up
7emansell Jan 5, 2026
393cbed
Plus tests
7emansell Jan 5, 2026
90a50f3
Pass control fields through
7emansell Jan 5, 2026
145a2cd
Remove sorting i reconsidered
7emansell Jan 6, 2026
3ebf6a1
test
7emansell Jan 6, 2026
748a08f
Support multi-word prefixes in "containing" search
yossariano Jan 6, 2026
093fa68
Merge pull request #609 from NYPL/SCC-5009/package-updates
charmingduchess Jan 6, 2026
b6e22c7
Merge pull request #612 from NYPL/main
charmingduchess Jan 6, 2026
a740a69
Bump qs from 6.13.0 to 6.14.1
dependabot[bot] Jan 6, 2026
1e41ca3
rm unused method
charmingduchess Jan 6, 2026
48787bb
Ensure ordering works properly
yossariano Jan 6, 2026
9727568
Remove duplicate prefix query clause
yossariano Jan 6, 2026
61b57eb
break down findParallelFields into readable chunks, rename suppressed…
7emansell Jan 6, 2026
5fab6ae
Merge pull request #605 from NYPL/SCC-3733/refactor-delivery
charmingduchess Jan 6, 2026
ded58a3
merge qa
charmingduchess Jan 6, 2026
5e897c0
fix tests
charmingduchess Jan 6, 2026
8341e88
Merge pull request #610 from NYPL/dependabot/npm_and_yarn/qs-6.14.1
charmingduchess Jan 6, 2026
a60b0dc
Removing subfields instead of writing them as "redacted"
7emansell Jan 7, 2026
f65bcba
New marc rules
7emansell Jan 14, 2026
f5a77cc
ignore field tag if it's not in rule for matching
7emansell Jan 14, 2026
8448d5b
Fix check for missing deliverable-to-resolution
nonword Jan 14, 2026
4b23e33
Merge pull request #618 from NYPL/NOREF-fix-deliverable-to-recap-fall…
nonword Jan 14, 2026
e831cc8
Merge pull request #608 from NYPL/SCC-5105/marc-endpoint
7emansell Jan 14, 2026
35eb47c
Simplify stemming solution
yossariano Jan 15, 2026
567838b
Just use a new index with a edge ngram tokenizer
yossariano Jan 15, 2026
80b920e
no-op change to force github state sync
yossariano Jan 15, 2026
13afccf
Add dependabot.yml
nonword Jan 20, 2026
1391abf
Move dependabot.yml
nonword Jan 20, 2026
b53042d
Merge pull request #611 from NYPL/SCC-5059-contains-stemming
yossariano Jan 22, 2026
a264e50
Merge branch 'main' into SCC-4987-author-browse-endpoint
yossariano Jan 27, 2026
3a8f0ff
Merge pull request #621 from NYPL/SCC-5146-add-dependabot-yml
nonword Jan 29, 2026
13e9aff
Update for contributor browse
yossariano Feb 2, 2026
a1cad1f
update resources index
charmingduchess Feb 4, 2026
28125f2
start test and script
charmingduchess Feb 4, 2026
f76142b
wip: framework works, expectations not correct
charmingduchess Feb 4, 2026
6183444
Merge pull request #631 from NYPL/SCC-5130/resources-index
charmingduchess Feb 4, 2026
0863a6e
fix resources config
charmingduchess Feb 4, 2026
652ebf6
Merge pull request #633 from NYPL/SCC-5130/resources-index
charmingduchess Feb 4, 2026
f37a59a
fix resources index again
charmingduchess Feb 4, 2026
9fc93c2
test file
charmingduchess Feb 4, 2026
740467d
tests extend to general and excludes
charmingduchess Feb 5, 2026
a26551b
remove log
yossariano Feb 5, 2026
06cdaaf
Merge branch 'main' into SCC-4987-author-browse-endpoint
yossariano Feb 5, 2026
63ec0a7
Merge pull request #603 from NYPL/SCC-4987-author-browse-endpoint
yossariano Feb 5, 2026
27a9a72
fix config conflict
yossariano Feb 5, 2026
7f9c5b2
it does the thing
charmingduchess Feb 5, 2026
3cdafd0
Merge pull request #635 from NYPL/NOREF-fix-config-conflict
yossariano Feb 5, 2026
9e36b07
move constants out
charmingduchess Feb 6, 2026
8de8311
little refactor
charmingduchess Feb 6, 2026
439adf0
update gha script
charmingduchess Feb 6, 2026
63ce462
integration on qa2
charmingduchess Feb 6, 2026
dabcabe
Merge pull request #636 from NYPL/SC-5164/delivery-inegration-test
charmingduchess Feb 6, 2026
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
10 changes: 10 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
27 changes: 24 additions & 3 deletions .github/workflows/test-and-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,33 @@ jobs:
run: npm ci
- name: Unit Tests
run: npm test
deploy-qa:
integration-test-qa:
permissions:
id-token: write
contents: read
runs-on: ubuntu-latest
needs: tests
if: github.ref == 'refs/heads/qa'
steps:
- uses: actions/checkout@v4
- name: Set Node version
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
- name: Install dependencies
run: npm ci
- name: Start service
run: ENV=qa npm start &
- name: Run tests
run: npm run test-integration
deploy-qa:
permissions:
id-token: write
contents: read
runs-on: ubuntu-latest
needs:
- tests
if: github.ref == 'refs/heads/qa'
steps:
- name: Checkout repo
uses: actions/checkout@v3
Expand All @@ -31,7 +51,6 @@ jobs:
with:
role-to-assume: arn:aws:iam::946183545209:role/GithubActionsDeployerRole
aws-region: us-east-1

- name: Log in to ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
Expand Down Expand Up @@ -60,7 +79,9 @@ jobs:
id-token: write
contents: read
runs-on: ubuntu-latest
needs: tests
needs:
- tests
- inte
if: github.ref == 'refs/heads/qa2'
steps:
- name: Checkout repo
Expand Down
1 change: 1 addition & 0 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ app.init = async () => {

require('./lib/resources')(app)
require('./lib/subjects')(app)
require('./lib/contributors')(app)
require('./lib/vocabularies')(app)

// routes
Expand Down
5 changes: 3 additions & 2 deletions config/qa.env
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
ENCRYPTED_ELASTICSEARCH_URI=AQECAHh7ea2tyZ6phZgT4B9BDKwguhlFtRC6hgt+7HbmeFsrsgAAAJYwgZMGCSqGSIb3DQEHBqCBhTCBggIBADB9BgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDMIkDoQ9C/cCDCAq1wIBEIBQ+L3OgUGeOW9rs1CWkhpBjwM4LbbVRFIWedqew4UXIeSNMJ8cO9SNe4YGCUIoKwCDYt7W7ip3VtDRRRMVvz6QJw+Eg8ugTMVs2pbNFGNvaAQ=
RESOURCES_INDEX=resources-2025-07-07
SUBJECTS_INDEX=browse-qa-2025-10-27

ENCRYPTED_RESOURCES_INDEX=AQECAHh7ea2tyZ6phZgT4B9BDKwguhlFtRC6hgt+7HbmeFsrsgAAAHIwcAYJKoZIhvcNAQcGoGMwYQIBADBcBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDPMBVNbSFDq16QAs4AIBEIAvHrJZjGewR7g4oT5oifQUDGTj2SgYibnrhU05uBatHEVYz/mOawAVrjt/1oxPqv4=
BROWSE_INDEX=browse-qa-2026-01-15
ENCRYPTED_ELASTICSEARCH_API_KEY=AQECAHh7ea2tyZ6phZgT4B9BDKwguhlFtRC6hgt+7HbmeFsrsgAAAJ4wgZsGCSqGSIb3DQEHBqCBjTCBigIBADCBhAYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAx+kryf2KUmGdBYD9sCARCAV3ygz3eXIdq8JX/wpG9JRWlTNMRcpNE1qT0zNlN4t+ZvXEoedLQa/3p1YjgHw06GIAdA9xtkMV4eH9a1K8uCvjP8XxxNKekcMj59TlResnu9QF3r7pGXuQ==

ENCRYPTED_SCSB_URL=AQECAHh7ea2tyZ6phZgT4B9BDKwguhlFtRC6hgt+7HbmeFsrsgAAAH8wfQYJKoZIhvcNAQcGoHAwbgIBADBpBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDBKllElmWYLxGOGopQIBEIA8JJyKde/8m8iCJGKR5D8HoTJhXHeyvw9eIDeuUNKiXLfJwoVz+PDAZSxkCQtM9O91zGhXbe3l6Bk1RlYJ
Expand Down
4 changes: 2 additions & 2 deletions config/test.env
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
ELASTICSEARCH_URI=encrypted-elasticsearch-uri
RESOURCES_INDEX=test-resources-index
SUBJECTS_INDEX=test-subjects-index
BROWSE_INDEX=test-browse-index

SCSB_URL=encrypted-scsb-url
SCSB_API_KEY=encrypted-scsb-api-key
Expand All @@ -10,7 +10,7 @@ NYPL_OAUTH_URL=http://oauth.example.com
NYPL_OAUTH_ID=encrypted-nypl-oauth-id
NYPL_OAUTH_SECRET=encrypted-nypl-oauth-id

NYPL_CORE_VERSION=v2.35
NYPL_CORE_VERSION=v2.37

LOG_LEVEL=error
FEATURES=on-site-edd
Expand Down
62 changes: 62 additions & 0 deletions data/marc-rules.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
[
{
"marcIndicatorRegExp": "3610 ",
"subfieldSpec": { "subfields": [], "directive": "include" },
"label": "",
"directive": "exclude"
},
{
"marcIndicatorRegExp": "365..",
"subfieldSpec": { "subfields": [], "directive": "include" },
"label": "",
"directive": "exclude"
},
{
"marcIndicatorRegExp": "5410.",
"subfieldSpec": { "subfields": [], "directive": "include" },
"label": "",
"directive": "exclude"
},
{
"marcIndicatorRegExp": "541 .",
"subfieldSpec": { "subfields": [], "directive": "include" },
"label": "",
"directive": "exclude"
},
{
"marcIndicatorRegExp": "5420 ",
"subfieldSpec": { "subfields": [], "directive": "include" },
"label": "",
"directive": "exclude"
},
{
"marcIndicatorRegExp": "5610.",
"subfieldSpec": { "subfields": [], "directive": "include" },
"label": "",
"directive": "exclude"
},
{
"marcIndicatorRegExp": "561 .",
"subfieldSpec": { "subfields": [], "directive": "include" },
"label": "",
"directive": "exclude"
},
{
"marcIndicatorRegExp": "5830.",
"subfieldSpec": { "subfields": [], "directive": "include" },
"label": "",
"directive": "exclude"
},
{
"marcIndicatorRegExp": "583 .",
"subfieldSpec": { "subfields": [], "directive": "include" },
"label": "",
"directive": "exclude"
},
{
"marcIndicatorRegExp": "5900.",
"subfieldSpec": { "subfields": [], "directive": "include" },
"label": "",
"directive": "exclude"
}
]
5 changes: 1 addition & 4 deletions data/onsite-edd-criteria.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,6 @@
"par",
"pat",
"pat22",
"pat32",
"scf",
"scff2",
"scff3"
"pat32"
]
}
26 changes: 4 additions & 22 deletions lib/annotated-marc-serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

const arrayUnique = require('./util').arrayUnique
const relatorMappings = require('../data/relator-mappings.json')
const { varFieldMatches, buildSourceWithMasking } = require('./marc-util')

class AnnotatedMarcSerializer {
}
Expand Down Expand Up @@ -133,32 +134,13 @@ AnnotatedMarcSerializer.matchingMarcFields = function (bib, rule) {
*
* @return {boolean}
*/
AnnotatedMarcSerializer.varFieldMatches = function (field, rule) {
const fieldMarcIndicator = `${field.marcTag}${field.ind1 || ' '}${field.ind2 || ' '}`
return rule.marcIndicatorRegExp.test(fieldMarcIndicator) &&
rule.fieldTag === field.fieldTag
}
AnnotatedMarcSerializer.varFieldMatches = varFieldMatches

/**
* Given a varField, returns a copy with any hidden subfield content replaced
* with "[redacted]" based on given rule
*/
AnnotatedMarcSerializer.buildSourceWithMasking = function (field, rule) {
return Object.assign({}, field, {
subfields: (field.subfields || [])
.map((subfield) => {
let subfieldContent = subfield.content
// If directive is 'include' and subfield not included
// .. or directive is 'exclude', but subfield included,
// [redact] it:
if ((rule.subfieldSpec.directive === 'include' && rule.subfieldSpec.subfields.indexOf(subfield.tag) < 0) ||
(rule.subfieldSpec.directive === 'exclude' && rule.subfieldSpec.subfields.indexOf(subfield.tag) >= 0)) {
subfieldContent = '[redacted]'
}
return Object.assign({}, subfield, { content: subfieldContent })
})
})
}
AnnotatedMarcSerializer.buildSourceWithMasking = buildSourceWithMasking

/**
* Get prefix for a marctag & subfield, given a previous subfield (if avail.)
Expand Down Expand Up @@ -322,7 +304,7 @@ AnnotatedMarcSerializer.addStatementsForVarFieldForRule = function (doc, bib, va
.pop()
}
})
.filter((parallel) => parallelNumbers.some((parallelNumber) => parallel.linkingValue.indexOf(parallelNumber) === 4))
.filter((parallel) => parallelNumbers.some((parallelNumber) => parallel.linkingValue?.indexOf(parallelNumber) === 4))
.map((parallel) => parallel.field)

if (matchingParallels.length > 0) {
Expand Down
19 changes: 3 additions & 16 deletions lib/availability_resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const logger = require('./logger')
const ResourceSerializer = require('./jsonld_serializers').ResourceSerializer
const NyplSourceMapper = require('research-catalog-indexer/lib/utils/nypl-source-mapper')
const { nonRecapItemStatusAggregation } = require('./elasticsearch/client')
const { deepValue, isInRecap } = require('./util')
const { deepValue, isInRecap, barcodeFromItem } = require('./util')

const ITEM_STATUSES = {
available: {
Expand Down Expand Up @@ -264,7 +264,7 @@ class AvailabilityResolver {
const item = this.elasticSearchResponse.hits.hits[0]._source.items[0]
// If it's an electronic item or a non-recap item, skip it
if (item.electronicLocator || !isInRecap(item)) return Promise.resolve()
const barcode = this._getItemBarcode(item)
const barcode = barcodeFromItem(item)
if (!barcode) return Promise.resolve()

return scsbClient.recapCustomerCodeByBarcode(barcode)
Expand Down Expand Up @@ -292,7 +292,7 @@ class AvailabilityResolver {
// Only need to calculate recap item availability because nypl-owned records
// status is updated elsewhere.
if (_isInRecap) {
const barcode = this._getItemBarcode(item)
const barcode = barcodeFromItem(item)
const recapAvailabilityStatus = barcodesAndAvailability[barcode]
if (recapAvailabilityStatus === 'Available') {
item.status[0].id = ITEM_STATUSES.available.id
Expand All @@ -310,19 +310,6 @@ class AvailabilityResolver {
})
}
}

_getItemBarcode (item) {
// TODO: This is an awkward use of .reduce. Should prob use .find
return (item.identifier || []).reduce((_, identifier) => {
// Rolling forward, some identifiers will be serialized as entities.
// For now, let's convert them back to urn-style:
identifier = ResourceSerializer.prototype._ensureIdentifierIsUrnStyle(identifier)
if (identifier.split(':').length === 3 && identifier.split(':')[1] === 'barcode') {
return identifier.split(':')[2]
}
return null
}, null)
}
} // end class

module.exports = AvailabilityResolver
121 changes: 121 additions & 0 deletions lib/contributors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
const { parseBrowseParams } = require('./elasticsearch/browse-utils')

const ApiRequest = require('./api-request')
const ElasticQueryBrowseBuilder = require('./elasticsearch/elastic-query-browse-builder')

const BROWSE_INDEX = process.env.BROWSE_INDEX

const parseNameAndRole = (delimitedString) => {
if (!delimitedString.includes('|')) {
return { name: delimitedString, role: null }
}
const [name, role] = delimitedString.split('|')
return { name, role }
}

module.exports = function (app, _private = null) {
app.contributors = {}

app.contributors.browse = function (params, opts, request) {
app.logger.debug('Unparsed params: ', params)
params = parseBrowseParams(params)

app.logger.debug('Parsed params: ', params)

const body = buildElasticContributorsBody(params)

app.logger.debug('Contrbutors#browse', BROWSE_INDEX, body)

return app.esClient.search(body, process.env.BROWSE_INDEX)
.then((resp) => {
return {
'@type': 'contributorList',
page: params.page,
per_page: params.per_page,
totalResults: resp.hits?.total?.value,
contributors: resp.hits?.hits?.reduce((workingResponse, hit) => {
if (hit.matched_queries?.[0] === 'preferredTerm' || hit.matched_queries?.[0] === 'preferredTermPrefix') { // if match is on preferredTerm, use that regardless of variant matches
const { name, role } = parseNameAndRole(hit._source.preferredTerm)

let contributorData = workingResponse.find(item => item.termLabel === name)

if (!contributorData) {
contributorData = {
'@type': 'preferredTerm',
termLabel: name
}
workingResponse.push(contributorData)
}

if (role) {
// just add the role count to the top level response
const roleCount = { role, count: hit._source.count }
if (!contributorData.roleCounts) {
contributorData.roleCounts = []
}
contributorData.roleCounts.push(roleCount)
} else {
// top-level contributor object
contributorData.count = hit._source.count
contributorData.broaderTerms = hit._source.broaderTerms?.map((term) => ({ termLabel: term }))
contributorData.narrowerTerms = hit._source.narrowerTerms?.map((term) => ({ termLabel: term }))
contributorData.seeAlso = hit._source.seeAlso?.map((term) => ({ termLabel: term }))
contributorData.uri = hit._source.uri
}
} else {
// Match was on a variant- use that in the response
const matchedVariantTerm = hit.inner_hits.variants.hits.hits[0]._source.variant

const variantData = {
'@type': 'variant',
termLabel: matchedVariantTerm,
preferredTerms: [
{
termLabel: hit._source.preferredTerm,
count: hit._source.count
}
]
}

workingResponse.push(variantData)
}

return workingResponse
}, [])
}
})
}

// For unit testing
if (_private && typeof _private === 'object') {
_private.buildElasticContributorsBody = buildElasticContributorsBody
_private.parseBrowseParams = parseBrowseParams
}
}

/**
* Given GET params, returns a plainobject with `from`, `size`, `query`,
* `sort`, and any other params necessary to perform the ES query based
* on the GET params.
*
* @return {object} An object that can be posted directly to ES
*/
const buildElasticContributorsBody = function (params) {
const body = {
from: (params.per_page * (params.page - 1)),
size: params.per_page
}

const request = ApiRequest.fromParams(params)
const builder = ElasticQueryBrowseBuilder.forApiRequest(request)

body.query = builder.query.toJson()

// match only termType 'contributor'
body.query.bool.must.push({ term: { termType: { value: 'contributor' } } })

// Exclude items that have count == 0
body.query.bool.must.push({ range: { count: { gt: 0 } } })

return body
}
Loading