fix: refactor prisma relations (#1581)

This commit is contained in:
David Nguyen
2025-01-13 13:41:53 +11:00
committed by GitHub
parent 48b55758e3
commit 7d0a9c6439
143 changed files with 687 additions and 790 deletions

View File

@@ -36,19 +36,19 @@ export const SEND_RECIPIENT_SIGNED_EMAIL_JOB_DEFINITION = {
const document = await prisma.document.findFirst({
where: {
id: documentId,
Recipient: {
recipients: {
some: {
id: recipientId,
},
},
},
include: {
Recipient: {
recipients: {
where: {
id: recipientId,
},
},
User: true,
user: true,
documentMeta: true,
team: {
include: {
@@ -62,7 +62,7 @@ export const SEND_RECIPIENT_SIGNED_EMAIL_JOB_DEFINITION = {
throw new Error('Document not found');
}
if (document.Recipient.length === 0) {
if (document.recipients.length === 0) {
throw new Error('Document has no recipients');
}
@@ -74,9 +74,9 @@ export const SEND_RECIPIENT_SIGNED_EMAIL_JOB_DEFINITION = {
return;
}
const [recipient] = document.Recipient;
const [recipient] = document.recipients;
const { email: recipientEmail, name: recipientName } = recipient;
const { User: owner } = document;
const { user: owner } = document;
const recipientReference = recipientName || recipientEmail;

View File

@@ -33,7 +33,7 @@ export const run = async ({
id: documentId,
},
include: {
User: true,
user: true,
documentMeta: true,
team: {
select: {
@@ -53,7 +53,7 @@ export const run = async ({
}),
]);
const { documentMeta, team, User: documentOwner } = document;
const { documentMeta, user: documentOwner } = document;
const isEmailEnabled = extractDerivedDocumentEmailSettings(
document.documentMeta,
@@ -70,7 +70,7 @@ export const run = async ({
const recipientTemplate = createElement(DocumentRejectionConfirmedEmail, {
recipientName: recipient.name,
documentName: document.title,
documentOwnerName: document.User.name || document.User.email,
documentOwnerName: document.user.name || document.user.email,
reason: recipient.rejectionReason || '',
assetBaseUrl: NEXT_PUBLIC_WEBAPP_URL(),
});

View File

@@ -20,7 +20,10 @@ import { insertFieldInPDF } from '../../../server-only/pdf/insert-field-in-pdf';
import { normalizeSignatureAppearances } from '../../../server-only/pdf/normalize-signature-appearances';
import { triggerWebhook } from '../../../server-only/webhooks/trigger/trigger-webhook';
import { DOCUMENT_AUDIT_LOG_TYPE } from '../../../types/document-audit-logs';
import { ZWebhookDocumentSchema } from '../../../types/webhook-payload';
import {
ZWebhookDocumentSchema,
mapDocumentToWebhookDocumentPayload,
} from '../../../types/webhook-payload';
import { getFile } from '../../../universal/upload/get-file';
import { putPdfFile } from '../../../universal/upload/put-file';
import { fieldsContainUnsignedRequiredField } from '../../../utils/advanced-fields-helpers';
@@ -40,7 +43,7 @@ export const run = async ({
const document = await prisma.document.findFirstOrThrow({
where: {
id: documentId,
Recipient: {
recipients: {
every: {
signingStatus: SigningStatus.SIGNED,
},
@@ -48,7 +51,7 @@ export const run = async ({
},
include: {
documentMeta: true,
Recipient: true,
recipients: true,
team: {
select: {
teamGlobalSettings: {
@@ -102,7 +105,7 @@ export const run = async ({
documentId: document.id,
},
include: {
Signature: true,
signature: true,
},
});
@@ -243,13 +246,13 @@ export const run = async ({
include: {
documentData: true,
documentMeta: true,
Recipient: true,
recipients: true,
},
});
await triggerWebhook({
event: WebhookTriggerEvents.DOCUMENT_COMPLETED,
data: ZWebhookDocumentSchema.parse(updatedDocument),
data: ZWebhookDocumentSchema.parse(mapDocumentToWebhookDocumentPayload(updatedDocument)),
userId: updatedDocument.userId,
teamId: updatedDocument.teamId ?? undefined,
});

View File

@@ -248,7 +248,7 @@ export const NEXT_AUTH_OPTIONS: AuthOptions = {
credentialId: Buffer.from(requestBodyCrediential.id, 'base64'),
},
include: {
User: {
user: {
select: {
id: true,
email: true,
@@ -263,7 +263,7 @@ export const NEXT_AUTH_OPTIONS: AuthOptions = {
throw new AppError(AppErrorCode.NOT_SETUP);
}
const user = passkey.User;
const user = passkey.user;
const { rpId, origin } = getAuthenticatorOptions();

View File

@@ -30,14 +30,14 @@ export const findDocuments = async ({ query, page = 1, perPage = 10 }: FindDocum
createdAt: 'desc',
},
include: {
User: {
user: {
select: {
id: true,
name: true,
email: true,
},
},
Recipient: true,
recipients: true,
},
}),
prisma.document.count({

View File

@@ -11,18 +11,18 @@ export const getEntireDocument = async ({ id }: GetEntireDocumentOptions) => {
},
include: {
documentMeta: true,
User: {
user: {
select: {
id: true,
name: true,
email: true,
},
},
Recipient: {
recipients: {
include: {
Field: {
fields: {
include: {
Signature: true,
signature: true,
},
},
},

View File

@@ -28,7 +28,7 @@ export async function getSigningVolume({
status: 'ACTIVE',
OR: [
{
User: {
user: {
OR: [
{ name: { contains: search, mode: 'insensitive' } },
{ email: { contains: search, mode: 'insensitive' } },
@@ -47,11 +47,11 @@ export async function getSigningVolume({
prisma.subscription.findMany({
where: whereClause,
include: {
User: {
user: {
select: {
name: true,
email: true,
Document: {
documents: {
where: {
status: DocumentStatus.COMPLETED,
deletedAt: null,
@@ -63,7 +63,7 @@ export async function getSigningVolume({
team: {
select: {
name: true,
document: {
documents: {
where: {
status: DocumentStatus.COMPLETED,
deletedAt: null,
@@ -74,7 +74,7 @@ export async function getSigningVolume({
},
orderBy:
sortBy === 'name'
? [{ User: { name: sortOrder } }, { team: { name: sortOrder } }, { createdAt: 'desc' }]
? [{ user: { name: sortOrder } }, { team: { name: sortOrder } }, { createdAt: 'desc' }]
: sortBy === 'createdAt'
? [{ createdAt: sortOrder }]
: undefined,
@@ -88,9 +88,9 @@ export async function getSigningVolume({
const leaderboardWithVolume: SigningVolume[] = subscriptions.map((subscription) => {
const name =
subscription.User?.name || subscription.team?.name || subscription.User?.email || 'Unknown';
const userSignedDocs = subscription.User?.Document?.length || 0;
const teamSignedDocs = subscription.team?.document?.length || 0;
subscription.user?.name || subscription.team?.name || subscription.user?.email || 'Unknown';
const userSignedDocs = subscription.user?.documents?.length || 0;
const teamSignedDocs = subscription.team?.documents?.length || 0;
return {
id: subscription.id,
name,

View File

@@ -10,7 +10,7 @@ export const getUsersCount = async () => {
export const getUsersWithSubscriptionsCount = async () => {
return await prisma.user.count({
where: {
Subscription: {
subscriptions: {
some: {
status: SubscriptionStatus.ACTIVE,
},
@@ -22,7 +22,7 @@ export const getUsersWithSubscriptionsCount = async () => {
export const getUserWithAtLeastOneDocumentPerMonth = async () => {
return await prisma.user.count({
where: {
Document: {
documents: {
some: {
createdAt: {
gte: DateTime.now().minus({ months: 1 }).toJSDate(),
@@ -36,7 +36,7 @@ export const getUserWithAtLeastOneDocumentPerMonth = async () => {
export const getUserWithAtLeastOneDocumentSignedPerMonth = async () => {
return await prisma.user.count({
where: {
Document: {
documents: {
some: {
status: {
equals: DocumentStatus.COMPLETED,

View File

@@ -23,7 +23,7 @@ export const sendConfirmationEmail = async ({ userId }: SendConfirmationEmailPro
id: userId,
},
include: {
VerificationToken: {
verificationTokens: {
orderBy: {
createdAt: 'desc',
},
@@ -32,7 +32,7 @@ export const sendConfirmationEmail = async ({ userId }: SendConfirmationEmailPro
},
});
const [verificationToken] = user.VerificationToken;
const [verificationToken] = user.verificationTokens;
if (!verificationToken?.token) {
throw new Error('Verification token not found for the user');

View File

@@ -20,7 +20,7 @@ export const sendForgotPassword = async ({ userId }: SendForgotPasswordOptions)
id: userId,
},
include: {
PasswordResetToken: {
passwordResetTokens: {
orderBy: {
createdAt: 'desc',
},
@@ -33,7 +33,7 @@ export const sendForgotPassword = async ({ userId }: SendForgotPasswordOptions)
throw new Error('User not found');
}
const token = user.PasswordResetToken[0].token;
const token = user.passwordResetTokens[0].token;
const assetBaseUrl = NEXT_PUBLIC_WEBAPP_URL() || 'http://localhost:3000';
const resetPasswordLink = `${NEXT_PUBLIC_WEBAPP_URL()}/reset-password/${token}`;

View File

@@ -14,7 +14,10 @@ import {
import { jobs } from '../../jobs/client';
import type { TRecipientActionAuth } from '../../types/document-auth';
import { ZWebhookDocumentSchema } from '../../types/webhook-payload';
import {
ZWebhookDocumentSchema,
mapDocumentToWebhookDocumentPayload,
} from '../../types/webhook-payload';
import { getIsRecipientsTurnToSign } from '../recipient/get-is-recipient-turn';
import { triggerWebhook } from '../webhooks/trigger/trigger-webhook';
import { sendPendingEmail } from './send-pending-email';
@@ -31,7 +34,7 @@ const getDocument = async ({ token, documentId }: CompleteDocumentWithTokenOptio
return await prisma.document.findFirstOrThrow({
where: {
id: documentId,
Recipient: {
recipients: {
some: {
token,
},
@@ -39,7 +42,7 @@ const getDocument = async ({ token, documentId }: CompleteDocumentWithTokenOptio
},
include: {
documentMeta: true,
Recipient: {
recipients: {
where: {
token,
},
@@ -59,11 +62,11 @@ export const completeDocumentWithToken = async ({
throw new Error(`Document ${document.id} must be pending`);
}
if (document.Recipient.length === 0) {
if (document.recipients.length === 0) {
throw new Error(`Document ${document.id} has no recipient with token ${token}`);
}
const [recipient] = document.Recipient;
const [recipient] = document.recipients;
if (recipient.signingStatus === SigningStatus.SIGNED) {
throw new Error(`Recipient ${recipient.id} has already signed`);
@@ -195,7 +198,7 @@ export const completeDocumentWithToken = async ({
const haveAllRecipientsSigned = await prisma.document.findFirst({
where: {
id: document.id,
Recipient: {
recipients: {
every: {
OR: [{ signingStatus: SigningStatus.SIGNED }, { role: RecipientRole.CC }],
},
@@ -219,13 +222,13 @@ export const completeDocumentWithToken = async ({
},
include: {
documentMeta: true,
Recipient: true,
recipients: true,
},
});
await triggerWebhook({
event: WebhookTriggerEvents.DOCUMENT_SIGNED,
data: ZWebhookDocumentSchema.parse(updatedDocument),
data: ZWebhookDocumentSchema.parse(mapDocumentToWebhookDocumentPayload(updatedDocument)),
userId: updatedDocument.userId,
teamId: updatedDocument.teamId ?? undefined,
});

View File

@@ -13,7 +13,10 @@ import type { Team, TeamGlobalSettings } from '@documenso/prisma/client';
import { TeamMemberRole } from '@documenso/prisma/client';
import { DocumentSchema } from '@documenso/prisma/generated/zod';
import { ZWebhookDocumentSchema } from '../../types/webhook-payload';
import {
ZWebhookDocumentSchema,
mapDocumentToWebhookDocumentPayload,
} from '../../types/webhook-payload';
import { getFile } from '../../universal/upload/get-file';
import { putPdfFile } from '../../universal/upload/put-file';
import { triggerWebhook } from '../webhooks/trigger/trigger-webhook';
@@ -178,7 +181,7 @@ export const createDocument = async ({
},
include: {
documentMeta: true,
Recipient: true,
recipients: true,
},
});
@@ -188,7 +191,7 @@ export const createDocument = async ({
await triggerWebhook({
event: WebhookTriggerEvents.DOCUMENT_CREATED,
data: ZWebhookDocumentSchema.parse(createdDocument),
data: ZWebhookDocumentSchema.parse(mapDocumentToWebhookDocumentPayload(createdDocument)),
userId,
teamId,
});

View File

@@ -58,7 +58,7 @@ export const deleteDocument = async ({
id,
},
include: {
Recipient: true,
recipients: true,
documentMeta: true,
team: {
include: {
@@ -77,7 +77,7 @@ export const deleteDocument = async ({
const isUserOwner = document.userId === userId;
const isUserTeamMember = document.team?.members.some((member) => member.userId === userId);
const userRecipient = document.Recipient.find((recipient) => recipient.email === user.email);
const userRecipient = document.recipients.find((recipient) => recipient.email === user.email);
if (!isUserOwner && !isUserTeamMember && !userRecipient) {
throw new AppError(AppErrorCode.UNAUTHORIZED, {
@@ -128,7 +128,7 @@ export const deleteDocument = async ({
type HandleDocumentOwnerDeleteOptions = {
document: Document & {
Recipient: Recipient[];
recipients: Recipient[];
documentMeta: DocumentMeta | null;
};
team?:
@@ -210,7 +210,7 @@ const handleDocumentOwnerDelete = async ({
// Send cancellation emails to recipients.
await Promise.all(
document.Recipient.map(async (recipient) => {
document.recipients.map(async (recipient) => {
if (recipient.sendStatus !== SendStatus.SENT) {
return;
}

View File

@@ -56,7 +56,7 @@ export const duplicateDocument = async ({
const createDocumentArguments: Prisma.DocumentCreateArgs = {
data: {
title: document.title,
User: {
user: {
connect: {
id: document.userId,
},

View File

@@ -45,12 +45,12 @@ export type FindDocumentsOptions = {
export const ZFindDocumentsResponseSchema = ZFindResultResponse.extend({
data: DocumentSchema.extend({
User: UserSchema.pick({
user: UserSchema.pick({
id: true,
name: true,
email: true,
}),
Recipient: RecipientSchema.array(),
recipients: RecipientSchema.array(),
team: TeamSchema.pick({
id: true,
url: true,
@@ -112,8 +112,8 @@ export const findDocuments = async ({
const searchFilter: Prisma.DocumentWhereInput = {
OR: [
{ title: { contains: query, mode: 'insensitive' } },
{ Recipient: { some: { name: { contains: query, mode: 'insensitive' } } } },
{ Recipient: { some: { email: { contains: query, mode: 'insensitive' } } } },
{ recipients: { some: { name: { contains: query, mode: 'insensitive' } } } },
{ recipients: { some: { email: { contains: query, mode: 'insensitive' } } } },
],
};
@@ -137,7 +137,7 @@ export const findDocuments = async ({
{
OR: [
{
Recipient: {
recipients: {
some: {
email: user.email,
},
@@ -174,7 +174,7 @@ export const findDocuments = async ({
deletedAt: null,
},
{
Recipient: {
recipients: {
some: {
email: user.email,
documentDeletedAt: null,
@@ -195,13 +195,13 @@ export const findDocuments = async ({
deletedAt: null,
},
{
User: {
user: {
email: team.teamEmail.email,
},
deletedAt: null,
},
{
Recipient: {
recipients: {
some: {
email: team.teamEmail.email,
documentDeletedAt: null,
@@ -266,14 +266,14 @@ export const findDocuments = async ({
[orderByColumn]: orderByDirection,
},
include: {
User: {
user: {
select: {
id: true,
name: true,
email: true,
},
},
Recipient: true,
recipients: true,
team: {
select: {
id: true,
@@ -313,7 +313,7 @@ const findDocumentsFilter = (status: ExtendedDocumentStatus, user: User) => {
},
{
status: ExtendedDocumentStatus.COMPLETED,
Recipient: {
recipients: {
some: {
email: user.email,
},
@@ -321,7 +321,7 @@ const findDocumentsFilter = (status: ExtendedDocumentStatus, user: User) => {
},
{
status: ExtendedDocumentStatus.PENDING,
Recipient: {
recipients: {
some: {
email: user.email,
},
@@ -333,7 +333,7 @@ const findDocumentsFilter = (status: ExtendedDocumentStatus, user: User) => {
status: {
not: ExtendedDocumentStatus.DRAFT,
},
Recipient: {
recipients: {
some: {
email: user.email,
signingStatus: SigningStatus.NOT_SIGNED,
@@ -357,7 +357,7 @@ const findDocumentsFilter = (status: ExtendedDocumentStatus, user: User) => {
},
{
status: ExtendedDocumentStatus.PENDING,
Recipient: {
recipients: {
some: {
email: user.email,
signingStatus: SigningStatus.SIGNED,
@@ -378,7 +378,7 @@ const findDocumentsFilter = (status: ExtendedDocumentStatus, user: User) => {
},
{
status: ExtendedDocumentStatus.COMPLETED,
Recipient: {
recipients: {
some: {
email: user.email,
},
@@ -443,7 +443,7 @@ const findTeamDocumentsFilter = (
status: {
not: ExtendedDocumentStatus.DRAFT,
},
Recipient: {
recipients: {
some: {
email: teamEmail,
},
@@ -453,7 +453,7 @@ const findTeamDocumentsFilter = (
// Filter to display all documents that have been sent by the team email.
filter.OR.push({
User: {
user: {
email: teamEmail,
},
OR: visibilityFilters,
@@ -472,7 +472,7 @@ const findTeamDocumentsFilter = (
status: {
not: ExtendedDocumentStatus.DRAFT,
},
Recipient: {
recipients: {
some: {
email: teamEmail,
signingStatus: SigningStatus.NOT_SIGNED,
@@ -498,7 +498,7 @@ const findTeamDocumentsFilter = (
if (teamEmail && filter.OR) {
filter.OR.push({
status: ExtendedDocumentStatus.DRAFT,
User: {
user: {
email: teamEmail,
},
OR: visibilityFilters,
@@ -523,7 +523,7 @@ const findTeamDocumentsFilter = (
status: ExtendedDocumentStatus.PENDING,
OR: [
{
Recipient: {
recipients: {
some: {
email: teamEmail,
signingStatus: SigningStatus.SIGNED,
@@ -535,7 +535,7 @@ const findTeamDocumentsFilter = (
OR: visibilityFilters,
},
{
User: {
user: {
email: teamEmail,
},
OR: visibilityFilters,
@@ -560,7 +560,7 @@ const findTeamDocumentsFilter = (
if (teamEmail && filter.OR) {
filter.OR.push(
{
Recipient: {
recipients: {
some: {
email: teamEmail,
},
@@ -568,7 +568,7 @@ const findTeamDocumentsFilter = (
OR: visibilityFilters,
},
{
User: {
user: {
email: teamEmail,
},
OR: visibilityFilters,

View File

@@ -26,14 +26,14 @@ export const getDocumentById = async ({ documentId, userId, teamId }: GetDocumen
include: {
documentData: true,
documentMeta: true,
User: {
user: {
select: {
id: true,
name: true,
email: true,
},
},
Recipient: {
recipients: {
select: {
email: true,
},
@@ -119,14 +119,14 @@ export const getDocumentWhereInput = async ({
if (team.teamEmail) {
documentWhereInput.OR.push(
{
Recipient: {
recipients: {
some: {
email: team.teamEmail.email,
},
},
},
{
User: {
user: {
email: team.teamEmail.email,
},
},
@@ -154,7 +154,7 @@ export const getDocumentWhereInput = async ({
{
OR: [
{
Recipient: {
recipients: {
some: {
email: user.email,
},

View File

@@ -41,7 +41,7 @@ export const getDocumentByToken = async ({ token }: GetDocumentByTokenOptions) =
const result = await prisma.document.findFirstOrThrow({
where: {
Recipient: {
recipients: {
some: {
token,
},
@@ -66,17 +66,17 @@ export const getDocumentAndSenderByToken = async ({
const result = await prisma.document.findFirstOrThrow({
where: {
Recipient: {
recipients: {
some: {
token,
},
},
},
include: {
User: true,
user: true,
documentData: true,
documentMeta: true,
Recipient: {
recipients: {
where: {
token,
},
@@ -96,9 +96,9 @@ export const getDocumentAndSenderByToken = async ({
});
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
const { password: _password, ...User } = result.User;
const { password: _password, ...user } = result.user;
const recipient = result.Recipient[0];
const recipient = result.recipients[0];
// Sanity check, should not be possible.
if (!recipient) {
@@ -125,7 +125,7 @@ export const getDocumentAndSenderByToken = async ({
return {
...result,
User,
user,
};
};
@@ -144,14 +144,14 @@ export const getDocumentAndRecipientByToken = async ({
const result = await prisma.document.findFirstOrThrow({
where: {
Recipient: {
recipients: {
some: {
token,
},
},
},
include: {
Recipient: {
recipients: {
where: {
token,
},
@@ -160,7 +160,7 @@ export const getDocumentAndRecipientByToken = async ({
},
});
const [recipient] = result.Recipient;
const [recipient] = result.recipients;
// Sanity check, should not be possible.
if (!recipient) {
@@ -185,8 +185,5 @@ export const getDocumentAndRecipientByToken = async ({
});
}
return {
...result,
Recipient: result.Recipient,
};
return result;
};

View File

@@ -21,8 +21,8 @@ export type GetDocumentWithDetailsByIdOptions = {
export const ZGetDocumentWithDetailsByIdResponseSchema = DocumentSchema.extend({
documentData: DocumentDataSchema,
documentMeta: DocumentMetaSchema.nullable(),
Recipient: RecipientSchema.array(),
Field: FieldSchema.array(),
recipients: RecipientSchema.array(),
fields: FieldSchema.array(),
});
export type TGetDocumentWithDetailsByIdResponse = z.infer<
@@ -45,8 +45,8 @@ export const getDocumentWithDetailsById = async ({
include: {
documentData: true,
documentMeta: true,
Recipient: true,
Field: true,
recipients: true,
fields: true,
},
});

View File

@@ -85,8 +85,8 @@ const getCounts = async ({ user, createdAt, search }: GetCountsOption) => {
const searchFilter: Prisma.DocumentWhereInput = {
OR: [
{ title: { contains: search, mode: 'insensitive' } },
{ Recipient: { some: { name: { contains: search, mode: 'insensitive' } } } },
{ Recipient: { some: { email: { contains: search, mode: 'insensitive' } } } },
{ recipients: { some: { name: { contains: search, mode: 'insensitive' } } } },
{ recipients: { some: { email: { contains: search, mode: 'insensitive' } } } },
],
};
@@ -113,7 +113,7 @@ const getCounts = async ({ user, createdAt, search }: GetCountsOption) => {
},
where: {
status: ExtendedDocumentStatus.PENDING,
Recipient: {
recipients: {
some: {
email: user.email,
signingStatus: SigningStatus.NOT_SIGNED,
@@ -132,7 +132,7 @@ const getCounts = async ({ user, createdAt, search }: GetCountsOption) => {
},
where: {
createdAt,
User: {
user: {
email: {
not: user.email,
},
@@ -140,7 +140,7 @@ const getCounts = async ({ user, createdAt, search }: GetCountsOption) => {
OR: [
{
status: ExtendedDocumentStatus.PENDING,
Recipient: {
recipients: {
some: {
email: user.email,
signingStatus: SigningStatus.SIGNED,
@@ -150,7 +150,7 @@ const getCounts = async ({ user, createdAt, search }: GetCountsOption) => {
},
{
status: ExtendedDocumentStatus.COMPLETED,
Recipient: {
recipients: {
some: {
email: user.email,
signingStatus: SigningStatus.SIGNED,
@@ -191,8 +191,8 @@ const getTeamCounts = async (options: GetTeamCountsOption) => {
const searchFilter: Prisma.DocumentWhereInput = {
OR: [
{ title: { contains: options.search, mode: 'insensitive' } },
{ Recipient: { some: { name: { contains: options.search, mode: 'insensitive' } } } },
{ Recipient: { some: { email: { contains: options.search, mode: 'insensitive' } } } },
{ recipients: { some: { name: { contains: options.search, mode: 'insensitive' } } } },
{ recipients: { some: { email: { contains: options.search, mode: 'insensitive' } } } },
],
};
@@ -234,7 +234,7 @@ const getTeamCounts = async (options: GetTeamCountsOption) => {
{
OR: [
{ userId: options.userId },
{ Recipient: { some: { email: options.currentUserEmail } } },
{ recipients: { some: { email: options.currentUserEmail } } },
],
},
],
@@ -257,7 +257,7 @@ const getTeamCounts = async (options: GetTeamCountsOption) => {
teamId,
},
{
User: {
user: {
email: teamEmail,
},
},
@@ -274,7 +274,7 @@ const getTeamCounts = async (options: GetTeamCountsOption) => {
userId: userIdWhereClause,
createdAt,
status: ExtendedDocumentStatus.PENDING,
Recipient: {
recipients: {
some: {
email: teamEmail,
signingStatus: SigningStatus.NOT_SIGNED,
@@ -296,7 +296,7 @@ const getTeamCounts = async (options: GetTeamCountsOption) => {
OR: [
{
status: ExtendedDocumentStatus.PENDING,
Recipient: {
recipients: {
some: {
email: teamEmail,
signingStatus: SigningStatus.SIGNED,
@@ -307,7 +307,7 @@ const getTeamCounts = async (options: GetTeamCountsOption) => {
},
{
status: ExtendedDocumentStatus.COMPLETED,
Recipient: {
recipients: {
some: {
email: teamEmail,
signingStatus: SigningStatus.SIGNED,

View File

@@ -6,7 +6,10 @@ import { prisma } from '@documenso/prisma';
import { WebhookTriggerEvents } from '@documenso/prisma/client';
import { DOCUMENT_AUDIT_LOG_TYPE } from '../../types/document-audit-logs';
import { ZWebhookDocumentSchema } from '../../types/webhook-payload';
import {
ZWebhookDocumentSchema,
mapDocumentToWebhookDocumentPayload,
} from '../../types/webhook-payload';
import type { RequestMetadata } from '../../universal/extract-request-metadata';
import { createDocumentAuditLogData } from '../../utils/document-audit-logs';
import { triggerWebhook } from '../webhooks/trigger/trigger-webhook';
@@ -31,17 +34,17 @@ export async function rejectDocumentWithToken({
documentId,
},
include: {
Document: {
document: {
include: {
User: true,
Recipient: true,
user: true,
recipients: true,
documentMeta: true,
},
},
},
});
const document = recipient?.Document;
const document = recipient?.document;
if (!recipient || !document) {
throw new TRPCError({
@@ -97,7 +100,7 @@ export async function rejectDocumentWithToken({
id: document.id,
},
include: {
Recipient: true,
recipients: true,
documentMeta: true,
},
});
@@ -109,7 +112,7 @@ export async function rejectDocumentWithToken({
// Trigger webhook for document rejection
await triggerWebhook({
event: WebhookTriggerEvents.DOCUMENT_REJECTED,
data: ZWebhookDocumentSchema.parse(updatedDocument),
data: ZWebhookDocumentSchema.parse(mapDocumentToWebhookDocumentPayload(updatedDocument)),
userId: document.userId,
teamId: document.teamId ?? undefined,
});

View File

@@ -54,7 +54,7 @@ export const resendDocument = async ({
const document = await prisma.document.findUnique({
where: documentWhereInput,
include: {
Recipient: {
recipients: {
where: {
id: {
in: recipients,
@@ -80,7 +80,7 @@ export const resendDocument = async ({
throw new Error('Document not found');
}
if (document.Recipient.length === 0) {
if (document.recipients.length === 0) {
throw new Error('Document has no recipients');
}
@@ -101,7 +101,7 @@ export const resendDocument = async ({
}
await Promise.all(
document.Recipient.map(async (recipient) => {
document.recipients.map(async (recipient) => {
if (recipient.role === RecipientRole.CC) {
return;
}

View File

@@ -14,7 +14,10 @@ import {
} from '@documenso/prisma/client';
import { signPdf } from '@documenso/signing';
import { ZWebhookDocumentSchema } from '../../types/webhook-payload';
import {
ZWebhookDocumentSchema,
mapDocumentToWebhookDocumentPayload,
} from '../../types/webhook-payload';
import type { RequestMetadata } from '../../universal/extract-request-metadata';
import { getFile } from '../../universal/upload/get-file';
import { putPdfFile } from '../../universal/upload/put-file';
@@ -43,7 +46,7 @@ export const sealDocument = async ({
const document = await prisma.document.findFirstOrThrow({
where: {
id: documentId,
Recipient: {
recipients: {
every: {
signingStatus: SigningStatus.SIGNED,
},
@@ -52,7 +55,7 @@ export const sealDocument = async ({
include: {
documentData: true,
documentMeta: true,
Recipient: true,
recipients: true,
team: {
select: {
teamGlobalSettings: {
@@ -89,7 +92,7 @@ export const sealDocument = async ({
documentId: document.id,
},
include: {
Signature: true,
signature: true,
},
});
@@ -206,13 +209,13 @@ export const sealDocument = async ({
include: {
documentData: true,
documentMeta: true,
Recipient: true,
recipients: true,
},
});
await triggerWebhook({
event: WebhookTriggerEvents.DOCUMENT_COMPLETED,
data: ZWebhookDocumentSchema.parse(updatedDocument),
data: ZWebhookDocumentSchema.parse(mapDocumentToWebhookDocumentPayload(updatedDocument)),
userId: document.userId,
teamId: document.teamId ?? undefined,
});

View File

@@ -35,7 +35,7 @@ export const searchDocumentsWithKeyword = async ({
deletedAt: null,
},
{
Recipient: {
recipients: {
some: {
email: {
contains: query,
@@ -48,7 +48,7 @@ export const searchDocumentsWithKeyword = async ({
},
{
status: DocumentStatus.COMPLETED,
Recipient: {
recipients: {
some: {
email: user.email,
},
@@ -60,7 +60,7 @@ export const searchDocumentsWithKeyword = async ({
},
{
status: DocumentStatus.PENDING,
Recipient: {
recipients: {
some: {
email: user.email,
},
@@ -91,7 +91,7 @@ export const searchDocumentsWithKeyword = async ({
],
},
include: {
Recipient: true,
recipients: true,
team: {
select: {
url: true,
@@ -140,7 +140,7 @@ export const searchDocumentsWithKeyword = async ({
return canAccessDocument;
})
.map((document) => {
const { Recipient, ...documentWithoutRecipient } = document;
const { recipients, ...documentWithoutRecipient } = document;
let documentPath;
@@ -149,13 +149,13 @@ export const searchDocumentsWithKeyword = async ({
} else if (document.teamId && document.team) {
documentPath = `${formatDocumentsPath(document.team.url)}/${document.id}`;
} else {
documentPath = getSigningLink(Recipient, user);
documentPath = getSigningLink(recipients, user);
}
return {
...documentWithoutRecipient,
path: documentPath,
value: [document.id, document.title, ...document.Recipient.map((r) => r.email)].join(' '),
value: [document.id, document.title, ...document.recipients.map((r) => r.email)].join(' '),
};
});

View File

@@ -32,8 +32,8 @@ export const sendCompletedEmail = async ({ documentId, requestMetadata }: SendDo
include: {
documentData: true,
documentMeta: true,
Recipient: true,
User: true,
recipients: true,
user: true,
team: {
select: {
id: true,
@@ -50,11 +50,11 @@ export const sendCompletedEmail = async ({ documentId, requestMetadata }: SendDo
const isDirectTemplate = document?.source === DocumentSource.TEMPLATE_DIRECT_LINK;
if (document.Recipient.length === 0) {
if (document.recipients.length === 0) {
throw new Error('Document has no recipients');
}
const { User: owner } = document;
const { user: owner } = document;
const completedDocument = await getFile(document.documentData);
@@ -83,7 +83,7 @@ export const sendCompletedEmail = async ({ documentId, requestMetadata }: SendDo
// - Recipient emails are disabled
if (
isOwnerDocumentCompletedEmailEnabled &&
(!document.Recipient.find((recipient) => recipient.email === owner.email) ||
(!document.recipients.find((recipient) => recipient.email === owner.email) ||
!isDocumentCompletedEmailEnabled)
) {
const template = createElement(DocumentCompletedEmailTemplate, {
@@ -150,7 +150,7 @@ export const sendCompletedEmail = async ({ documentId, requestMetadata }: SendDo
}
await Promise.all(
document.Recipient.map(async (recipient) => {
document.recipients.map(async (recipient) => {
const customEmailTemplate = {
'signer.name': recipient.name,
'signer.email': recipient.email,

View File

@@ -23,7 +23,7 @@ export const sendDeleteEmail = async ({ documentId, reason }: SendDeleteEmailOpt
id: documentId,
},
include: {
User: true,
user: true,
documentMeta: true,
team: {
include: {
@@ -45,7 +45,7 @@ export const sendDeleteEmail = async ({ documentId, reason }: SendDeleteEmailOpt
return;
}
const { email, name } = document.User;
const { email, name } = document.user;
const assetBaseUrl = NEXT_PUBLIC_WEBAPP_URL() || 'http://localhost:3000';

View File

@@ -21,7 +21,10 @@ import {
import { jobs } from '../../jobs/client';
import { extractDerivedDocumentEmailSettings } from '../../types/document-email';
import { ZWebhookDocumentSchema } from '../../types/webhook-payload';
import {
ZWebhookDocumentSchema,
mapDocumentToWebhookDocumentPayload,
} from '../../types/webhook-payload';
import { getFile } from '../../universal/upload/get-file';
import { insertFormValuesInPdf } from '../pdf/insert-form-values-in-pdf';
import { triggerWebhook } from '../webhooks/trigger/trigger-webhook';
@@ -36,7 +39,7 @@ export type SendDocumentOptions = {
export const ZSendDocumentResponseSchema = DocumentSchema.extend({
documentMeta: DocumentMetaSchema.nullable(),
Recipient: RecipientSchema.array(),
recipients: RecipientSchema.array(),
});
export type TSendDocumentResponse = z.infer<typeof ZSendDocumentResponseSchema>;
@@ -68,7 +71,7 @@ export const sendDocument = async ({
}),
},
include: {
Recipient: {
recipients: {
orderBy: [{ signingOrder: { sort: 'asc', nulls: 'last' } }, { id: 'asc' }],
},
documentMeta: true,
@@ -80,7 +83,7 @@ export const sendDocument = async ({
throw new Error('Document not found');
}
if (document.Recipient.length === 0) {
if (document.recipients.length === 0) {
throw new Error('Document has no recipients');
}
@@ -90,13 +93,13 @@ export const sendDocument = async ({
const signingOrder = document.documentMeta?.signingOrder || DocumentSigningOrder.PARALLEL;
let recipientsToNotify = document.Recipient;
let recipientsToNotify = document.recipients;
if (signingOrder === DocumentSigningOrder.SEQUENTIAL) {
// Get the currently active recipient.
recipientsToNotify = document.Recipient.filter(
(r) => r.signingStatus === SigningStatus.NOT_SIGNED && r.role !== RecipientRole.CC,
).slice(0, 1);
recipientsToNotify = document.recipients
.filter((r) => r.signingStatus === SigningStatus.NOT_SIGNED && r.role !== RecipientRole.CC)
.slice(0, 1);
// Secondary filter so we aren't resending if the current active recipient has already
// received the document.
@@ -194,7 +197,7 @@ export const sendDocument = async ({
);
}
const allRecipientsHaveNoActionToTake = document.Recipient.every(
const allRecipientsHaveNoActionToTake = document.recipients.every(
(recipient) =>
recipient.role === RecipientRole.CC || recipient.signingStatus === SigningStatus.SIGNED,
);
@@ -215,7 +218,7 @@ export const sendDocument = async ({
},
include: {
documentMeta: true,
Recipient: true,
recipients: true,
},
});
}
@@ -241,14 +244,14 @@ export const sendDocument = async ({
},
include: {
documentMeta: true,
Recipient: true,
recipients: true,
},
});
});
await triggerWebhook({
event: WebhookTriggerEvents.DOCUMENT_SENT,
data: ZWebhookDocumentSchema.parse(updatedDocument),
data: ZWebhookDocumentSchema.parse(mapDocumentToWebhookDocumentPayload(updatedDocument)),
userId,
teamId,
});

View File

@@ -21,14 +21,14 @@ export const sendPendingEmail = async ({ documentId, recipientId }: SendPendingE
const document = await prisma.document.findFirst({
where: {
id: documentId,
Recipient: {
recipients: {
some: {
id: recipientId,
},
},
},
include: {
Recipient: {
recipients: {
where: {
id: recipientId,
},
@@ -46,7 +46,7 @@ export const sendPendingEmail = async ({ documentId, recipientId }: SendPendingE
throw new Error('Document not found');
}
if (document.Recipient.length === 0) {
if (document.recipients.length === 0) {
throw new Error('Document has no recipients');
}
@@ -58,7 +58,7 @@ export const sendPendingEmail = async ({ documentId, recipientId }: SendPendingE
return;
}
const [recipient] = document.Recipient;
const [recipient] = document.recipients;
const { email, name } = recipient;

View File

@@ -30,9 +30,9 @@ export const superDeleteDocument = async ({ id, requestMetadata }: SuperDeleteDo
id,
},
include: {
Recipient: true,
recipients: true,
documentMeta: true,
User: true,
user: true,
team: {
include: {
teamGlobalSettings: true,
@@ -45,7 +45,7 @@ export const superDeleteDocument = async ({ id, requestMetadata }: SuperDeleteDo
throw new Error('Document not found');
}
const { status, User: user } = document;
const { status, user } = document;
const isDocumentDeletedEmailEnabled = extractDerivedDocumentEmailSettings(
document.documentMeta,
@@ -54,11 +54,11 @@ export const superDeleteDocument = async ({ id, requestMetadata }: SuperDeleteDo
// if the document is pending, send cancellation emails to all recipients
if (
status === DocumentStatus.PENDING &&
document.Recipient.length > 0 &&
document.recipients.length > 0 &&
isDocumentDeletedEmailEnabled
) {
await Promise.all(
document.Recipient.map(async (recipient) => {
document.recipients.map(async (recipient) => {
if (recipient.sendStatus !== SendStatus.SENT) {
return;
}

View File

@@ -6,7 +6,10 @@ import { ReadStatus, SendStatus } from '@documenso/prisma/client';
import { WebhookTriggerEvents } from '@documenso/prisma/client';
import type { TDocumentAccessAuthTypes } from '../../types/document-auth';
import { ZWebhookDocumentSchema } from '../../types/webhook-payload';
import {
ZWebhookDocumentSchema,
mapDocumentToWebhookDocumentPayload,
} from '../../types/webhook-payload';
import { triggerWebhook } from '../webhooks/trigger/trigger-webhook';
export type ViewedDocumentOptions = {
@@ -71,7 +74,7 @@ export const viewedDocument = async ({
},
include: {
documentMeta: true,
Recipient: true,
recipients: true,
},
});
@@ -81,7 +84,7 @@ export const viewedDocument = async ({
await triggerWebhook({
event: WebhookTriggerEvents.DOCUMENT_OPENED,
data: ZWebhookDocumentSchema.parse(document),
data: ZWebhookDocumentSchema.parse(mapDocumentToWebhookDocumentPayload(document)),
userId: document.userId,
teamId: document.teamId ?? undefined,
});

View File

@@ -61,8 +61,8 @@ export const createDocumentFields = async ({
}),
},
include: {
Recipient: true,
Field: true,
recipients: true,
fields: true,
},
});
@@ -80,7 +80,7 @@ export const createDocumentFields = async ({
// Field validation.
const validatedFields = fields.map((field) => {
const recipient = document.Recipient.find((recipient) => recipient.id === field.recipientId);
const recipient = document.recipients.find((recipient) => recipient.id === field.recipientId);
// Each field MUST have a recipient associated with it.
if (!recipient) {
@@ -90,7 +90,7 @@ export const createDocumentFields = async ({
}
// Check whether the recipient associated with the field can have new fields created.
if (!canRecipientFieldsBeModified(recipient, document.Field)) {
if (!canRecipientFieldsBeModified(recipient, document.fields)) {
throw new AppError(AppErrorCode.INVALID_REQUEST, {
message:
'Recipient type cannot have fields, or they have already interacted with the document.',

View File

@@ -145,7 +145,7 @@ export const createField = async ({
fieldMeta: result.data,
},
include: {
Recipient: true,
recipient: true,
},
});
@@ -160,7 +160,7 @@ export const createField = async ({
},
data: {
fieldId: field.secondaryId,
fieldRecipientEmail: field.Recipient?.email ?? '',
fieldRecipientEmail: field.recipient?.email ?? '',
fieldRecipientId: recipientId,
fieldType: field.type,
},

View File

@@ -56,8 +56,8 @@ export const createTemplateFields = async ({
}),
},
include: {
Recipient: true,
Field: true,
recipients: true,
fields: true,
},
});
@@ -69,7 +69,7 @@ export const createTemplateFields = async ({
// Field validation.
const validatedFields = fields.map((field) => {
const recipient = template.Recipient.find((recipient) => recipient.id === field.recipientId);
const recipient = template.recipients.find((recipient) => recipient.id === field.recipientId);
// Each field MUST have a recipient associated with it.
if (!recipient) {
@@ -79,7 +79,7 @@ export const createTemplateFields = async ({
}
// Check whether the recipient associated with the field can have new fields created.
if (!canRecipientFieldsBeModified(recipient, template.Field)) {
if (!canRecipientFieldsBeModified(recipient, template.fields)) {
throw new AppError(AppErrorCode.INVALID_REQUEST, {
message:
'Recipient type cannot have fields, or they have already interacted with the template.',

View File

@@ -59,12 +59,12 @@ export const deleteDocumentField = async ({
}),
},
include: {
Recipient: {
recipients: {
where: {
id: field.recipientId,
},
include: {
Field: true,
fields: true,
},
},
},
@@ -82,7 +82,7 @@ export const deleteDocumentField = async ({
});
}
const recipient = document.Recipient.find((recipient) => recipient.id === field.recipientId);
const recipient = document.recipients.find((recipient) => recipient.id === field.recipientId);
if (!recipient) {
throw new AppError(AppErrorCode.INVALID_REQUEST, {
@@ -91,7 +91,7 @@ export const deleteDocumentField = async ({
}
// Check whether the recipient associated with the field can have new fields created.
if (!canRecipientFieldsBeModified(recipient, recipient.Field)) {
if (!canRecipientFieldsBeModified(recipient, recipient.fields)) {
throw new AppError(AppErrorCode.INVALID_REQUEST, {
message: 'Recipient has already interacted with the document.',
});

View File

@@ -22,7 +22,7 @@ export const deleteField = async ({
const field = await prisma.field.delete({
where: {
id: fieldId,
Document: {
document: {
id: documentId,
...(teamId
? {
@@ -42,7 +42,7 @@ export const deleteField = async ({
},
},
include: {
Recipient: true,
recipient: true,
},
});
@@ -78,7 +78,7 @@ export const deleteField = async ({
},
data: {
fieldId: field.secondaryId,
fieldRecipientEmail: field.Recipient?.email ?? '',
fieldRecipientEmail: field.recipient?.email ?? '',
fieldRecipientId: field.recipientId ?? -1,
fieldType: field.type,
},

View File

@@ -16,7 +16,7 @@ export const deleteTemplateField = async ({
const field = await prisma.field.findFirst({
where: {
id: fieldId,
Template: teamId
template: teamId
? {
team: {
id: teamId,

View File

@@ -11,14 +11,14 @@ export const getCompletedFieldsForDocument = async ({
return await prisma.field.findMany({
where: {
documentId,
Recipient: {
recipient: {
signingStatus: SigningStatus.SIGNED,
},
inserted: true,
},
include: {
Signature: true,
Recipient: {
signature: true,
recipient: {
select: {
name: true,
email: true,

View File

@@ -8,21 +8,21 @@ export type GetCompletedFieldsForTokenOptions = {
export const getCompletedFieldsForToken = async ({ token }: GetCompletedFieldsForTokenOptions) => {
return await prisma.field.findMany({
where: {
Document: {
Recipient: {
document: {
recipients: {
some: {
token,
},
},
},
Recipient: {
recipient: {
signingStatus: SigningStatus.SIGNED,
},
inserted: true,
},
include: {
Signature: true,
Recipient: {
signature: true,
recipient: {
select: {
name: true,
email: true,

View File

@@ -29,7 +29,7 @@ export const getFieldById = async ({
id: fieldId,
documentId,
templateId,
Document: {
document: {
OR:
teamId === undefined
? [

View File

@@ -16,7 +16,7 @@ export const getFieldsForDocument = async ({
const fields = await prisma.field.findMany({
where: {
documentId,
Document: teamId
document: teamId
? {
team: {
id: teamId,
@@ -33,8 +33,8 @@ export const getFieldsForDocument = async ({
},
},
include: {
Signature: true,
Recipient: {
signature: true,
recipient: {
select: {
name: true,
email: true,

View File

@@ -7,12 +7,12 @@ export type GetFieldsForTokenOptions = {
export const getFieldsForToken = async ({ token }: GetFieldsForTokenOptions) => {
return await prisma.field.findMany({
where: {
Recipient: {
recipient: {
token,
},
},
include: {
Signature: true,
signature: true,
},
});
};

View File

@@ -20,17 +20,17 @@ export const removeSignedFieldWithToken = async ({
const field = await prisma.field.findFirstOrThrow({
where: {
id: fieldId,
Recipient: {
recipient: {
token,
},
},
include: {
Document: true,
Recipient: true,
document: true,
recipient: true,
},
});
const { Document: document, Recipient: recipient } = field;
const { document, recipient } = field;
if (!document) {
throw new Error(`Document not found for field ${field.id}`);

View File

@@ -70,7 +70,7 @@ export const setFieldsForDocument = async ({
}),
},
include: {
Recipient: true,
recipients: true,
},
});
@@ -91,7 +91,7 @@ export const setFieldsForDocument = async ({
documentId,
},
include: {
Recipient: true,
recipient: true,
},
});
@@ -102,7 +102,7 @@ export const setFieldsForDocument = async ({
const linkedFields = fields.map((field) => {
const existing = existingFields.find((existingField) => existingField.id === field.id);
const recipient = document.Recipient.find(
const recipient = document.recipients.find(
(recipient) => recipient.email.toLowerCase() === field.signerEmail.toLowerCase(),
);
@@ -237,12 +237,12 @@ export const setFieldsForDocument = async ({
customText: '',
inserted: false,
fieldMeta: parsedFieldMeta,
Document: {
document: {
connect: {
id: documentId,
},
},
Recipient: {
recipient: {
connect: {
documentId_email: {
documentId,
@@ -318,7 +318,7 @@ export const setFieldsForDocument = async ({
metadata: requestMetadata,
data: {
fieldId: field.secondaryId,
fieldRecipientEmail: field.Recipient?.email ?? '',
fieldRecipientEmail: field.recipient?.email ?? '',
fieldRecipientId: field.recipientId ?? -1,
fieldType: field.type,
},

View File

@@ -77,7 +77,7 @@ export const setFieldsForTemplate = async ({
templateId,
},
include: {
Recipient: true,
recipient: true,
},
});
@@ -182,12 +182,12 @@ export const setFieldsForTemplate = async ({
customText: '',
inserted: false,
fieldMeta: parsedFieldMeta,
Template: {
template: {
connect: {
id: templateId,
},
},
Recipient: {
recipient: {
connect: {
templateId_email: {
templateId,

View File

@@ -59,17 +59,17 @@ export const signFieldWithToken = async ({
const field = await prisma.field.findFirstOrThrow({
where: {
id: fieldId,
Recipient: {
recipient: {
token,
},
},
include: {
Document: true,
Recipient: true,
document: true,
recipient: true,
},
});
const { Document: document, Recipient: recipient } = field;
const { document, recipient } = field;
if (!document) {
throw new Error(`Document not found for field ${field.id}`);
@@ -213,7 +213,7 @@ export const signFieldWithToken = async ({
// Dirty but I don't want to deal with type information
Object.assign(updatedField, {
Signature: signature,
signature,
});
}

View File

@@ -64,8 +64,8 @@ export const updateDocumentFields = async ({
}),
},
include: {
Recipient: true,
Field: true,
recipients: true,
fields: true,
},
});
@@ -82,7 +82,7 @@ export const updateDocumentFields = async ({
}
const fieldsToUpdate = fields.map((field) => {
const originalField = document.Field.find((existingField) => existingField.id === field.id);
const originalField = document.fields.find((existingField) => existingField.id === field.id);
if (!originalField) {
throw new AppError(AppErrorCode.NOT_FOUND, {
@@ -90,7 +90,7 @@ export const updateDocumentFields = async ({
});
}
const recipient = document.Recipient.find(
const recipient = document.recipients.find(
(recipient) => recipient.id === originalField.recipientId,
);
@@ -102,7 +102,7 @@ export const updateDocumentFields = async ({
}
// Check whether the recipient associated with the field can be modified.
if (!canRecipientFieldsBeModified(recipient, document.Field)) {
if (!canRecipientFieldsBeModified(recipient, document.fields)) {
throw new AppError(AppErrorCode.INVALID_REQUEST, {
message:
'Cannot modify a field where the recipient has already interacted with the document',

View File

@@ -44,7 +44,7 @@ export const updateField = async ({
const oldField = await prisma.field.findFirstOrThrow({
where: {
id: fieldId,
Document: {
document: {
id: documentId,
...(teamId
? {
@@ -86,7 +86,7 @@ export const updateField = async ({
fieldMeta: newFieldMeta,
},
include: {
Recipient: true,
recipient: true,
},
});
@@ -127,7 +127,7 @@ export const updateField = async ({
},
data: {
fieldId: updatedField.secondaryId,
fieldRecipientEmail: updatedField.Recipient?.email ?? '',
fieldRecipientEmail: updatedField.recipient?.email ?? '',
fieldRecipientId: recipientId ?? -1,
fieldType: updatedField.type,
changes: diffFieldChanges(oldField, updatedField),

View File

@@ -56,8 +56,8 @@ export const updateTemplateFields = async ({
}),
},
include: {
Recipient: true,
Field: true,
recipients: true,
fields: true,
},
});
@@ -68,7 +68,7 @@ export const updateTemplateFields = async ({
}
const fieldsToUpdate = fields.map((field) => {
const originalField = template.Field.find((existingField) => existingField.id === field.id);
const originalField = template.fields.find((existingField) => existingField.id === field.id);
if (!originalField) {
throw new AppError(AppErrorCode.NOT_FOUND, {
@@ -76,7 +76,7 @@ export const updateTemplateFields = async ({
});
}
const recipient = template.Recipient.find(
const recipient = template.recipients.find(
(recipient) => recipient.id === originalField.recipientId,
);
@@ -88,7 +88,7 @@ export const updateTemplateFields = async ({
}
// Check whether the recipient associated with the field can be modified.
if (!canRecipientFieldsBeModified(recipient, template.Field)) {
if (!canRecipientFieldsBeModified(recipient, template.fields)) {
throw new AppError(AppErrorCode.INVALID_REQUEST, {
message:
'Cannot modify a field where the recipient has already interacted with the document',

View File

@@ -98,8 +98,8 @@ export const insertFieldInPDF = async (pdf: PDFDocument, field: FieldWithSignatu
type: P.union(FieldType.SIGNATURE, FieldType.FREE_SIGNATURE),
},
async (field) => {
if (field.Signature?.signatureImageAsBase64) {
const image = await pdf.embedPng(field.Signature?.signatureImageAsBase64 ?? '');
if (field.signature?.signatureImageAsBase64) {
const image = await pdf.embedPng(field.signature?.signatureImageAsBase64 ?? '');
let imageWidth = image.width;
let imageHeight = image.height;
@@ -136,7 +136,7 @@ export const insertFieldInPDF = async (pdf: PDFDocument, field: FieldWithSignatu
rotate: degrees(pageRotationInDegrees),
});
} else {
const signatureText = field.Signature?.typedSignature ?? '';
const signatureText = field.signature?.typedSignature ?? '';
const longestLineInTextForWidth = signatureText
.split('\n')

View File

@@ -61,7 +61,7 @@ export const getPublicProfileByUrl = async ({
},
include: {
profile: true,
Template: {
templates: {
where: {
directLink: {
enabled: true,
@@ -73,7 +73,7 @@ export const getPublicProfileByUrl = async ({
},
},
// Subscriptions and teamMembers are used to calculate the badges.
Subscription: {
subscriptions: {
where: {
status: SubscriptionStatus.ACTIVE,
},
@@ -133,7 +133,7 @@ export const getPublicProfileByUrl = async ({
if (IS_BILLING_ENABLED()) {
const earlyAdopterPriceIds = await getCommunityPlanPriceIds();
const activeEarlyAdopterSub = user.Subscription.find(
const activeEarlyAdopterSub = user.subscriptions.find(
(subscription) =>
subscription.status === SubscriptionStatus.ACTIVE &&
earlyAdopterPriceIds.includes(subscription.priceId),
@@ -154,7 +154,7 @@ export const getPublicProfileByUrl = async ({
url: profileUrl,
avatarImageId: user.avatarImageId,
name: user.name || '',
templates: user.Template.filter(
templates: user.templates.filter(
(template): template is PublicDirectLinkTemplate =>
template.directLink?.enabled === true && template.type === TemplateType.PUBLIC,
),

View File

@@ -7,14 +7,14 @@ export const getUserByApiToken = async ({ token }: { token: string }) => {
const user = await prisma.user.findFirst({
where: {
ApiToken: {
apiTokens: {
some: {
token: hashedToken,
},
},
},
include: {
ApiToken: true,
apiTokens: true,
},
});
@@ -22,7 +22,7 @@ export const getUserByApiToken = async ({ token }: { token: string }) => {
throw new Error('Invalid token');
}
const retrievedToken = user.ApiToken.find((apiToken) => apiToken.token === hashedToken);
const retrievedToken = user.apiTokens.find((apiToken) => apiToken.token === hashedToken);
// This should be impossible but we need to satisfy TypeScript
if (!retrievedToken) {

View File

@@ -65,7 +65,7 @@ export const createDocumentRecipients = async ({
}),
},
include: {
Recipient: true,
recipients: true,
},
});
@@ -103,7 +103,7 @@ export const createDocumentRecipients = async ({
}));
const duplicateRecipients = normalizedRecipients.filter((newRecipient) => {
const existingRecipient = document.Recipient.find(
const existingRecipient = document.recipients.find(
(existingRecipient) => existingRecipient.email === newRecipient.email,
);

View File

@@ -60,7 +60,7 @@ export const createTemplateRecipients = async ({
}),
},
include: {
Recipient: true,
recipients: true,
},
});
@@ -92,7 +92,7 @@ export const createTemplateRecipients = async ({
}));
const duplicateRecipients = normalizedRecipients.filter((newRecipient) => {
const existingRecipient = template.Recipient.find(
const existingRecipient = template.recipients.find(
(existingRecipient) => existingRecipient.email === newRecipient.email,
);

View File

@@ -32,7 +32,7 @@ export const deleteDocumentRecipient = async ({
}: DeleteDocumentRecipientOptions): Promise<void> => {
const document = await prisma.document.findFirst({
where: {
Recipient: {
recipients: {
some: {
id: recipientId,
},
@@ -56,7 +56,7 @@ export const deleteDocumentRecipient = async ({
include: {
documentMeta: true,
team: true,
Recipient: {
recipients: {
where: {
id: recipientId,
},
@@ -93,7 +93,7 @@ export const deleteDocumentRecipient = async ({
});
}
const recipientToDelete = document.Recipient[0];
const recipientToDelete = document.recipients[0];
if (!recipientToDelete || recipientToDelete.id !== recipientId) {
throw new AppError(AppErrorCode.NOT_FOUND, {

View File

@@ -23,7 +23,7 @@ export const deleteRecipient = async ({
const recipient = await prisma.recipient.findFirst({
where: {
id: recipientId,
Document: {
document: {
id: documentId,
...(teamId
? {

View File

@@ -15,7 +15,7 @@ export const deleteTemplateRecipient = async ({
}: DeleteTemplateRecipientOptions): Promise<void> => {
const template = await prisma.template.findFirst({
where: {
Recipient: {
recipients: {
some: {
id: recipientId,
},
@@ -37,7 +37,7 @@ export const deleteTemplateRecipient = async ({
}),
},
include: {
Recipient: {
recipients: {
where: {
id: recipientId,
},
@@ -51,7 +51,7 @@ export const deleteTemplateRecipient = async ({
});
}
const recipientToDelete = template.Recipient[0];
const recipientToDelete = template.recipients[0];
if (!recipientToDelete || recipientToDelete.id !== recipientId) {
throw new AppError(AppErrorCode.NOT_FOUND, {

View File

@@ -8,7 +8,7 @@ export type GetIsRecipientTurnOptions = {
export async function getIsRecipientsTurnToSign({ token }: GetIsRecipientTurnOptions) {
const document = await prisma.document.findFirstOrThrow({
where: {
Recipient: {
recipients: {
some: {
token,
},
@@ -16,7 +16,7 @@ export async function getIsRecipientsTurnToSign({ token }: GetIsRecipientTurnOpt
},
include: {
documentMeta: true,
Recipient: {
recipients: {
orderBy: {
signingOrder: 'asc',
},
@@ -28,7 +28,7 @@ export async function getIsRecipientsTurnToSign({ token }: GetIsRecipientTurnOpt
return true;
}
const recipients = document.Recipient;
const { recipients } = document;
const currentRecipientIndex = recipients.findIndex((r) => r.token === token);

View File

@@ -12,7 +12,7 @@ export type GetRecipientByIdOptions = {
};
export const ZGetRecipientByIdResponseSchema = RecipientSchema.extend({
Field: FieldSchema.array(),
fields: FieldSchema.array(),
});
export type TGetRecipientByIdResponse = z.infer<typeof ZGetRecipientByIdResponseSchema>;
@@ -29,7 +29,7 @@ export const getRecipientById = async ({
const recipient = await prisma.recipient.findFirst({
where: {
id: recipientId,
Document: teamId
document: teamId
? {
team: {
id: teamId,
@@ -46,7 +46,7 @@ export const getRecipientById = async ({
},
},
include: {
Field: true,
fields: true,
},
});

View File

@@ -7,7 +7,7 @@ export type GetRecipientSignaturesOptions = {
export const getRecipientSignatures = async ({ recipientId }: GetRecipientSignaturesOptions) => {
return await prisma.signature.findMany({
where: {
Field: {
field: {
recipientId,
},
},

View File

@@ -14,7 +14,7 @@ export const getRecipientsForDocument = async ({
const recipients = await prisma.recipient.findMany({
where: {
documentId,
Document: teamId
document: teamId
? {
team: {
id: teamId,

View File

@@ -14,7 +14,7 @@ export const getRecipientsForTemplate = async ({
const recipients = await prisma.recipient.findMany({
where: {
templateId,
Template: teamId
template: teamId
? {
team: {
id: teamId,

View File

@@ -75,7 +75,7 @@ export const setDocumentRecipients = async ({
}),
},
include: {
Field: true,
fields: true,
documentMeta: true,
team: {
include: {
@@ -148,7 +148,7 @@ export const setDocumentRecipients = async ({
if (
existing &&
hasRecipientBeenChanged(existing, recipient) &&
!canRecipientBeModified(existing, document.Field)
!canRecipientBeModified(existing, document.fields)
) {
throw new AppError(AppErrorCode.INVALID_REQUEST, {
message: 'Cannot modify a recipient who has already interacted with the document',

View File

@@ -65,8 +65,8 @@ export const updateDocumentRecipients = async ({
}),
},
include: {
Field: true,
Recipient: true,
fields: true,
recipients: true,
},
});
@@ -99,7 +99,7 @@ export const updateDocumentRecipients = async ({
}
const recipientsToUpdate = recipients.map((recipient) => {
const originalRecipient = document.Recipient.find(
const originalRecipient = document.recipients.find(
(existingRecipient) => existingRecipient.id === recipient.id,
);
@@ -109,7 +109,7 @@ export const updateDocumentRecipients = async ({
});
}
const duplicateRecipientWithSameEmail = document.Recipient.find(
const duplicateRecipientWithSameEmail = document.recipients.find(
(existingRecipient) =>
existingRecipient.email === recipient.email && existingRecipient.id !== recipient.id,
);
@@ -122,7 +122,7 @@ export const updateDocumentRecipients = async ({
if (
hasRecipientBeenChanged(originalRecipient, recipient) &&
!canRecipientBeModified(originalRecipient, document.Field)
!canRecipientBeModified(originalRecipient, document.fields)
) {
throw new AppError(AppErrorCode.INVALID_REQUEST, {
message: 'Cannot modify a recipient who has already interacted with the document',
@@ -172,7 +172,7 @@ export const updateDocumentRecipients = async ({
authOptions,
},
include: {
Field: true,
fields: true,
},
});

View File

@@ -40,7 +40,7 @@ export const updateRecipient = async ({
const recipient = await prisma.recipient.findFirst({
where: {
id: recipientId,
Document: {
document: {
id: documentId,
...(teamId
? {
@@ -60,7 +60,7 @@ export const updateRecipient = async ({
},
},
include: {
Document: true,
document: true,
},
});

View File

@@ -63,7 +63,7 @@ export const updateTemplateRecipients = async ({
}),
},
include: {
Recipient: true,
recipients: true,
},
});
@@ -90,7 +90,7 @@ export const updateTemplateRecipients = async ({
}
const recipientsToUpdate = recipients.map((recipient) => {
const originalRecipient = template.Recipient.find(
const originalRecipient = template.recipients.find(
(existingRecipient) => existingRecipient.id === recipient.id,
);
@@ -100,7 +100,7 @@ export const updateTemplateRecipients = async ({
});
}
const duplicateRecipientWithSameEmail = template.Recipient.find(
const duplicateRecipientWithSameEmail = template.recipients.find(
(existingRecipient) =>
existingRecipient.email === recipient.email && existingRecipient.id !== recipient.id,
);
@@ -157,7 +157,7 @@ export const updateTemplateRecipients = async ({
authOptions,
},
include: {
Field: true,
fields: true,
},
});

View File

@@ -15,7 +15,7 @@ export const getRecipientOrSenderByShareLinkSlug = async ({
const sender = await prisma.user.findFirst({
where: {
Document: { some: { id: documentId } },
documents: { some: { id: documentId } },
email,
},
select: {
@@ -35,7 +35,7 @@ export const getRecipientOrSenderByShareLinkSlug = async ({
email,
},
include: {
Signature: true,
signatures: true,
},
});

View File

@@ -56,7 +56,7 @@ export const createTeam = async ({
id: userId,
},
include: {
Subscription: true,
subscriptions: true,
},
});
@@ -68,7 +68,7 @@ export const createTeam = async ({
prices.map((price) => price.id),
);
isPaymentRequired = !subscriptionsContainsActivePlan(user.Subscription, teamRelatedPriceIds);
isPaymentRequired = !subscriptionsContainsActivePlan(user.subscriptions, teamRelatedPriceIds);
customerId = await createTeamCustomer({
name: user.name ?? teamName,

View File

@@ -57,7 +57,7 @@ export const transferTeamOwnership = async ({ token }: TransferTeamOwnershipOpti
},
},
include: {
Subscription: true,
subscriptions: true,
},
});

View File

@@ -32,7 +32,10 @@ import { DOCUMENT_AUDIT_LOG_TYPE } from '../../types/document-audit-logs';
import type { TRecipientActionAuthTypes } from '../../types/document-auth';
import { DocumentAccessAuth, ZRecipientAuthOptionsSchema } from '../../types/document-auth';
import { ZFieldMetaSchema } from '../../types/field-meta';
import { ZWebhookDocumentSchema } from '../../types/webhook-payload';
import {
ZWebhookDocumentSchema,
mapDocumentToWebhookDocumentPayload,
} from '../../types/webhook-payload';
import type { ApiRequestMetadata } from '../../universal/extract-request-metadata';
import type { CreateDocumentAuditLogDataResponse } from '../../utils/document-audit-logs';
import { createDocumentAuditLogData } from '../../utils/document-audit-logs';
@@ -64,7 +67,7 @@ export type CreateDocumentFromDirectTemplateOptions = {
};
type CreatedDirectRecipientField = {
field: Field & { Signature?: Signature | null };
field: Field & { signature?: Signature | null };
derivedRecipientActionAuth: TRecipientActionAuthTypes | null;
};
@@ -95,15 +98,15 @@ export const createDocumentFromDirectTemplate = async ({
},
},
include: {
Recipient: {
recipients: {
include: {
Field: true,
fields: true,
},
},
directLink: true,
templateDocumentData: true,
templateMeta: true,
User: true,
user: true,
team: {
include: {
teamGlobalSettings: true,
@@ -116,7 +119,7 @@ export const createDocumentFromDirectTemplate = async ({
throw new AppError(AppErrorCode.INVALID_REQUEST, { message: 'Invalid or missing template' });
}
const { Recipient: recipients, directLink, User: templateOwner } = template;
const { recipients, directLink, user: templateOwner } = template;
const directTemplateRecipient = recipients.find(
(recipient) => recipient.id === directLink.directTemplateRecipientId,
@@ -159,7 +162,7 @@ export const createDocumentFromDirectTemplate = async ({
directTemplateRecipient.authOptions,
);
const nonDirectTemplateRecipients = template.Recipient.filter(
const nonDirectTemplateRecipients = template.recipients.filter(
(recipient) => recipient.id !== directTemplateRecipient.id,
);
@@ -173,7 +176,7 @@ export const createDocumentFromDirectTemplate = async ({
// Associate, validate and map to a query every direct template recipient field with the provided fields.
const createDirectRecipientFieldArgs = await Promise.all(
directTemplateRecipient.Field.map(async (templateField) => {
directTemplateRecipient.fields.map(async (templateField) => {
const signedFieldValue = signedFieldValues.find(
(value) => value.fieldId === templateField.id,
);
@@ -268,7 +271,7 @@ export const createDocumentFromDirectTemplate = async ({
globalAccessAuth: templateAuthOptions.globalAccessAuth,
globalActionAuth: templateAuthOptions.globalActionAuth,
}),
Recipient: {
recipients: {
createMany: {
data: nonDirectTemplateRecipients.map((recipient) => {
const authOptions = ZRecipientAuthOptionsSchema.parse(recipient?.authOptions);
@@ -306,7 +309,7 @@ export const createDocumentFromDirectTemplate = async ({
},
},
include: {
Recipient: true,
recipients: true,
team: {
select: {
url: true,
@@ -318,7 +321,7 @@ export const createDocumentFromDirectTemplate = async ({
let nonDirectRecipientFieldsToCreate: Omit<Field, 'id' | 'secondaryId' | 'templateId'>[] = [];
Object.values(nonDirectTemplateRecipients).forEach((templateRecipient) => {
const recipient = document.Recipient.find(
const recipient = document.recipients.find(
(recipient) => recipient.email === templateRecipient.email,
);
@@ -327,7 +330,7 @@ export const createDocumentFromDirectTemplate = async ({
}
nonDirectRecipientFieldsToCreate = nonDirectRecipientFieldsToCreate.concat(
templateRecipient.Field.map((field) => ({
templateRecipient.fields.map((field) => ({
documentId: document.id,
recipientId: recipient.id,
type: field.type,
@@ -366,7 +369,7 @@ export const createDocumentFromDirectTemplate = async ({
sendStatus: SendStatus.SENT,
signedAt: initialRequestTime,
signingOrder: directTemplateRecipient.signingOrder,
Field: {
fields: {
createMany: {
data: directTemplateNonSignatureFields.map(({ templateField, customText }) => ({
documentId: document.id,
@@ -384,7 +387,7 @@ export const createDocumentFromDirectTemplate = async ({
},
},
include: {
Field: true,
fields: true,
},
});
@@ -410,7 +413,7 @@ export const createDocumentFromDirectTemplate = async ({
customText: '',
inserted: true,
fieldMeta: templateField.fieldMeta || Prisma.JsonNull,
Signature: {
signature: {
create: {
recipientId: createdDirectRecipient.id,
signatureImageAsBase64: signature.signatureImageAsBase64,
@@ -419,7 +422,7 @@ export const createDocumentFromDirectTemplate = async ({
},
},
include: {
Signature: true,
signature: true,
},
});
@@ -432,7 +435,7 @@ export const createDocumentFromDirectTemplate = async ({
);
const createdDirectRecipientFields: CreatedDirectRecipientField[] = [
...createdDirectRecipient.Field.map((field) => ({
...createdDirectRecipient.fields.map((field) => ({
field,
derivedRecipientActionAuth: null,
})),
@@ -501,7 +504,7 @@ export const createDocumentFromDirectTemplate = async ({
.with(FieldType.SIGNATURE, FieldType.FREE_SIGNATURE, (type) => ({
type,
data:
field.Signature?.signatureImageAsBase64 || field.Signature?.typedSignature || '',
field.signature?.signatureImageAsBase64 || field.signature?.typedSignature || '',
}))
.with(
FieldType.DATE,
@@ -610,13 +613,13 @@ export const createDocumentFromDirectTemplate = async ({
include: {
documentData: true,
documentMeta: true,
Recipient: true,
recipients: true,
},
});
await triggerWebhook({
event: WebhookTriggerEvents.DOCUMENT_SIGNED,
data: ZWebhookDocumentSchema.parse(createdDocument),
data: ZWebhookDocumentSchema.parse(mapDocumentToWebhookDocumentPayload(createdDocument)),
userId: template.userId,
teamId: template.teamId ?? undefined,
});

View File

@@ -43,8 +43,8 @@ export const createDocumentFromTemplateLegacy = async ({
}),
},
include: {
Recipient: true,
Field: true,
recipients: true,
fields: true,
templateDocumentData: true,
templateMeta: true,
team: {
@@ -76,8 +76,8 @@ export const createDocumentFromTemplateLegacy = async ({
title: template.title,
visibility: template.team?.teamGlobalSettings?.documentVisibility,
documentDataId: documentData.id,
Recipient: {
create: template.Recipient.map((recipient) => ({
recipients: {
create: template.recipients.map((recipient) => ({
email: recipient.email,
name: recipient.name,
role: recipient.role,
@@ -100,7 +100,7 @@ export const createDocumentFromTemplateLegacy = async ({
},
include: {
Recipient: {
recipients: {
orderBy: {
id: 'asc',
},
@@ -110,10 +110,10 @@ export const createDocumentFromTemplateLegacy = async ({
});
await prisma.field.createMany({
data: template.Field.map((field) => {
const recipient = template.Recipient.find((recipient) => recipient.id === field.recipientId);
data: template.fields.map((field) => {
const recipient = template.recipients.find((recipient) => recipient.id === field.recipientId);
const documentRecipient = document.Recipient.find((doc) => doc.email === recipient?.email);
const documentRecipient = document.recipients.find((doc) => doc.email === recipient?.email);
if (!documentRecipient) {
throw new Error('Recipient not found.');
@@ -135,9 +135,9 @@ export const createDocumentFromTemplateLegacy = async ({
});
if (recipients && recipients.length > 0) {
document.Recipient = await Promise.all(
document.recipients = await Promise.all(
recipients.map(async (recipient, index) => {
const existingRecipient = document.Recipient.at(index);
const existingRecipient = document.recipients.at(index);
return await prisma.recipient.upsert({
where: {

View File

@@ -25,7 +25,10 @@ import { DOCUMENT_AUDIT_LOG_TYPE } from '../../types/document-audit-logs';
import { ZRecipientAuthOptionsSchema } from '../../types/document-auth';
import type { TDocumentEmailSettings } from '../../types/document-email';
import { ZFieldMetaSchema } from '../../types/field-meta';
import { ZWebhookDocumentSchema } from '../../types/webhook-payload';
import {
ZWebhookDocumentSchema,
mapDocumentToWebhookDocumentPayload,
} from '../../types/webhook-payload';
import type { ApiRequestMetadata } from '../../universal/extract-request-metadata';
import { createDocumentAuditLogData } from '../../utils/document-audit-logs';
import {
@@ -78,7 +81,7 @@ export type CreateDocumentFromTemplateOptions = {
export const ZCreateDocumentFromTemplateResponseSchema = DocumentSchema.extend({
documentData: DocumentDataSchema,
Recipient: RecipientSchema.array(),
recipients: RecipientSchema.array(),
});
export type TCreateDocumentFromTemplateResponse = z.infer<
@@ -115,9 +118,9 @@ export const createDocumentFromTemplate = async ({
}),
},
include: {
Recipient: {
recipients: {
include: {
Field: true,
fields: true,
},
},
templateDocumentData: true,
@@ -138,7 +141,7 @@ export const createDocumentFromTemplate = async ({
// Check that all the passed in recipient IDs can be associated with a template recipient.
recipients.forEach((recipient) => {
const foundRecipient = template.Recipient.find(
const foundRecipient = template.recipients.find(
(templateRecipient) => templateRecipient.id === recipient.id,
);
@@ -153,12 +156,12 @@ export const createDocumentFromTemplate = async ({
documentAuth: template.authOptions,
});
const finalRecipients: FinalRecipient[] = template.Recipient.map((templateRecipient) => {
const finalRecipients: FinalRecipient[] = template.recipients.map((templateRecipient) => {
const foundRecipient = recipients.find((recipient) => recipient.id === templateRecipient.id);
return {
templateRecipientId: templateRecipient.id,
fields: templateRecipient.Field,
fields: templateRecipient.fields,
name: foundRecipient ? (foundRecipient.name ?? '') : templateRecipient.name,
email: foundRecipient ? foundRecipient.email : templateRecipient.email,
role: templateRecipient.role,
@@ -233,7 +236,7 @@ export const createDocumentFromTemplate = async ({
override?.typedSignatureEnabled ?? template.templateMeta?.typedSignatureEnabled,
},
},
Recipient: {
recipients: {
createMany: {
data: finalRecipients.map((recipient) => {
const authOptions = ZRecipientAuthOptionsSchema.parse(recipient?.authOptions);
@@ -260,7 +263,7 @@ export const createDocumentFromTemplate = async ({
},
},
include: {
Recipient: {
recipients: {
orderBy: {
id: 'asc',
},
@@ -272,7 +275,7 @@ export const createDocumentFromTemplate = async ({
let fieldsToCreate: Omit<Field, 'id' | 'secondaryId' | 'templateId'>[] = [];
Object.values(finalRecipients).forEach(({ email, fields }) => {
const recipient = document.Recipient.find((recipient) => recipient.email === email);
const recipient = document.recipients.find((recipient) => recipient.email === email);
if (!recipient) {
throw new Error('Recipient not found.');
@@ -323,7 +326,7 @@ export const createDocumentFromTemplate = async ({
},
include: {
documentMeta: true,
Recipient: true,
recipients: true,
},
});
@@ -333,7 +336,7 @@ export const createDocumentFromTemplate = async ({
await triggerWebhook({
event: WebhookTriggerEvents.DOCUMENT_CREATED,
data: ZWebhookDocumentSchema.parse(createdDocument),
data: ZWebhookDocumentSchema.parse(mapDocumentToWebhookDocumentPayload(createdDocument)),
userId,
teamId,
});

View File

@@ -52,7 +52,7 @@ export const createTemplateDirectLink = async ({
}),
},
include: {
Recipient: true,
recipients: true,
directLink: true,
},
});
@@ -67,14 +67,14 @@ export const createTemplateDirectLink = async ({
if (
directRecipientId &&
!template.Recipient.find((recipient) => recipient.id === directRecipientId)
!template.recipients.find((recipient) => recipient.id === directRecipientId)
) {
throw new AppError(AppErrorCode.NOT_FOUND, { message: 'Recipient not found' });
}
if (
!directRecipientId &&
template.Recipient.find(
template.recipients.find(
(recipient) => recipient.email.toLowerCase() === DIRECT_TEMPLATE_RECIPIENT_EMAIL,
)
) {

View File

@@ -37,7 +37,7 @@ export const deleteTemplateDirectLink = async ({
},
include: {
directLink: true,
Recipient: true,
recipients: true,
},
});
@@ -60,7 +60,7 @@ export const deleteTemplateDirectLink = async ({
id: directLink.directTemplateRecipientId,
},
data: {
...generateAvaliableRecipientPlaceholder(template.Recipient),
...generateAvaliableRecipientPlaceholder(template.recipients),
},
});

View File

@@ -41,8 +41,8 @@ export const duplicateTemplate = async ({
}),
},
include: {
Recipient: true,
Field: true,
recipients: true,
fields: true,
templateDocumentData: true,
templateMeta: true,
},
@@ -77,8 +77,8 @@ export const duplicateTemplate = async ({
teamId,
title: template.title + ' (copy)',
templateDocumentDataId: documentData.id,
Recipient: {
create: template.Recipient.map((recipient) => ({
recipients: {
create: template.recipients.map((recipient) => ({
email: recipient.email,
name: recipient.name,
token: nanoid(),
@@ -87,15 +87,15 @@ export const duplicateTemplate = async ({
templateMeta,
},
include: {
Recipient: true,
recipients: true,
},
});
await prisma.field.createMany({
data: template.Field.map((field) => {
const recipient = template.Recipient.find((recipient) => recipient.id === field.recipientId);
data: template.fields.map((field) => {
const recipient = template.recipients.find((recipient) => recipient.id === field.recipientId);
const duplicatedTemplateRecipient = duplicatedTemplate.Recipient.find(
const duplicatedTemplateRecipient = duplicatedTemplate.recipients.find(
(doc) => doc.email === recipient?.email,
);

View File

@@ -36,8 +36,8 @@ export const ZFindTemplatesResponseSchema = ZFindResultResponse.extend({
id: true,
url: true,
}).nullable(),
Field: FieldSchema.array(),
Recipient: RecipientSchema.array(),
fields: FieldSchema.array(),
recipients: RecipientSchema.array(),
templateMeta: TemplateMetaSchema.pick({
signingOrder: true,
distributionMethod: true,
@@ -119,8 +119,8 @@ export const findTemplates = async ({
url: true,
},
},
Field: true,
Recipient: true,
fields: true,
recipients: true,
templateMeta: true,
directLink: {
select: {

View File

@@ -16,9 +16,9 @@ export const getTemplateByDirectLinkToken = async ({
},
include: {
directLink: true,
Recipient: {
recipients: {
include: {
Field: true,
fields: true,
},
},
templateDocumentData: true,
@@ -28,6 +28,6 @@ export const getTemplateByDirectLinkToken = async ({
return {
...template,
Field: template.Recipient.map((recipient) => recipient.Field).flat(),
fields: template.recipients.map((recipient) => recipient.fields).flat(),
};
};

View File

@@ -23,9 +23,9 @@ export const ZGetTemplateByIdResponseSchema = TemplateSchema.extend({
directLink: TemplateDirectLinkSchema.nullable(),
templateDocumentData: DocumentDataSchema,
templateMeta: TemplateMetaSchema.nullable(),
Recipient: RecipientSchema.array(),
Field: FieldSchema.array(),
User: UserSchema.pick({
recipients: RecipientSchema.array(),
fields: FieldSchema.array(),
user: UserSchema.pick({
id: true,
name: true,
email: true,
@@ -62,9 +62,9 @@ export const getTemplateById = async ({
directLink: true,
templateDocumentData: true,
templateMeta: true,
Recipient: true,
Field: true,
User: {
recipients: true,
fields: true,
user: {
select: {
id: true,
name: true,

View File

@@ -46,7 +46,7 @@ export const toggleTemplateDirectLink = async ({
}),
},
include: {
Recipient: true,
recipients: true,
directLink: true,
},
});

View File

@@ -11,11 +11,11 @@ export const disableUser = async ({ id }: DisableUserOptions) => {
id,
},
include: {
ApiToken: true,
Webhooks: true,
apiTokens: true,
webhooks: true,
passkeys: true,
VerificationToken: true,
PasswordResetToken: true,
verificationTokens: true,
passwordResetTokens: true,
},
});

View File

@@ -34,8 +34,8 @@ export const findUsers = async ({
const [users, count] = await Promise.all([
prisma.user.findMany({
include: {
Subscription: true,
Document: {
subscriptions: true,
documents: {
select: {
id: true,
},

View File

@@ -24,7 +24,7 @@ export const resetPassword = async ({ token, password, requestMetadata }: ResetP
token,
},
include: {
User: true,
user: true,
},
});
@@ -38,7 +38,7 @@ export const resetPassword = async ({ token, password, requestMetadata }: ResetP
throw new AppError(AppErrorCode.EXPIRED_CODE);
}
const isSamePassword = await compare(password, foundToken.User.password || '');
const isSamePassword = await compare(password, foundToken.user.password || '');
if (isSamePassword) {
throw new AppError('SAME_PASSWORD');

View File

@@ -97,6 +97,11 @@ export const ZDropdownFieldMeta = ZBaseFieldMeta.extend({
export type TDropdownFieldMeta = z.infer<typeof ZDropdownFieldMeta>;
/**
* This will parse empty objects to { "type": "initials" }
*
* Todo: Fix.
*/
export const ZFieldMetaSchema = z
.union([
ZBaseFieldMeta.extend(ZInitialsFieldMeta.shape),

View File

@@ -1,5 +1,6 @@
import { z } from 'zod';
import type { Document, DocumentMeta, Recipient } from '@documenso/prisma/client';
import {
DocumentDistributionMethod,
DocumentSigningOrder,
@@ -73,8 +74,36 @@ export const ZWebhookDocumentSchema = z.object({
templateId: z.number().nullable(),
source: z.nativeEnum(DocumentSource),
documentMeta: ZWebhookDocumentMetaSchema.nullable(),
recipients: z.array(ZWebhookRecipientSchema),
/**
* Legacy field for backwards compatibility.
*/
Recipient: z.array(ZWebhookRecipientSchema),
});
export type TWebhookRecipient = z.infer<typeof ZWebhookRecipientSchema>;
export type TWebhookDocument = z.infer<typeof ZWebhookDocumentSchema>;
export const mapDocumentToWebhookDocumentPayload = (
document: Document & {
recipients: Recipient[];
documentMeta: DocumentMeta | null;
},
): TWebhookDocument => {
const { recipients, documentMeta, ...trimmedDocument } = document;
return {
...trimmedDocument,
documentMeta: documentMeta
? {
...documentMeta,
// Not sure why is optional in the prisma schema.
timezone: 'Etc/UTC',
dateFormat: 'yyyy-MM-dd hh:mm a',
}
: null,
Recipient: recipients,
recipients,
};
};

View File

@@ -12,7 +12,7 @@ export const maskRecipientTokensForDocument = <T extends DocumentWithRecipients>
user,
token,
}: MaskRecipientTokensForDocumentOptions<T>) => {
const maskedRecipients = document.Recipient.map((recipient) => {
const maskedRecipients = document.recipients.map((recipient) => {
if (document.userId === user?.id) {
return recipient;
}