Skip to content

Commit 0e9debc

Browse files
committed
Support local IDs for overlay of MARC records.
refs #3555
1 parent e38de3d commit 0e9debc

File tree

18 files changed

+384
-39
lines changed

18 files changed

+384
-39
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
[
2+
{
3+
"@id": "http://localhost:3000/resource/ae93cff4-d272-43b2-a4ee-fb8651907e51",
4+
"@type": [
5+
"http://sinopia.io/vocabulary/LocalAdminMetadata"
6+
],
7+
"http://id.loc.gov/ontologies/bibframe/identifier": [
8+
{
9+
"@id": "_:Nfe4b29df32004cc1b097a218f69df09f"
10+
}
11+
],
12+
"http://sinopia.io/vocabulary/exportDate": [
13+
{
14+
"@value": "2022-08-01T15:49:44.558203"
15+
}
16+
],
17+
"http://sinopia.io/vocabulary/hasResourceTemplate": [
18+
{
19+
"@value": "pcc:sinopia:localAdminMetadata"
20+
}
21+
],
22+
"http://sinopia.io/vocabulary/localAdminMetadataFor": [
23+
{
24+
"@id": "http://localhost:3000/resource/a5c5f4c0-e7cd-4ca5-a20f-2a37fe1080d5"
25+
}
26+
]
27+
},
28+
{
29+
"@id": "_:Nfe4b29df32004cc1b097a218f69df09f",
30+
"@type": [
31+
"http://id.loc.gov/ontologies/bibframe/Local"
32+
],
33+
"http://id.loc.gov/ontologies/bibframe/source": [
34+
{
35+
"@id": "_:Nf65f353d6fb64adeb6aa6040d21fb88c"
36+
}
37+
],
38+
"http://www.w3.org/1999/02/22-rdf-syntax-ns#value": [
39+
{
40+
"@value": "13714202"
41+
}
42+
]
43+
},
44+
{
45+
"@id": "_:Nf65f353d6fb64adeb6aa6040d21fb88c",
46+
"@type": [
47+
"http://id.loc.gov/ontologies/bibframe/Source"
48+
],
49+
"http://www.w3.org/2000/01/rdf-schema#label": [
50+
{
51+
"@value": "SIRSI"
52+
}
53+
]
54+
}
55+
]

