Files
documenso/packages/lib/server-only/recipient/set-recipients-for-document.ts
David Nguyen 8641884515 fix: recipients with CC role not being editable (#918)
## Description

Fixed issue where setting a recipient role as CC will prevent any
further changes as it is considered as "sent" and "signed".

## Other changes

- Prevent editing document after completed
- Removed CC and Viewers from the field recipient list since they will
never be filled
- Minor UI issues

## Checklist

- [X] I have tested these changes locally and they work as expected.
- [X] I have added/updated tests that prove the effectiveness of these
changes.
- [X] I have followed the project's coding style guidelines.
2024-02-09 12:37:17 +11:00

134 lines
3.4 KiB
TypeScript

import { prisma } from '@documenso/prisma';
import { RecipientRole } from '@documenso/prisma/client';
import { SendStatus, SigningStatus } from '@documenso/prisma/client';
import { nanoid } from '../../universal/id';
export interface SetRecipientsForDocumentOptions {
userId: number;
documentId: number;
recipients: {
id?: number | null;
email: string;
name: string;
role: RecipientRole;
}[];
}
export const setRecipientsForDocument = async ({
userId,
documentId,
recipients,
}: SetRecipientsForDocumentOptions) => {
const document = await prisma.document.findFirst({
where: {
id: documentId,
OR: [
{
userId,
},
{
team: {
members: {
some: {
userId,
},
},
},
},
],
},
});
if (!document) {
throw new Error('Document not found');
}
if (document.completedAt) {
throw new Error('Document already complete');
}
const normalizedRecipients = recipients.map((recipient) => ({
...recipient,
email: recipient.email.toLowerCase(),
}));
const existingRecipients = await prisma.recipient.findMany({
where: {
documentId,
},
});
const removedRecipients = existingRecipients.filter(
(existingRecipient) =>
!normalizedRecipients.find(
(recipient) =>
recipient.id === existingRecipient.id || recipient.email === existingRecipient.email,
),
);
const linkedRecipients = normalizedRecipients
.map((recipient) => {
const existing = existingRecipients.find(
(existingRecipient) =>
existingRecipient.id === recipient.id || existingRecipient.email === recipient.email,
);
return {
...recipient,
_persisted: existing,
};
})
.filter((recipient) => {
return (
recipient._persisted?.role === RecipientRole.CC ||
(recipient._persisted?.sendStatus !== SendStatus.SENT &&
recipient._persisted?.signingStatus !== SigningStatus.SIGNED)
);
});
const persistedRecipients = await prisma.$transaction(
// Disabling as wrapping promises here causes type issues
// eslint-disable-next-line @typescript-eslint/promise-function-async
linkedRecipients.map((recipient) =>
prisma.recipient.upsert({
where: {
id: recipient._persisted?.id ?? -1,
documentId,
},
update: {
name: recipient.name,
email: recipient.email,
role: recipient.role,
documentId,
sendStatus: recipient.role === RecipientRole.CC ? SendStatus.SENT : SendStatus.NOT_SENT,
signingStatus:
recipient.role === RecipientRole.CC ? SigningStatus.SIGNED : SigningStatus.NOT_SIGNED,
},
create: {
name: recipient.name,
email: recipient.email,
role: recipient.role,
token: nanoid(),
documentId,
sendStatus: recipient.role === RecipientRole.CC ? SendStatus.SENT : SendStatus.NOT_SENT,
signingStatus:
recipient.role === RecipientRole.CC ? SigningStatus.SIGNED : SigningStatus.NOT_SIGNED,
},
}),
),
);
if (removedRecipients.length > 0) {
await prisma.recipient.deleteMany({
where: {
id: {
in: removedRecipients.map((recipient) => recipient.id),
},
},
});
}
return persistedRecipients;
};