Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 2 additions & 2 deletions api/dependencies/package-lock.json

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

2 changes: 1 addition & 1 deletion api/dependencies/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dc-api-dependencies",
"version": "2.9.0",
"version": "2.9.1",
"description": "NUL Digital Collections API Dependencies",
"repository": "https://github.com/nulib/dc-api-v2",
"author": "nulib",
Expand Down
4 changes: 2 additions & 2 deletions api/package-lock.json

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

2 changes: 1 addition & 1 deletion api/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dc-api-build",
"version": "2.9.0",
"version": "2.9.1",
"description": "NUL Digital Collections API Build Environment",
"repository": "https://github.com/nulib/dc-api-v2",
"author": "nulib",
Expand Down
50 changes: 50 additions & 0 deletions api/src/api/opensearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,55 @@ async function getSharedLink(id, opts) {
return getDocument("shared_links", id, opts);
}

async function getWorkFileSets(workId, opts = {}) {
Honeybadger.addBreadcrumb("Retrieving work file sets", {
metadata: { workId },
});

const {
allowPrivate = false,
allowUnpublished = false,
role = null,
source = null,
} = opts;

const visibilityFilters = [];
if (!allowPrivate) {
visibilityFilters.push({
bool: {
should: [
{ term: { visibility: "Public" } },
{ term: { visibility: "Institution" } },
],
},
});
}
if (!allowUnpublished) {
visibilityFilters.push({ term: { published: true } });
}

const mustClauses = [{ term: { work_id: workId } }];
if (role) {
mustClauses.push({ term: { role: role } });
}

const searchBody = {
size: 10000,
query: {
bool: {
must: mustClauses,
filter: visibilityFilters,
},
},
};

if (source) {
searchBody._source = source;
}

return await search(prefix("dc-v2-file-set"), JSON.stringify(searchBody));
}