__tests__/actionCreators/transfer.test.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@ describe("transfer", () => {
1616
sinopiaApi.postTransfer = jest.fn().mockResolvedValue()
1717
const store = mockStore(createState())
1818
await store.dispatch(
19-
transfer(resourceUri, "stanford", "ils", "testerrorkey")
19+
transfer(resourceUri, "stanford", "ils", "abc123", "testerrorkey")
2020
)
2121

2222
expect(store.getActions()).toHaveLength(0)
2323
expect(sinopiaApi.postTransfer).toHaveBeenCalledWith(
2424
resourceUri,
2525
"stanford",
26-
"ils"
26+
"ils",
27+
"abc123"
2728
)
2829
})
2930
})
@@ -32,7 +33,7 @@ describe("transfer", () => {
3233
sinopiaApi.postTransfer = jest.fn().mockRejectedValue("Ooops!")
3334
const store = mockStore(createState())
3435
await store.dispatch(
35-
transfer(resourceUri, "stanford", "ils", "testerrorkey")
36+
transfer(resourceUri, "stanford", "ils", "abc123", "testerrorkey")
3637
)
3738

3839
expect(store.getActions()).toHaveAction("ADD_ERROR", {

__tests__/feature/editing/transfer.test.js

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jest.spyOn(Config, "transferConfig", "get").mockReturnValue({
2020
},
2121
})
2222

23-
describe("transfer saved bf:Instance when user belongs to a transfer group", () => {
23+
describe("transfer saved bf:Instance when user belongs to a transfer group and no local ID", () => {
2424
it("allows transfer", async () => {
2525
const state = createState()
2626
const store = createStore(state)
@@ -42,6 +42,37 @@ describe("transfer saved bf:Instance when user belongs to a transfer group", ()
4242

4343
const transferBtn = screen.getByText("Export to Catalog")
4444
fireEvent.click(transferBtn)
45+
fireEvent.click(await screen.findByText("Create a new record in catalog."))
46+
await screen.findByText("Requesting")
47+
}, 15000)
48+
})
49+
50+
describe("transfer saved bf:Instance when user belongs to a transfer group and provided local ID", () => {
51+
it("allows transfer", async () => {
52+
const state = createState()
53+
const store = createStore(state)
54+
renderApp(store)
55+
56+
fireEvent.click(screen.getByText("Linked Data Editor", { selector: "a" }))
57+
58+
fireEvent.change(screen.getByLabelText("Search"), {
59+
target: { value: bfUri },
60+
})
61+
fireEvent.click(screen.getByTestId("Submit search"))
62+
63+
await screen.findByText(bfUri)
64+
fireEvent.click(screen.getByRole("button", { name: `Edit ${bfUri}` }))
65+
66+
await screen.findByText("The Practitioner's Guide to Graph Data", {
67+
selector: resourceHeaderSelector,
68+
})
69+
70+
const transferBtn = screen.getByText("Export to Catalog")
71+
fireEvent.click(transferBtn)
72+
fireEvent.change(await screen.findByLabelText("Enter local system id"), {
73+
target: { value: "abc123" },
74+
})
75+
fireEvent.click(await screen.findByText("Go"))
4576
await screen.findByText("Requesting")
4677
}, 15000)
4778
})

__tests__/sinopiaApi.test.js

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -431,13 +431,13 @@ describe("putUserHistory", () => {
431431
})
432432

433433
describe("postTransfer", () => {
434-
describe("success", () => {
434+
describe("success without localId", () => {
435435
it("returns", async () => {
436436
global.fetch = jest.fn().mockResolvedValue({
437437
ok: true,
438438
})
439439

440-
await postTransfer(resourceUri, "stanford", "ils")
440+
await postTransfer(resourceUri, "stanford", "ils", null)
441441

442442
expect(global.fetch).toHaveBeenCalledWith(
443443
"https://api.development.sinopia.io/transfer/7b4c275d-b0c7-40a4-80b3-e95a0d9d987c/stanford/ils",
@@ -450,6 +450,25 @@ describe("postTransfer", () => {
450450
)
451451
})
452452
})
453+
describe("success with localId", () => {
454+
it("returns", async () => {
455+
global.fetch = jest.fn().mockResolvedValue({
456+
ok: true,
457+
})
458+
459+
await postTransfer(resourceUri, "stanford", "ils", "abc123")
460+
461+
expect(global.fetch).toHaveBeenCalledWith(
462+
"https://api.development.sinopia.io/transfer/7b4c275d-b0c7-40a4-80b3-e95a0d9d987c/stanford/ils/abc123",
463+
{
464+
method: "POST",
465+
headers: {
466+
Authorization: "Bearer Secret-Token",
467+
},
468+
}
469+
)
470+
})
471+
})
453472
})
454473

455474
describe("fetchResourceRelationships", () => {

__tests__/testUtilities/fixtureLoaderHelper.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const resourceFilenames = {
1515
"a5c5f4c0-e7cd-4ca5-a20f-2a37fe1080d5": "instance_with_refs.json",
1616
"b6c5f4c0-e7cd-4ca5-a20f-2a37fe1080d6": "test-inputs.json",
1717
"c7c5f4c0-e7cd-4ca5-a20f-2a37fe1080d7": "test-multiple_property_uris.json",
18+
"ae93cff4-d272-43b2-a4ee-fb8651907e51": "local_admin_metadata.json",
1819
}
1920

2021
const templateFilenames = {
@@ -201,5 +202,8 @@ export const getFixtureResourceRelationships = () => {
201202
bfItemInferredRefs: [],
202203
bfInstanceInferredRefs: [],
203204
bfWorkInferredRefs: [],
205+
sinopiaHasLocalAdminMetadataInferredRefs: [
206+
"http://localhost:3000/resource/ae93cff4-d272-43b2-a4ee-fb8651907e51",
207+
],
204208
}
205209
}

src/Config.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,13 +140,19 @@ class Config {
140140

141141
static get transferConfig() {
142142
return {
143-
ils: {
143+
SIRSI: {
144144
// group: label
145-
stanford: "Catalog",
145+
stanford: "Symphony",
146146
cornell: "Catalog",
147+
},
148+
FOLIO: {
149+
stanford: "Folio",
150+
cornell: "Catalog",
151+
},
152+
ALMA: {
147153
penn: "Catalog",
148154
},
149-
// Can add additional transfer targets, e.g., discovery
155+
// Can add additional transfer targets.
150156
}
151157
}
152158

src/actionCreators/relationships.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { fetchResourceRelationships } from "sinopiaApi"
66

77
/**
88
* A thunk that loads inferred relationships from the Sinopia API and adds to state.
9-
* @return true if successful
9+
* @return relationships if successful or false if not
1010
*/
1111
export const loadRelationships = (resourceKey, uri, errorKey) => (dispatch) => {
1212
dispatch(clearErrors(errorKey))
@@ -15,12 +15,14 @@ export const loadRelationships = (resourceKey, uri, errorKey) => (dispatch) => {
1515
dispatch(
1616
setRelationships(resourceKey, {
1717
bfAdminMetadataRefs: relationships.bfAdminMetadataInferredRefs,
18+
sinopiaLocalAdminMetadataRefs:
19+
relationships.sinopiaHasLocalAdminMetadataInferredRefs,
1820
bfItemRefs: relationships.bfItemInferredRefs,
1921
bfInstanceRefs: relationships.bfInstanceInferredRefs,
2022
bfWorkRefs: relationships.bfWorkInferredRefs,
2123
})
2224
)
23-
return true
25+
return relationships
2426
})
2527
.catch((err) => {
2628
console.error(err)

src/actionCreators/resources.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import { addResourceHistory } from "actionCreators/history"
4141
import _ from "lodash"
4242
import { setCurrentComponent } from "actions/index"
4343
import { loadRelationships } from "./relationships"
44+
import { loadLocalIds } from "./transfer"
4445

4546
/**
4647
* A thunk that loads an existing resource from Sinopia API and adds to state.
@@ -72,7 +73,19 @@ export const loadResource =
7273
unusedDataset.size > 0 ? unusedDataset.toCanonical() : null
7374
)
7475
)
75-
dispatch(loadRelationships(resource.key, uri, errorKey))
76+
dispatch(loadRelationships(resource.key, uri, errorKey)).then(
77+
(relationships) => {
78+
if (relationships) {
79+
dispatch(
80+
loadLocalIds(
81+
resource.key,
82+
relationships.sinopiaHasLocalAdminMetadataInferredRefs,
83+
errorKey
84+
)
85+
)
86+
}
87+
}
88+
)
7689
return [response, resource, unusedDataset]
7790
})
7891
.catch((err) => {

src/actionCreators/transfer.js

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,75 @@
1-
import { postTransfer } from "../sinopiaApi"
1+
import { postTransfer, fetchResource } from "../sinopiaApi"
22
import { addError } from "actions/errors"
3+
import { clearLocalIds, setLocalId } from "actions/transfer"
4+
import rdf from "rdf-ext"
35

46
export const transfer =
5-
(resourceUri, group, target, errorKey) => (dispatch) => {
6-
postTransfer(resourceUri, group, target).catch((err) => {
7+
(resourceUri, group, target, localId, errorKey) => (dispatch) =>
8+
postTransfer(resourceUri, group, target, localId).catch((err) => {
79
dispatch(
810
addError(errorKey, `Error requesting transfer: ${err.message || err}`)
911
)
1012
})
13+
14+
export const loadLocalIds =
15+
(resourceKey, sinopiaLocalAdminMetadataRefs, errorKey) => (dispatch) => {
16+
dispatch(clearLocalIds(resourceKey))
17+
sinopiaLocalAdminMetadataRefs.forEach((resourceUri) => {
18+
dispatch(fetchLocalId(resourceUri, errorKey)).then(
19+
([target, group, localId]) => {
20+
if (!target) {
21+
return
22+
}
23+
dispatch(setLocalId(resourceKey, target, group, localId))
24+
}
25+
)
26+
})
1127
}
1228

13-
export const noop = () => {}
29+
const fetchLocalId = (uri, errorKey) => (dispatch) =>
30+
fetchResource(uri)
31+
.then(([dataset, response]) => {
32+
if (!dataset) return [false, false, false]
33+
const identifierNode = identifierNodeFromDataset(uri, dataset)
34+
if (!identifierNode) return [false, false, false]
35+
const localId = localIdFromIdentifierNode(identifierNode, dataset)
36+
const target = targetFromIdentifierNode(identifierNode, dataset)
37+
return [target, response.group, localId]
38+
})
39+
.catch((err) => {
40+
dispatch(
41+
addError(errorKey, `Error retrieving ${uri}: ${err.message || err}`)
42+
)
43+
return [false, false, false]
44+
})
45+
46+
const localIdFromIdentifierNode = (identifierNode, dataset) =>
47+
dataset
48+
.match(
49+
identifierNode,
50+
rdf.namedNode("http://www.w3.org/1999/02/22-rdf-syntax-ns#value")
51+
)
52+
.toArray()[0].object.value
53+
54+
const targetFromIdentifierNode = (identifierNode, dataset) => {
55+
const sourceNode = dataset
56+
.match(
57+
identifierNode,
58+
rdf.namedNode("http://id.loc.gov/ontologies/bibframe/source")
59+
)
60+
.toArray()[0].object
61+
return dataset
62+
.match(
63+
sourceNode,
64+
rdf.namedNode("http://www.w3.org/2000/01/rdf-schema#label")
65+
)
66+
.toArray()[0].object.value
67+
}
68+
69+
const identifierNodeFromDataset = (uri, dataset) =>
70+
dataset
71+
.match(
72+
rdf.namedNode(uri),
73+
rdf.namedNode("http://id.loc.gov/ontologies/bibframe/identifier")
74+
)
75+
.toArray()[0].object

src/actions/transfer.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export const clearLocalIds = (resourceKey) => ({
2+
type: "CLEAR_LOCAL_IDS",
3+
payload: resourceKey,
4+
})
5+
6+
export const setLocalId = (resourceKey, target, group, localId) => ({
7+
type: "SET_LOCAL_ID",
8+
payload: { resourceKey, target, group, localId },
9+
})

0 commit comments

Comments
 (0)