diff --git a/api/prisma/convertResearchTopics.ts b/api/prisma/convertResearchTopics.ts deleted file mode 100644 index d097adbd3..000000000 --- a/api/prisma/convertResearchTopics.ts +++ /dev/null @@ -1,77 +0,0 @@ -import * as I from 'lib/interface'; -import * as client from 'lib/client'; -import * as publicationService from 'components/publication/service'; -import * as topicService from 'components/topic/service'; - -const convertResearchTopics = async (): Promise => { - // get all research problems which need to be converted to research topics - const researchTopicProblems = await publicationService.getResearchTopics(); - - const createdTopics: (I.Topic & { publicationId: string })[] = []; // publicationId is needed for creating connections later on - - // create bare research topics for each research problem they correspond to - for (const problem of researchTopicProblems) { - const createdTopic = await topicService.create({ - title: problem.title || '', - language: problem.language, - parentIds: [] - }); - - createdTopics.push({ ...createdTopic, publicationId: problem.id }); - } - - // create relations for each created topic - for (let i = 0; i < createdTopics.length; i++) { - const currentProblem = researchTopicProblems[i]; - const currentTopic = createdTopics[i]; - - // find parents - const parentTopics = createdTopics.filter((topic) => - currentProblem.linkedTo.some((link) => link.publicationToRef.id === topic.publicationId) - ); - - // find children - const childTopics = createdTopics.filter((topic) => - currentProblem.linkedFrom.some((link) => link.publicationFromRef.id === topic.publicationId) - ); - - // find linked research problems which are not themselves topics - const linkedProblems = currentProblem.linkedFrom - .filter( - (link) => - link.publicationFromRef.type === 'PROBLEM' && - !childTopics.some((childTopic) => childTopic.publicationId === link.publicationFromRef.id) - ) - .map((link) => link.publicationFromRef.id); - - // check if the converted problem had some linked "HYPOTHESIS" children - if (currentProblem.linkedFrom.some((link) => link.publicationFromRef.type === 'HYPOTHESIS')) { - linkedProblems.push(currentProblem.id); // assign the research problem to it's corresponding research topic (to itself) - } - - await client.prisma.topic.update({ - where: { - id: currentTopic.id - }, - data: { - parents: { - connect: parentTopics?.map((topic) => ({ id: topic.id })) - }, - children: { - connect: childTopics?.map((topic) => ({ id: topic.id })) - }, - publications: { - connect: linkedProblems.map((problemId) => ({ id: problemId })) // assign linked research problems to the created topic - } - } - }); - } - - return createdTopics.length; -}; - -convertResearchTopics() - .then((createdTopicsCount) => - console.log(`Successfully converted ${createdTopicsCount} research problems to research topics`) - ) - .catch((error) => console.log(error)); diff --git a/api/prisma/removeResearchTopicProblems.ts b/api/prisma/removeResearchTopicProblems.ts deleted file mode 100644 index 6f7a11ddb..000000000 --- a/api/prisma/removeResearchTopicProblems.ts +++ /dev/null @@ -1,90 +0,0 @@ -import * as client from 'lib/client'; -import * as publicationService from 'components/publication/service'; -import axios from 'axios'; - -const updateDoiState = (doi: string): Promise => { - console.log('Updating DOI:', doi); - - // registered/findable DOIs cannot be deleted - // but we can update their state from "findable" to "registered" so they are not available anymore via the Public API - // https://support.datacite.org/docs/doi-states - return axios.put( - `${process.env.DATACITE_ENDPOINT}/${doi}`, - { - data: { - attributes: { - event: 'hide' - } - } - }, - { - auth: { - username: process.env.DATACITE_USER as string, - password: process.env.DATACITE_PASSWORD as string - } - } - ); -}; - -const removeResearchTopicProblems = async (): Promise<{ deletedCount: number; remainingCount: number }> => { - // get all research topic problems which don't have hypothesis children - const researchTopicProblems = await publicationService.getResearchTopics({ - linkedFrom: { - none: { - publicationFromRef: { - type: 'HYPOTHESIS' - } - } - } - }); - - const toBeDeleted: string[] = []; - - // update DOIs in chunks - const chunkSize = 10; - - for (let i = 0; i < researchTopicProblems.length; i += chunkSize) { - const currentChunk = researchTopicProblems.slice(i, i + chunkSize); - - const promises = currentChunk.map((problem) => - updateDoiState(problem.doi).catch((error) => { - console.log('Error updating DOI:', problem.doi); - - return error as Error; - }) - ); - - const results = await Promise.all(promises); - - results.forEach((result, index) => { - if (!(result instanceof Error)) { - toBeDeleted.push(currentChunk[index].id); - } - }); - } - - // delete all research problems where id matches - // all their links will be deleted in cascade - const { count: deletedCount } = await client.prisma.publication.deleteMany({ - where: { - id: { - in: toBeDeleted - } - } - }); - - const remainingCount = researchTopicProblems.length - deletedCount; - - return { deletedCount, remainingCount }; -}; - -removeResearchTopicProblems() - .then(({ deletedCount, remainingCount }) => { - console.log(`Successfully deleted ${deletedCount} research problems.`); - - if (remainingCount) { - console.log('Remaining research problems which could not be deleted:', remainingCount); - console.log('Please check the logs above.'); - } - }) - .catch((error) => console.log(error)); diff --git a/api/serverless.yml b/api/serverless.yml index 9d25232f0..26a0cbfbc 100644 --- a/api/serverless.yml +++ b/api/serverless.yml @@ -184,13 +184,6 @@ functions: path: ${self:custom.versions.v1}/publications/{id}/pdf method: GET cors: true - getResearchTopics: - handler: src/components/publication/routes.getResearchTopics - events: - - http: - path: ${self:custom.versions.v1}/publications/research-topics - method: GET - cors: true getPublicationTopics: handler: src/components/publication/routes.getPublicationTopics events: diff --git a/api/src/components/coauthor/__tests__/createCoAuthor.test.ts b/api/src/components/coauthor/__tests__/createCoAuthor.test.ts index 5d35a7ce1..a2188d6be 100644 --- a/api/src/components/coauthor/__tests__/createCoAuthor.test.ts +++ b/api/src/components/coauthor/__tests__/createCoAuthor.test.ts @@ -129,12 +129,12 @@ describe('create coauthor', () => { test('Co-author email is converted to lower case on save', async () => { await testUtils.agent - .put('/publications/publication-data-draft/coauthors') + .put('/publication-versions/publication-data-draft-v1/coauthors') .query({ apiKey: '123456789' }) .send([ { id: createId(), - publicationId: 'publication-problem-draft', + publicationVersionId: 'publication-problem-draft-v1', email: 'MULTIcaseAddress@emailtest.COM', linkedUser: null, approvalRequested: false, @@ -143,7 +143,7 @@ describe('create coauthor', () => { ]); const coAuthors = await testUtils.agent - .get('/publications/publication-data-draft/coauthors') + .get('/publication-versions/publication-data-draft-v1/coauthors') .query({ apiKey: '123456789' }); expect(coAuthors.body.length).toEqual(2); // corresponding author and this new one diff --git a/api/src/components/publication/__tests__/getResearchTopics.test.ts b/api/src/components/publication/__tests__/getResearchTopics.test.ts deleted file mode 100644 index 890272bf4..000000000 --- a/api/src/components/publication/__tests__/getResearchTopics.test.ts +++ /dev/null @@ -1,23 +0,0 @@ -import * as testUtils from 'lib/testUtils'; - -describe('Research Topics', () => { - beforeEach(async () => { - await testUtils.clearDB(); - await testUtils.testSeed(); - }); - - test('Get list of research topics published by Science Octopus', async () => { - const response = await testUtils.agent.get('/publications/research-topics'); - - expect(response.status).toEqual(200); - - expect( - response.body.every( - (item) => - item.type === 'PROBLEM' && - item.createdBy === 'octopus' && - (item.content.includes('This is an automatically-generated topic') as boolean) - ) - ).toBe(true); - }); -}); diff --git a/api/src/components/publication/controller.ts b/api/src/components/publication/controller.ts index 45f87003d..396f5fd86 100644 --- a/api/src/components/publication/controller.ts +++ b/api/src/components/publication/controller.ts @@ -202,16 +202,6 @@ export const getPDF = async ( : response.json(200, { pdfUrl }); }; -export const getResearchTopics = async (): Promise => { - try { - const researchTopics = await publicationService.getResearchTopics(); - - return response.json(200, researchTopics); - } catch (error) { - return response.json(500, { message: 'Unknown server error.' }); - } -}; - export const updateTopics = async ( event: I.AuthenticatedAPIRequest< I.UpdatePublicationTopicsRequestBody, diff --git a/api/src/components/publication/routes.ts b/api/src/components/publication/routes.ts index 20218c154..2cf5f2bbd 100644 --- a/api/src/components/publication/routes.ts +++ b/api/src/components/publication/routes.ts @@ -29,10 +29,6 @@ export const getPDF = middy(publicationController.getPDF) .use(middleware.httpJsonBodyParser()) .use(middleware.validator(publicationSchema.getPDF, 'pathParameters')); -export const getResearchTopics = middy(publicationController.getResearchTopics).use( - middleware.doNotWaitForEmptyEventLoop({ runOnError: true, runOnBefore: true, runOnAfter: true }) -); - export const updateTopics = middy(publicationController.updateTopics) .use(middleware.doNotWaitForEmptyEventLoop({ runOnError: true, runOnBefore: true, runOnAfter: true })) .use(middleware.httpJsonBodyParser()) diff --git a/api/src/components/publication/service.ts b/api/src/components/publication/service.ts index ecc5e47f8..eb5aaebb8 100644 --- a/api/src/components/publication/service.ts +++ b/api/src/components/publication/service.ts @@ -6,6 +6,7 @@ import * as referenceService from 'reference/service'; import * as Helpers from 'lib/helpers'; import { Browser, launch } from 'puppeteer-core'; import { PutObjectCommand } from '@aws-sdk/client-s3'; +import { Prisma } from '@prisma/client'; export const isIdInUse = async (id: string) => { const publication = await client.prisma.publication.count({ @@ -922,129 +923,6 @@ export const generatePDF = async (publicationVersion: I.PublicationVersion): Pro } }; -export const getResearchTopics = async () => { - const publications = await client.prisma.publication.findMany({ - where: { - type: 'PROBLEM', - OR: [ - { - id: { - equals: 'why' // god problem will be converted to a god topic - } - }, - { - versions: { - some: { - isLatestVersion: true, - content: { - contains: 'This is an automatically-generated topic' - } - } - } - } - ], - References: { - none: {} - }, - ...additionalFilters, - versions: { - some: { - createdBy: 'octopus', - isLatestVersion: true, - References: { - none: {} - } - } - } - }, - include: { - versions: { - where: { - isLatestVersion: true - }, - include: { - user: { - select: { - id: true, - firstName: true, - lastName: true, - orcid: true - } - } - } - }, - linkedTo: { - select: { - id: true, - publicationToRef: { - select: { - id: true, - type: true, - doi: true, - versions: { - select: { - user: { - select: { - id: true, - firstName: true, - lastName: true, - orcid: true - } - }, - title: true, - publishedDate: true, - currentStatus: true, - description: true, - keywords: true - } - } - } - } - } - }, - linkedFrom: { - select: { - id: true, - publicationFromRef: { - select: { - id: true, - type: true, - doi: true, - versions: { - select: { - user: { - select: { - id: true, - firstName: true, - lastName: true, - orcid: true - } - }, - title: true, - publishedDate: true, - currentStatus: true, - description: true, - keywords: true - } - } - } - } - } - }, - PublicationBookmarks: true - } - }); - - // Merge versioned data into the publication records - const mergedPublications = publications.map((publication) => { - const currentVersion = publication.versions[0]; - - return { ...currentVersion, ...publication }; - }); - - return mergedPublications; -}; - // Overwrite existing topics with those whose IDs were passed. export const updateTopics = async (id: string, topics: string[]) => { // Format topics in a way that prisma can understand. diff --git a/e2e/tests/LoggedIn/publish.e2e.spec.ts b/e2e/tests/LoggedIn/publish.e2e.spec.ts index 4624afc36..980f4172b 100644 --- a/e2e/tests/LoggedIn/publish.e2e.spec.ts +++ b/e2e/tests/LoggedIn/publish.e2e.spec.ts @@ -627,7 +627,7 @@ const addCoAuthor = async (page: Page, user: Helpers.TestUser) => { }; const removeCoAuthor = async (page: Page, user: Helpers.TestUser) => { - await page.locator('aside button:has-text("Co-authors")').click(); + await page.locator('aside button:has-text("Co-authors")').first().click(); const row = page.locator('tr', { hasText: user.email }); await row.locator('button[title="Delete"]').click(); }; diff --git a/ui/src/components/Publication/Visualization/index.tsx b/ui/src/components/Publication/Visualization/index.tsx index e8bd30540..ea24c4bf8 100644 --- a/ui/src/components/Publication/Visualization/index.tsx +++ b/ui/src/components/Publication/Visualization/index.tsx @@ -124,27 +124,24 @@ const getPublicationsByType = (data: Interfaces.PublicationWithLinks, type: stri if (publication.type === type) { // Push the selected publication first - const latestVersion = publication.versions.find((version) => version.isLatestLiveVersion); - if (latestVersion) { - publications.push({ - id: publication.id, - title: latestVersion.title, - type: publication.type, - createdBy: latestVersion.createdBy, - publishedDate: latestVersion.publishedDate, - authorFirstName: latestVersion.user.firstName, - authorLastName: latestVersion.user.lastName, - authors: latestVersion.coAuthors, - pointers: linkedFrom - .filter( - (linkedPublication) => - linkedPublication.type !== 'PEER_REVIEW' && - linkedPublication.parentPublication === publication.id - ) - .map((publication) => publication.id) // get the ids of all direct child publications - }); - } + publications.push({ + id: publication.id, + title: publication.title, + type: publication.type, + createdBy: publication.createdBy, + publishedDate: publication.publishedDate, + authorFirstName: publication.authorFirstName, + authorLastName: publication.authorLastName, + authors: publication.authors, + pointers: linkedFrom + .filter( + (linkedPublication) => + linkedPublication.type !== 'PEER_REVIEW' && + linkedPublication.parentPublication === publication.id + ) + .map((publication) => publication.id) // get the ids of all direct child publications + }); } // ignore publications above 'PROBLEM'