Skip to content

Commit

Permalink
Merge pull request #731 from JiscSD/OC-969
Browse files Browse the repository at this point in the history
OC-969: Add "Author Types" filter to search
  • Loading branch information
finlay-jisc authored Dec 5, 2024
2 parents aea4f8c + 5e97ffb commit 8377b09
Show file tree
Hide file tree
Showing 26 changed files with 521 additions and 232 deletions.
17 changes: 14 additions & 3 deletions api/prisma/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,19 @@ const createPublications = async (publications: Prisma.PublicationCreateInput[])
versions: {
where: {
isLatestVersion: true
},
select: {
title: true,
description: true,
keywords: true,
content: true,
currentStatus: true,
publishedDate: true,
user: {
select: {
role: true
}
}
}
}
}
Expand All @@ -31,12 +44,10 @@ const createPublications = async (publications: Prisma.PublicationCreateInput[])
id: createdPublication.id,
type: createdPublication.type,
title: latestVersion.title,
licence: latestVersion.licence,
organisationalAuthor: latestVersion.user.role === 'ORGANISATION',
description: latestVersion.description,
keywords: latestVersion.keywords,
content: latestVersion.content,
language: 'en',
currentStatus: latestVersion.currentStatus,
publishedDate: latestVersion.publishedDate,
cleanContent: convert(latestVersion.content)
}
Expand Down
32 changes: 0 additions & 32 deletions api/prisma/seeds/local/unitTesting/publications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -979,38 +979,6 @@ const publicationSeeds: Prisma.PublicationCreateInput[] = [
}
}
},
{
id: 'research-topic',
doi: '10.82259/cty5-2g27',
type: 'PROBLEM',
linkedTo: {
create: {
publicationToId: 'publication-problem-live',
versionToId: 'publication-problem-live-v1',
draft: false
}
},
versions: {
create: {
id: 'research-topic-v1',
versionNumber: 1,
title: 'Music',
conflictOfInterestStatus: false,
conflictOfInterestText: '',
content:
'This is an automatically-generated topic, produced in order to provide authors with a place to attach new Problem publications',
currentStatus: 'LIVE',
isLatestLiveVersion: true,
user: { connect: { id: 'octopus' } },
publicationStatus: {
create: [
{ status: 'DRAFT', createdAt: '2022-01-20T15:51:42.523Z' },
{ status: 'LIVE', createdAt: '2022-01-20T15:51:42.523Z' }
]
}
}
}
},
{
id: 'publication-peer-review-draft',
doi: '10.82259/cty5-2g28',
Expand Down
16 changes: 13 additions & 3 deletions api/scripts/reindex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ const reindex = async (): Promise<void> => {
versions: {
where: {
isLatestLiveVersion: true
},
select: {
title: true,
description: true,
keywords: true,
content: true,
publishedDate: true,
user: {
select: {
role: true
}
}
}
}
}
Expand All @@ -43,12 +55,10 @@ const reindex = async (): Promise<void> => {
id: pub.id,
type: pub.type,
title: latestLiveVersion.title,
licence: latestLiveVersion.licence,
organisationalAuthor: latestLiveVersion.user.role === 'ORGANISATION',
description: latestLiveVersion.description,
keywords: latestLiveVersion.keywords,
content: latestLiveVersion.content,
language: 'en',
currentStatus: latestLiveVersion.currentStatus,
publishedDate: latestLiveVersion.publishedDate,
cleanContent: convert(latestLiveVersion.content)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as testUtils from 'lib/testUtils';

describe('View publications + versions', () => {
beforeEach(async () => {
beforeAll(async () => {
await testUtils.clearDB();
await testUtils.testSeed();
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as testUtils from 'lib/testUtils';

describe('Get links from a supplied publication', () => {
beforeEach(async () => {
beforeAll(async () => {
await testUtils.clearDB();
await testUtils.testSeed();
});
Expand Down
10 changes: 9 additions & 1 deletion api/src/components/publication/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,6 @@ export const getOpenSearchPublications = (filters: I.OpenSearchPublicationFilter
const must: unknown[] = [];

if (filters.search) {
// @ts-ignore
must.push({
multi_match: {
query: filters.search,
Expand All @@ -373,6 +372,15 @@ export const getOpenSearchPublications = (filters: I.OpenSearchPublicationFilter
});
}

// The endpoint does accept both author types at once, but this is the same as not filtering.
if (filters.authorType && Enum.authorTypes.includes(filters.authorType)) {
must.push({
term: {
organisationalAuthor: filters.authorType === 'organisational'
}
});
}

// @ts-ignore
query.body.query.bool.must = must;

Expand Down
186 changes: 186 additions & 0 deletions api/src/components/publicationVersion/__tests__/getAll.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import * as enums from 'lib/enum';
import * as testUtils from 'lib/testUtils';

describe('Get many publication versions', () => {
beforeAll(async () => {
await testUtils.clearDB();
await testUtils.testSeed();
await testUtils.openSearchSeed();
});

test('Pages have 10 results by default', async () => {
const getPublications = await testUtils.agent.get('/publication-versions');

expect(getPublications.status).toEqual(200);
expect(getPublications.body.metadata).toMatchObject({
limit: 10,
offset: 0
});
expect(getPublications.body.data.length).toEqual(10);
});

test('Can limit page size', async () => {
const getPublications = await testUtils.agent.get('/publication-versions').query({
limit: 5
});

expect(getPublications.status).toEqual(200);
expect(getPublications.body.metadata).toMatchObject({
limit: 5
});
expect(getPublications.body.data.length).toEqual(5);
});

test('Can get second page', async () => {
const getPublications = await testUtils.agent.get('/publication-versions').query({
offset: 10
});

expect(getPublications.status).toEqual(200);
expect(getPublications.body.metadata).toMatchObject({
limit: 10,
offset: 10
});
// This will change if we add more live seed publications.
expect(getPublications.body.data.length).toEqual(5);
});

test('Can order by publication date, descending', async () => {
const getPublications = await testUtils.agent.get('/publication-versions').query({
orderBy: 'publishedDate',
orderDirection: 'desc'
});

expect(getPublications.status).toEqual(200);
const publicationDates = getPublications.body.data.map((version) => version.publishedDate);

Check warning on line 55 in api/src/components/publicationVersion/__tests__/getAll.test.ts

View workflow job for this annotation

GitHub Actions / eslint

Unsafe return of an `any` typed value
// Sort a copy of the dates from the results to confirm order.
const sortedPublicationDates = [...publicationDates].sort(
(a, b) => new Date(b).getTime() - new Date(a).getTime()
);
expect(publicationDates).toEqual(sortedPublicationDates);
});

test('Can order by publication date, ascending', async () => {
const getPublications = await testUtils.agent.get('/publication-versions').query({
orderBy: 'publishedDate',
orderDirection: 'asc'
});

expect(getPublications.status).toEqual(200);
const publicationDates = getPublications.body.data.map((version) => version.publishedDate);

Check warning on line 70 in api/src/components/publicationVersion/__tests__/getAll.test.ts

View workflow job for this annotation

GitHub Actions / eslint

Unsafe return of an `any` typed value
// Sort a copy of the dates from the results to confirm order.
const sortedPublicationDates = [...publicationDates].sort(
(a, b) => new Date(a).getTime() - new Date(b).getTime()
);
expect(publicationDates).toEqual(sortedPublicationDates);
});

test('Invalid orderBy is rejected', async () => {
const getPublications = await testUtils.agent.get('/publication-versions').query({
orderBy: 'dinosaur'
});

expect(getPublications.status).toEqual(400);
expect(getPublications.body.message).toHaveLength(1);
expect(getPublications.body.message[0].keyword).toEqual('enum');
});

test('Invalid order direction is rejected', async () => {
const getPublications = await testUtils.agent.get('/publication-versions').query({
orderBy: 'publishedDate',
orderDirection: 'dinosaur'
});

expect(getPublications.status).toEqual(400);
expect(getPublications.body.message).toHaveLength(1);
expect(getPublications.body.message[0].keyword).toEqual('enum');
});

test('Can filter by publication type', async () => {
await Promise.all(
enums.publicationTypes.map(async (type) => {
const getPublications = await testUtils.agent.get(`/publication-versions?type=${type}`);

expect(getPublications.status).toEqual(200);
expect(getPublications.body.data.every((version) => version.publication.type === type)).toEqual(true);
})
);
});

test('Can filter by multiple publication types at once', async () => {
const getPublications = await testUtils.agent.get('/publication-versions?type=PROBLEM,PROTOCOL');

expect(getPublications.status).toEqual(200);
expect(
getPublications.body.data.every((version) => ['PROBLEM', 'PROTOCOL'].includes(version.publication.type))
).toEqual(true);
});

test('Type filtering rejects invalid types', async () => {
const getPublications = await testUtils.agent.get('/publication-versions?type=DINOSAUR');

expect(getPublications.status).toEqual(400);
expect(getPublications.body.message).toHaveLength(1);
expect(getPublications.body.message[0].keyword).toEqual('pattern');
});

test('Can filter by author type', async () => {
const getOrganisationalPublications = await testUtils.agent.get(
'/publication-versions?authorType=organisational'
);

expect(getOrganisationalPublications.status).toEqual(200);
// User role isn't returned in body so differentiate results by length (there are fewer organisational publications).
expect(getOrganisationalPublications.body.data).toHaveLength(2);

const getIndividualPublications = await testUtils.agent.get('/publication-versions?authorType=individual');

expect(getIndividualPublications.status).toEqual(200);
expect(getIndividualPublications.body.data).toHaveLength(10);
});

test('Can filter by multiple author types at once', async () => {
const getPublications = await testUtils.agent.get('/publication-versions?authorType=individual,organisational');

expect(getPublications.status).toEqual(200);
// Includes everything.
expect(getPublications.body.metadata.total).toEqual(15);
});

test('Author filtering rejects invalid types', async () => {
const getPublications = await testUtils.agent.get('/publication-versions?authorType=dinosaur');

expect(getPublications.status).toEqual(400);
expect(getPublications.body.message).toHaveLength(1);
expect(getPublications.body.message[0].keyword).toEqual('pattern');
});

test('Can filter by search term', async () => {
const getPublications = await testUtils.agent.get('/publication-versions?search=ari');

expect(getPublications.status).toEqual(200);
expect(getPublications.body.data).toHaveLength(1);
});

test('Can filter by date range', async () => {
const getPublications = await testUtils.agent.get('/publication-versions').query({
dateFrom: '2024-07-16',
dateTo: '2024-07-16'
});

expect(getPublications.status).toEqual(200);
expect(getPublications.body.data).toHaveLength(1);
});

test('Can exclude a particular publication by its ID', async () => {
const getAllPublications = await testUtils.agent.get('/publication-versions');
const allPubsCount = getAllPublications.body.metadata.total;

const getMostPublications = await testUtils.agent
.get('/publication-versions')
.query({ exclude: 'ari-publication-1' });

expect(getMostPublications.status).toEqual(200);
expect(getMostPublications.body.metadata.total).toEqual(allPubsCount - 1);
});
});
9 changes: 7 additions & 2 deletions api/src/components/publicationVersion/schema/getAll.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import * as Enum from 'enum';
import * as I from 'interface';

const getAll: I.JSONSchemaType<I.OpenSearchPublicationFilters> = {
type: 'object',
properties: {
type: {
type: 'string',
pattern:
'^((PROBLEM|PROTOCOL|ANALYSIS|REAL_WORLD_APPLICATION|HYPOTHESIS|DATA|INTERPRETATION|PEER_REVIEW)(,)?)+$',
pattern: `^((${Enum.publicationTypes.join('|')})(,)?)+$`,
default: 'PROBLEM,PROTOCOL,ANALYSIS,REAL_WORLD_APPLICATION,HYPOTHESIS,DATA,INTERPRETATION,PEER_REVIEW'
},
authorType: {
type: 'string',
pattern: `^((${Enum.authorTypes.join('|')})(,)?)+$`,
nullable: true
},
limit: {
type: 'number',
default: 10
Expand Down
2 changes: 1 addition & 1 deletion api/src/components/publicationVersion/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1092,7 +1092,7 @@ export const postPublishHook = async (publicationVersion: I.PublicationVersion,
id: publicationVersion.versionOf,
type: publicationVersion.publication.type,
title: publicationVersion.title,
licence: publicationVersion.licence,
organisationalAuthor: publicationVersion.user.role === 'ORGANISATION',
description: publicationVersion.description,
keywords: publicationVersion.keywords,
content: publicationVersion.content,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as testUtils from 'lib/testUtils';

describe('get references', () => {
beforeEach(async () => {
beforeAll(async () => {
await testUtils.clearDB();
await testUtils.testSeed();
});
Expand Down
2 changes: 1 addition & 1 deletion api/src/components/topic/__tests__/getTopic.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as testUtils from 'lib/testUtils';

describe('Get individual topic', () => {
beforeEach(async () => {
beforeAll(async () => {
await testUtils.clearDB();
await testUtils.testSeed();
});
Expand Down
2 changes: 1 addition & 1 deletion api/src/components/topic/__tests__/getTopics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as testUtils from 'lib/testUtils';
import * as I from 'lib/interface';

describe('Get Topics', () => {
beforeEach(async () => {
beforeAll(async () => {
await testUtils.clearDB();
await testUtils.testSeed();
});
Expand Down
Loading

0 comments on commit 8377b09

Please sign in to comment.