Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OC-725: Revert change to force co-authors to accept with the email they were invited with #528

Merged
merged 3 commits into from
Nov 13, 2023
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
106 changes: 52 additions & 54 deletions api/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -53,47 +53,47 @@ model Images {
}

model Publication {
id String @id @default(cuid())
url_slug String @unique @default(cuid())
type PublicationType
doi String
publicationFlags PublicationFlags[]
PublicationBookmarks PublicationBookmarks[]
linkedTo Links[] @relation("from")
linkedFrom Links[] @relation("to")
topics Topic[]
versions PublicationVersion[]
id String @id @default(cuid())
url_slug String @unique @default(cuid())
type PublicationType
doi String
publicationFlags PublicationFlags[]
PublicationBookmarks PublicationBookmarks[]
linkedTo Links[] @relation("from")
linkedFrom Links[] @relation("to")
topics Topic[]
versions PublicationVersion[]
}

model PublicationVersion {
id String @id @default(cuid())
id String @id @default(cuid())
doi String?
versionOf String
versionNumber Int
isLatestVersion Boolean @default(true)
isLatestLiveVersion Boolean @default(false)
publication Publication @relation(fields: [versionOf], references: [id], onDelete: Cascade)
isLatestVersion Boolean @default(true)
isLatestLiveVersion Boolean @default(false)
publication Publication @relation(fields: [versionOf], references: [id], onDelete: Cascade)
createdBy String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [createdBy], references: [id], onDelete: Cascade)
currentStatus PublicationStatusEnum @default(DRAFT)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [createdBy], references: [id], onDelete: Cascade)
currentStatus PublicationStatusEnum @default(DRAFT)
publicationStatus PublicationStatus[]
publishedDate DateTime?
title String?
licence LicenceType @default(CC_BY)
licence LicenceType @default(CC_BY)
conflictOfInterestStatus Boolean?
conflictOfInterestText String?
ethicalStatement String?
ethicalStatementFreeText String?
dataPermissionsStatement String?
dataPermissionsStatementProvidedBy String?
dataAccessStatement String?
selfDeclaration Boolean? @default(false)
selfDeclaration Boolean? @default(false)
description String?
keywords String[]
content String?
language Languages @default(en)
language Languages @default(en)
coAuthors CoAuthors[]
References References[]
funders Funders[]
Expand Down Expand Up @@ -138,27 +138,25 @@ model PublicationStatus {
status PublicationStatusEnum
createdAt DateTime @default(now())
publicationVersionId String
publicationVersion PublicationVersion @relation(fields: [publicationVersionId], references: [id], onDelete: Cascade)
publicationVersion PublicationVersion @relation(fields: [publicationVersionId], references: [id], onDelete: Cascade)
}

model CoAuthors {
id String @id @default(cuid())
email String
code String @default(cuid())
confirmedCoAuthor Boolean @default(false)
approvalRequested Boolean @default(false)
linkedUser String?
position Int @default(0)
createdAt DateTime @default(now())
reminderDate DateTime?
affiliations Json[]
isIndependent Boolean @default(false)
user User? @relation(fields: [linkedUser], references: [id])
publicationVersion PublicationVersion @relation(fields: [publicationVersionId], references: [id], onDelete: Cascade)
publicationVersionId String
id String @id @default(cuid())
email String
code String @default(cuid())
confirmedCoAuthor Boolean @default(false)
approvalRequested Boolean @default(false)
linkedUser String?
position Int @default(0)
createdAt DateTime @default(now())
reminderDate DateTime?
affiliations Json[]
isIndependent Boolean @default(false)
user User? @relation(fields: [linkedUser], references: [id])
publicationVersion PublicationVersion @relation(fields: [publicationVersionId], references: [id], onDelete: Cascade)
publicationVersionId String

// This @@unique needs to be disabled for the migration step because the fields involved must be mandatory.
// It needs to be reinstated after migration with publicationVersionId, not publicationId.
@@unique([publicationVersionId, email])
}

Expand Down Expand Up @@ -196,24 +194,24 @@ model PublicationBookmarks {
}

model Topic {
id String @id @default(cuid())
title String
language Languages @default(en)
translations TopicTranslation[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
parents Topic[] @relation("TopicHierarchy")
children Topic[] @relation("TopicHierarchy")
publications Publication[]
id String @id @default(cuid())
title String
language Languages @default(en)
translations TopicTranslation[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
parents Topic[] @relation("TopicHierarchy")
children Topic[] @relation("TopicHierarchy")
publications Publication[]
}

model Bookmark {
id String @id @default(cuid())
type BookmarkType
entityId String
userId String
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
id String @id @default(cuid())
type BookmarkType
entityId String
userId String
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)

@@unique([entityId, type, userId])
}
Expand Down Expand Up @@ -472,4 +470,4 @@ enum ReferenceType {
enum BookmarkType {
PUBLICATION
TOPIC
}
}
31 changes: 0 additions & 31 deletions api/src/components/coauthor/__tests__/linkCoAuthor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,35 +94,4 @@ describe('Link co-author', () => {

expect(link.status).toEqual(404);
});

// the following test covers an edge case, but still possible
test('Cannot link co-author with a different email address', async () => {
// trying to accept invitation with a user which is not a co-author
const response = await testUtils.agent
.patch('/publication-versions/publication-problem-draft-v1/link-coauthor')
.query({ apiKey: '000000004' })
.send({
email: 'test-user-7@jisc.ac.uk',
code: 'test-code-user-7',
approve: true
});

expect(response.status).toEqual(404);
expect(response.body.message).toBe('You are not currently listed as an author on this draft');

// trying to accept invitation with a different co-author account
const response2 = await testUtils.agent
.patch('/publication-versions/publication-problem-draft-v1/link-coauthor')
.query({ apiKey: '000000008' })
.send({
email: 'test-user-7@jisc.ac.uk',
code: 'test-code-user-7',
approve: true
});

expect(response2.status).toEqual(403);
expect(response2.body.message).toBe(
'Your email address does not match the one to which the invitation has been sent.'
);
});
});
18 changes: 8 additions & 10 deletions api/src/components/coauthor/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,19 +269,17 @@ export const link = async (
});
}

// check if the user email is the same as the one the invitation has been sent to
if (event.user.email !== coAuthorByEmail.email) {
const isCoAuthor = version.coAuthors.some((coAuthor) => coAuthor.email === event.user?.email); // check that this user is a coAuthor
await coAuthorService.linkUser(event.user.id, version.id, event.body.email, event.body.code);

return response.json(isCoAuthor ? 403 : 404, {
message: isCoAuthor
? 'Your email address does not match the one to which the invitation has been sent.'
: 'You are not currently listed as an author on this draft'
});
// The email of the linked user may not match the email the invitation was sent to
// (e.g. user manages their orcid account with a different email to their work email).
// In this case, we need to update the coauthor's email field because it becomes outdated.
if (event.user.email !== coAuthorByEmail.email) {
// We already check that the logged in user's email is not already a coauthor on this version,
// so this is safe.
await coAuthorService.update(coAuthorByEmail.id, { email: event.user.email });
}

await coAuthorService.linkUser(event.user.id, version.id, event.body.email, event.body.code);

return response.json(200, 'Linked user account');
} catch (err) {
console.log(err);
Expand Down
Loading