async function getDocument(index, id, opts = {}) {
Honeybadger.addBreadcrumb("Retrieving document", { metadata: { index, id } });
const request = initRequest(`/${prefix(index)}/_doc/${id}`);
Expand Down Expand Up @@ -133,6 +182,7 @@ module.exports = {
getFileSet,
getSharedLink,
getWork,
getWorkFileSets,
search,
scroll,
deleteScroll,
Expand Down
48 changes: 23 additions & 25 deletions api/src/api/response/iiif/manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const {
openSearchEndpoint,
} = require("../../../environment");
const { transformError } = require("../error");
const { getFileSet } = require("../../opensearch");
const { getWorkFileSets } = require("../../opensearch");
const {
addSupplementingAnnotationToCanvas,
addTranscriptionAnnotationsToCanvas,
Expand Down Expand Up @@ -396,33 +396,31 @@ async function fetchFileSetTranscriptions(source, options) {
if (source.work_type !== "Image") return {};
if (!openSearchEndpoint()) return {};

const candidates = (source.file_sets || []).filter(
(file_set) => file_set.role === "Access" && file_set.id
);

const allowPrivate = options.allowPrivate || false;
const allowUnpublished = options.allowUnpublished || false;

const results = await Promise.all(
candidates.map(async (file_set) => {
const response = await getFileSet(file_set.id, {
allowPrivate,
allowUnpublished,
});
if (response.statusCode !== 200) return null;
const body = JSON.parse(response.body);
const annotations =
body?._source?.annotations?.filter(
(annotation) => annotation.type === "transcription"
) || [];
if (annotations.length === 0) return null;
return { id: file_set.id, annotations };
})
);

return results
.filter(Boolean)
.reduce((acc, { id, annotations }) => ({ ...acc, [id]: annotations }), {});
const response = await getWorkFileSets(source.id, {
allowPrivate,
allowUnpublished,
role: "Access",
source: ["id", "annotations"],
});

if (response.statusCode !== 200) return {};

const body = JSON.parse(response.body);
const hits = body?.hits?.hits || [];

return hits.reduce((acc, hit) => {
const fileSetId = hit._source?.id;
const annotations = (hit._source?.annotations || []).filter(
(annotation) => annotation.type === "transcription"
);
if (fileSetId && annotations.length > 0) {
acc[fileSetId] = annotations;
}
return acc;
}, {});
}

function getTranscriptionContent(annotation = {}) {
Expand Down
4 changes: 2 additions & 2 deletions api/src/package-lock.json

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

2 changes: 1 addition & 1 deletion api/src/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dc-api",
"version": "2.9.0",
"version": "2.9.1",
"description": "NUL Digital Collections API",
"repository": "https://github.com/nulib/dc-api-v2",
"author": "nulib",
Expand Down
33 changes: 33 additions & 0 deletions api/test/fixtures/mocks/work-file-sets-access.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "dc-v2-file-set",
"_type": "_doc",
"_id": "fileset-access-1",
"_score": 1.0,
"_source": {
"id": "fileset-access-1",
"api_model": "FileSet",
"work_id": "work-123",
"role": "Access",
"visibility": "Public",
"published": true
}
}
]
}
}
47 changes: 47 additions & 0 deletions api/test/fixtures/mocks/work-file-sets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"took": 3,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "dc-v2-file-set",
"_type": "_doc",
"_id": "fileset-1",
"_score": 1.0,
"_source": {
"id": "fileset-1",
"api_model": "FileSet",
"work_id": "work-123",
"role": "Access",
"visibility": "Public",
"published": true
}
},
{
"_index": "dc-v2-file-set",
"_type": "_doc",
"_id": "fileset-2",
"_score": 1.0,
"_source": {
"id": "fileset-2",
"api_model": "FileSet",
"work_id": "work-123",
"role": "Access",
"visibility": "Public",
"published": true
}
}
]
}
}
31 changes: 18 additions & 13 deletions api/test/integration/get-work-by-id.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,26 @@ describe("Retrieve work by id", () => {
.get("/dc-v2-work/_doc/1234")
.reply(200, helpers.testFixture("mocks/work-1234.json"));

// Minimal transcription fetch for Access file sets in the fixture
// Mock file set search for transcriptions
mock
.get("/dc-v2-file-set/_doc/076dcbd8-8c57-40e8-bdf7-dc9153c87a36")
.post("/dc-v2-file-set/_search", () => true)
.reply(200, {
_source: {
id: "076dcbd8-8c57-40e8-bdf7-dc9153c87a36",
annotations: [],
},
});
mock
.get("/dc-v2-file-set/_doc/51862c1c-c024-45dc-ab26-694bd8ebc16c")
.reply(200, {
_source: {
id: "51862c1c-c024-45dc-ab26-694bd8ebc16c",
annotations: [],
hits: {
total: { value: 2 },
hits: [
{
_source: {
id: "076dcbd8-8c57-40e8-bdf7-dc9153c87a36",
annotations: [],
},
},
{
_source: {
id: "51862c1c-c024-45dc-ab26-694bd8ebc16c",
annotations: [],
},
},
],
},
});

Expand Down
71 changes: 71 additions & 0 deletions api/test/unit/api/opensearch.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,77 @@ describe("getCollection()", function () {
});
});

describe("getWorkFileSets()", function () {
helpers.saveEnvironment();
const mock = helpers.mockIndex();

it("gets file sets by work id", async function () {
const searchBody = {
size: 10000,
query: {
bool: {
must: [{ term: { work_id: "work-123" } }],
filter: [
{
bool: {
should: [
{ term: { visibility: "Public" } },
{ term: { visibility: "Institution" } },
],
},
},
{ term: { published: true } },
],
},
},
};

mock
.post("/dc-v2-file-set/_search", JSON.stringify(searchBody))
.reply(200, helpers.testFixture("mocks/work-file-sets.json"));

const result = await opensearch.getWorkFileSets("work-123");
const body = JSON.parse(result.body);
expect(result.statusCode).to.eq(200);
expect(body.hits.hits.length).to.be.greaterThan(0);
});

it("filters by role when provided", async function () {
const searchBody = {
size: 10000,
query: {
bool: {
must: [
{ term: { work_id: "work-123" } },
{ term: { role: "Access" } },
],
filter: [
{
bool: {
should: [
{ term: { visibility: "Public" } },
{ term: { visibility: "Institution" } },
],
},
},
{ term: { published: true } },
],
},
},
};

mock
.post("/dc-v2-file-set/_search", JSON.stringify(searchBody))
.reply(200, helpers.testFixture("mocks/work-file-sets-access.json"));

const result = await opensearch.getWorkFileSets("work-123", {
role: "Access",
});
const body = JSON.parse(result.body);
expect(result.statusCode).to.eq(200);
});
});

describe("search()", function () {
helpers.saveEnvironment();
const mock = helpers.mockIndex();
Expand Down
Loading