mirror of
https://github.com/documenso/documenso.git
synced 2025-11-23 13:11:32 +10:00
fix: refactor prisma relations (#1581)
This commit is contained in:
@ -1,6 +1,5 @@
|
||||
import { createNextRoute } from '@ts-rest/next';
|
||||
import { match } from 'ts-pattern';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { getServerLimits } from '@documenso/ee/server-only/limits/server';
|
||||
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
|
||||
@ -63,7 +62,6 @@ import {
|
||||
|
||||
import { ApiContractV1 } from './contract';
|
||||
import { authenticatedMiddleware } from './middleware/authenticated';
|
||||
import { ZTemplateWithDataSchema } from './schema';
|
||||
|
||||
export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
|
||||
getDocuments: authenticatedMiddleware(async (args, user, team) => {
|
||||
@ -419,11 +417,16 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
|
||||
teamId: team?.id,
|
||||
});
|
||||
|
||||
const parsed = ZTemplateWithDataSchema.parse(template);
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
body: parsed,
|
||||
body: {
|
||||
...template,
|
||||
Field: template.fields.map((field) => ({
|
||||
...field,
|
||||
fieldMeta: field.fieldMeta ? ZFieldMetaSchema.parse(field.fieldMeta) : null,
|
||||
})),
|
||||
Recipient: template.recipients,
|
||||
},
|
||||
};
|
||||
} catch (err) {
|
||||
return AppError.toRestAPIError(err);
|
||||
@ -442,12 +445,17 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
|
||||
teamId: team?.id,
|
||||
});
|
||||
|
||||
const parsed = z.array(ZTemplateWithDataSchema).parse(templates);
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
templates: parsed,
|
||||
templates: templates.map((template) => ({
|
||||
...template,
|
||||
Field: template.fields.map((field) => ({
|
||||
...field,
|
||||
fieldMeta: field.fieldMeta ? ZFieldMetaSchema.parse(field.fieldMeta) : null,
|
||||
})),
|
||||
Recipient: template.recipients,
|
||||
})),
|
||||
totalPages,
|
||||
},
|
||||
};
|
||||
@ -540,7 +548,7 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
|
||||
status: 200,
|
||||
body: {
|
||||
documentId: document.id,
|
||||
recipients: document.Recipient.map((recipient) => ({
|
||||
recipients: document.recipients.map((recipient) => ({
|
||||
recipientId: recipient.id,
|
||||
name: recipient.name,
|
||||
email: recipient.email,
|
||||
@ -634,7 +642,7 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
|
||||
status: 200,
|
||||
body: {
|
||||
documentId: document.id,
|
||||
recipients: document.Recipient.map((recipient) => ({
|
||||
recipients: document.recipients.map((recipient) => ({
|
||||
recipientId: recipient.id,
|
||||
name: recipient.name,
|
||||
email: recipient.email,
|
||||
@ -693,7 +701,7 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
|
||||
});
|
||||
}
|
||||
|
||||
const { Recipient: recipients, ...sentDocument } = await sendDocument({
|
||||
const { recipients, ...sentDocument } = await sendDocument({
|
||||
documentId: document.id,
|
||||
userId: user.id,
|
||||
teamId: team?.id,
|
||||
@ -1074,7 +1082,7 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
|
||||
fieldMeta: result.data,
|
||||
},
|
||||
include: {
|
||||
Recipient: true,
|
||||
recipient: true,
|
||||
},
|
||||
});
|
||||
|
||||
@ -1089,7 +1097,7 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
|
||||
},
|
||||
data: {
|
||||
fieldId: field.secondaryId,
|
||||
fieldRecipientEmail: field.Recipient?.email ?? '',
|
||||
fieldRecipientEmail: field.recipient?.email ?? '',
|
||||
fieldRecipientId: recipientId,
|
||||
fieldType: field.type,
|
||||
},
|
||||
@ -1108,7 +1116,7 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
|
||||
pageWidth: Number(field.width),
|
||||
pageHeight: Number(field.height),
|
||||
customText: field.customText,
|
||||
fieldMeta: ZFieldMetaSchema.parse(field.fieldMeta),
|
||||
fieldMeta: field.fieldMeta ? ZFieldMetaSchema.parse(field.fieldMeta) : undefined,
|
||||
inserted: field.inserted,
|
||||
};
|
||||
}),
|
||||
|
||||
@ -28,7 +28,7 @@ test('[DOCUMENT_AUTH]: should allow signing when no auth setup', async ({ page }
|
||||
|
||||
// Check that both are granted access.
|
||||
for (const recipient of recipients) {
|
||||
const { token, Field } = recipient;
|
||||
const { token, fields } = recipient;
|
||||
|
||||
const signUrl = `/sign/${token}`;
|
||||
|
||||
@ -45,7 +45,7 @@ test('[DOCUMENT_AUTH]: should allow signing when no auth setup', async ({ page }
|
||||
await page.mouse.up();
|
||||
}
|
||||
|
||||
for (const field of Field) {
|
||||
for (const field of fields) {
|
||||
await page.locator(`#field-${field.id}`).getByRole('button').click();
|
||||
|
||||
if (field.type === FieldType.TEXT) {
|
||||
@ -80,7 +80,7 @@ test('[DOCUMENT_AUTH]: should allow signing with valid global auth', async ({ pa
|
||||
|
||||
const recipient = recipients[0];
|
||||
|
||||
const { token, Field } = recipient;
|
||||
const { token, fields } = recipient;
|
||||
|
||||
const signUrl = `/sign/${token}`;
|
||||
|
||||
@ -102,7 +102,7 @@ test('[DOCUMENT_AUTH]: should allow signing with valid global auth', async ({ pa
|
||||
await page.mouse.up();
|
||||
}
|
||||
|
||||
for (const field of Field) {
|
||||
for (const field of fields) {
|
||||
await page.locator(`#field-${field.id}`).getByRole('button').click();
|
||||
|
||||
if (field.type === FieldType.TEXT) {
|
||||
@ -170,12 +170,12 @@ test('[DOCUMENT_AUTH]: should deny signing fields when required for global auth'
|
||||
|
||||
// Check that both are denied access.
|
||||
for (const recipient of recipients) {
|
||||
const { token, Field } = recipient;
|
||||
const { token, fields } = recipient;
|
||||
|
||||
await page.goto(`/sign/${token}`);
|
||||
await expect(page.getByRole('heading', { name: 'Sign Document' })).toBeVisible();
|
||||
|
||||
for (const field of Field) {
|
||||
for (const field of fields) {
|
||||
if (field.type !== FieldType.SIGNATURE) {
|
||||
continue;
|
||||
}
|
||||
@ -229,7 +229,7 @@ test('[DOCUMENT_AUTH]: should allow field signing when required for recipient au
|
||||
});
|
||||
|
||||
for (const recipient of recipients) {
|
||||
const { token, Field } = recipient;
|
||||
const { token, fields } = recipient;
|
||||
const { actionAuth } = ZRecipientAuthOptionsSchema.parse(recipient.authOptions);
|
||||
|
||||
// This document has no global action auth, so only account should require auth.
|
||||
@ -241,7 +241,7 @@ test('[DOCUMENT_AUTH]: should allow field signing when required for recipient au
|
||||
await expect(page.getByRole('heading', { name: 'Sign Document' })).toBeVisible();
|
||||
|
||||
if (isAuthRequired) {
|
||||
for (const field of Field) {
|
||||
for (const field of fields) {
|
||||
if (field.type !== FieldType.SIGNATURE) {
|
||||
continue;
|
||||
}
|
||||
@ -271,7 +271,7 @@ test('[DOCUMENT_AUTH]: should allow field signing when required for recipient au
|
||||
await page.mouse.up();
|
||||
}
|
||||
|
||||
for (const field of Field) {
|
||||
for (const field of fields) {
|
||||
await page.locator(`#field-${field.id}`).getByRole('button').click();
|
||||
|
||||
if (field.type === FieldType.TEXT) {
|
||||
@ -340,7 +340,7 @@ test('[DOCUMENT_AUTH]: should allow field signing when required for recipient an
|
||||
});
|
||||
|
||||
for (const recipient of recipients) {
|
||||
const { token, Field } = recipient;
|
||||
const { token, fields } = recipient;
|
||||
const { actionAuth } = ZRecipientAuthOptionsSchema.parse(recipient.authOptions);
|
||||
|
||||
// This document HAS global action auth, so account and inherit should require auth.
|
||||
@ -352,7 +352,7 @@ test('[DOCUMENT_AUTH]: should allow field signing when required for recipient an
|
||||
await expect(page.getByRole('heading', { name: 'Sign Document' })).toBeVisible();
|
||||
|
||||
if (isAuthRequired) {
|
||||
for (const field of Field) {
|
||||
for (const field of fields) {
|
||||
if (field.type !== FieldType.SIGNATURE) {
|
||||
continue;
|
||||
}
|
||||
@ -382,7 +382,7 @@ test('[DOCUMENT_AUTH]: should allow field signing when required for recipient an
|
||||
await page.mouse.up();
|
||||
}
|
||||
|
||||
for (const field of Field) {
|
||||
for (const field of fields) {
|
||||
await page.locator(`#field-${field.id}`).getByRole('button').click();
|
||||
|
||||
if (field.type === FieldType.TEXT) {
|
||||
|
||||
@ -24,7 +24,7 @@ import { apiSignin } from '../fixtures/authentication';
|
||||
const getDocumentByToken = async (token: string) => {
|
||||
return await prisma.document.findFirstOrThrow({
|
||||
where: {
|
||||
Recipient: {
|
||||
recipients: {
|
||||
some: {
|
||||
token,
|
||||
},
|
||||
@ -357,7 +357,7 @@ test('[DOCUMENT_FLOW]: should be able to approve a document', async ({ page }) =
|
||||
});
|
||||
|
||||
for (const recipient of recipients) {
|
||||
const { token, Field, role } = recipient;
|
||||
const { token, fields, role } = recipient;
|
||||
|
||||
const signUrl = `/sign/${token}`;
|
||||
|
||||
@ -378,7 +378,7 @@ test('[DOCUMENT_FLOW]: should be able to approve a document', async ({ page }) =
|
||||
await page.mouse.up();
|
||||
}
|
||||
|
||||
for (const field of Field) {
|
||||
for (const field of fields) {
|
||||
await page.locator(`#field-${field.id}`).getByRole('button').click();
|
||||
|
||||
await expect(page.locator(`#field-${field.id}`)).toHaveAttribute('data-inserted', 'true');
|
||||
@ -479,8 +479,8 @@ test('[DOCUMENT_FLOW]: should be able to sign a document with custom date', asyn
|
||||
fields: [FieldType.DATE],
|
||||
});
|
||||
|
||||
const { token, Field } = recipients[0];
|
||||
const [recipientField] = Field;
|
||||
const { token, fields } = recipients[0];
|
||||
const [recipientField] = fields;
|
||||
|
||||
await page.goto(`/sign/${token}`);
|
||||
await page.waitForURL(`/sign/${token}`);
|
||||
@ -496,7 +496,7 @@ test('[DOCUMENT_FLOW]: should be able to sign a document with custom date', asyn
|
||||
|
||||
const field = await prisma.field.findFirst({
|
||||
where: {
|
||||
Recipient: {
|
||||
recipient: {
|
||||
email: 'user1@example.com',
|
||||
},
|
||||
documentId: Number(document.id),
|
||||
@ -580,14 +580,14 @@ test('[DOCUMENT_FLOW]: should be able to create and sign a document with 3 recip
|
||||
|
||||
const createdDocument = await prisma.document.findFirst({
|
||||
where: { title: documentTitle },
|
||||
include: { Recipient: true },
|
||||
include: { recipients: true },
|
||||
});
|
||||
|
||||
expect(createdDocument).not.toBeNull();
|
||||
expect(createdDocument?.Recipient.length).toBe(3);
|
||||
expect(createdDocument?.recipients.length).toBe(3);
|
||||
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const recipient = createdDocument?.Recipient.find(
|
||||
const recipient = createdDocument?.recipients.find(
|
||||
(r) => r.email === `user${i + 1}@example.com`,
|
||||
);
|
||||
expect(recipient).not.toBeNull();
|
||||
|
||||
@ -129,7 +129,7 @@ test('[DOCUMENTS]: deleting a pending document should remove it from recipients'
|
||||
// signout
|
||||
await apiSignout({ page });
|
||||
|
||||
for (const recipient of pendingDocument.Recipient) {
|
||||
for (const recipient of pendingDocument.recipients) {
|
||||
await apiSignin({
|
||||
page,
|
||||
email: recipient.email,
|
||||
|
||||
@ -45,7 +45,7 @@ test.describe('Signing Certificate Tests', () => {
|
||||
await page.mouse.up();
|
||||
}
|
||||
|
||||
for (const field of recipient.Field) {
|
||||
for (const field of recipient.fields) {
|
||||
await page.locator(`#field-${field.id}`).getByRole('button').click();
|
||||
|
||||
await expect(page.locator(`#field-${field.id}`)).toHaveAttribute('data-inserted', 'true');
|
||||
@ -122,7 +122,7 @@ test.describe('Signing Certificate Tests', () => {
|
||||
await page.mouse.up();
|
||||
}
|
||||
|
||||
for (const field of recipient.Field) {
|
||||
for (const field of recipient.fields) {
|
||||
await page.locator(`#field-${field.id}`).getByRole('button').click();
|
||||
|
||||
await expect(page.locator(`#field-${field.id}`)).toHaveAttribute('data-inserted', 'true');
|
||||
@ -199,7 +199,7 @@ test.describe('Signing Certificate Tests', () => {
|
||||
await page.mouse.up();
|
||||
}
|
||||
|
||||
for (const field of recipient.Field) {
|
||||
for (const field of recipient.fields) {
|
||||
await page.locator(`#field-${field.id}`).getByRole('button').click();
|
||||
|
||||
await expect(page.locator(`#field-${field.id}`)).toHaveAttribute('data-inserted', 'true');
|
||||
|
||||
@ -124,7 +124,7 @@ test('[TEMPLATE]: should create a document from a template', async ({ page }) =>
|
||||
id: documentId,
|
||||
},
|
||||
include: {
|
||||
Recipient: true,
|
||||
recipients: true,
|
||||
documentMeta: true,
|
||||
},
|
||||
});
|
||||
@ -144,8 +144,8 @@ test('[TEMPLATE]: should create a document from a template', async ({ page }) =>
|
||||
expect(document.documentMeta?.subject).toEqual('SUBJECT');
|
||||
expect(document.documentMeta?.timezone).toEqual('Etc/UTC');
|
||||
|
||||
const recipientOne = document.Recipient[0];
|
||||
const recipientTwo = document.Recipient[1];
|
||||
const recipientOne = document.recipients[0];
|
||||
const recipientTwo = document.recipients[1];
|
||||
|
||||
const recipientOneAuth = extractDocumentAuthMethods({
|
||||
documentAuth: document.authOptions,
|
||||
@ -259,7 +259,7 @@ test('[TEMPLATE]: should create a team document from a team template', async ({
|
||||
id: documentId,
|
||||
},
|
||||
include: {
|
||||
Recipient: true,
|
||||
recipients: true,
|
||||
documentMeta: true,
|
||||
},
|
||||
});
|
||||
@ -281,8 +281,8 @@ test('[TEMPLATE]: should create a team document from a team template', async ({
|
||||
expect(document.documentMeta?.subject).toEqual('SUBJECT');
|
||||
expect(document.documentMeta?.timezone).toEqual('Etc/UTC');
|
||||
|
||||
const recipientOne = document.Recipient[0];
|
||||
const recipientTwo = document.Recipient[1];
|
||||
const recipientOne = document.recipients[0];
|
||||
const recipientTwo = document.recipients[1];
|
||||
|
||||
const recipientOneAuth = extractDocumentAuthMethods({
|
||||
documentAuth: document.authOptions,
|
||||
|
||||
@ -260,7 +260,7 @@ test('[DIRECT_TEMPLATES]: use direct template link with 2 recipients', async ({
|
||||
const secondRecipient = await seedUser();
|
||||
|
||||
const createTemplateOptions = {
|
||||
Recipient: {
|
||||
recipients: {
|
||||
createMany: {
|
||||
data: [
|
||||
{
|
||||
|
||||
@ -43,7 +43,7 @@ const handleUserLimits = async ({ email }: HandleUserLimitsOptions) => {
|
||||
email,
|
||||
},
|
||||
include: {
|
||||
Subscription: true,
|
||||
subscriptions: true,
|
||||
},
|
||||
});
|
||||
|
||||
@ -54,7 +54,7 @@ const handleUserLimits = async ({ email }: HandleUserLimitsOptions) => {
|
||||
let quota = structuredClone(FREE_PLAN_LIMITS);
|
||||
let remaining = structuredClone(FREE_PLAN_LIMITS);
|
||||
|
||||
const activeSubscriptions = user.Subscription.filter(
|
||||
const activeSubscriptions = user.subscriptions.filter(
|
||||
({ status }) => status === SubscriptionStatus.ACTIVE,
|
||||
);
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ type TransferStripeSubscriptionOptions = {
|
||||
/**
|
||||
* The user to transfer the subscription to.
|
||||
*/
|
||||
user: User & { Subscription: Subscription[] };
|
||||
user: User & { subscriptions: Subscription[] };
|
||||
|
||||
/**
|
||||
* The team the subscription is associated with.
|
||||
@ -54,7 +54,7 @@ export const transferTeamSubscription = async ({
|
||||
]);
|
||||
|
||||
const teamSubscriptionRequired = !subscriptionsContainsActivePlan(
|
||||
user.Subscription,
|
||||
user.subscriptions,
|
||||
teamRelatedPlanPriceIds,
|
||||
);
|
||||
|
||||
|
||||
@ -10,7 +10,6 @@ import { createTeamFromPendingTeam } from '@documenso/lib/server-only/team/creat
|
||||
import { getFlag } from '@documenso/lib/universal/get-feature-flag';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
import { onEarlyAdoptersCheckout } from './on-early-adopters-checkout';
|
||||
import { onSubscriptionDeleted } from './on-subscription-deleted';
|
||||
import { onSubscriptionUpdated } from './on-subscription-updated';
|
||||
|
||||
@ -56,10 +55,6 @@ export const stripeWebhookHandler = async (
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
||||
const session = event.data.object as Stripe.Checkout.Session;
|
||||
|
||||
if (session.metadata?.source === 'marketing') {
|
||||
await onEarlyAdoptersCheckout({ session });
|
||||
}
|
||||
|
||||
const customerId =
|
||||
typeof session.customer === 'string' ? session.customer : session.customer?.id;
|
||||
|
||||
|
||||
@ -1,140 +0,0 @@
|
||||
import type Stripe from 'stripe';
|
||||
|
||||
import { hashSync } from '@documenso/lib/server-only/auth/hash';
|
||||
import { sealDocument } from '@documenso/lib/server-only/document/seal-document';
|
||||
import { redis } from '@documenso/lib/server-only/redis';
|
||||
import { stripe } from '@documenso/lib/server-only/stripe';
|
||||
import { alphaid, nanoid } from '@documenso/lib/universal/id';
|
||||
import { putPdfFile } from '@documenso/lib/universal/upload/put-file';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import {
|
||||
DocumentSource,
|
||||
DocumentStatus,
|
||||
FieldType,
|
||||
ReadStatus,
|
||||
SendStatus,
|
||||
SigningStatus,
|
||||
} from '@documenso/prisma/client';
|
||||
|
||||
import { ZEarlyAdopterCheckoutMetadataSchema } from './early-adopter-checkout-metadata';
|
||||
|
||||
export type OnEarlyAdoptersCheckoutOptions = {
|
||||
session: Stripe.Checkout.Session;
|
||||
};
|
||||
|
||||
export const onEarlyAdoptersCheckout = async ({ session }: OnEarlyAdoptersCheckoutOptions) => {
|
||||
try {
|
||||
const safeMetadata = ZEarlyAdopterCheckoutMetadataSchema.safeParse(session.metadata);
|
||||
|
||||
if (!safeMetadata.success) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { email, name, signatureText, signatureDataUrl: signatureDataUrlRef } = safeMetadata.data;
|
||||
|
||||
const user = await prisma.user.findFirst({
|
||||
where: {
|
||||
email: email.toLowerCase(),
|
||||
},
|
||||
});
|
||||
|
||||
if (user) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tempPassword = nanoid(12);
|
||||
|
||||
const newUser = await prisma.user.create({
|
||||
data: {
|
||||
name,
|
||||
email: email.toLowerCase(),
|
||||
password: hashSync(tempPassword),
|
||||
signature: signatureDataUrlRef,
|
||||
},
|
||||
});
|
||||
|
||||
const customerId =
|
||||
typeof session.customer === 'string' ? session.customer : session.customer?.id;
|
||||
|
||||
if (customerId) {
|
||||
await stripe.customers.update(customerId, {
|
||||
metadata: {
|
||||
userId: newUser.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
await redis.set(`user:${newUser.id}:temp-password`, tempPassword, {
|
||||
// expire in 1 week
|
||||
ex: 60 * 60 * 24 * 7,
|
||||
});
|
||||
|
||||
const signatureDataUrl = await redis.get<string>(`signature:${session.client_reference_id}`);
|
||||
|
||||
const documentBuffer = await fetch(
|
||||
new URL('@documenso/assets/documenso-supporter-pledge.pdf', import.meta.url),
|
||||
).then(async (res) => res.arrayBuffer());
|
||||
|
||||
const { id: documentDataId } = await putPdfFile({
|
||||
name: 'Documenso Supporter Pledge.pdf',
|
||||
type: 'application/pdf',
|
||||
arrayBuffer: async () => Promise.resolve(documentBuffer),
|
||||
});
|
||||
|
||||
const document = await prisma.document.create({
|
||||
data: {
|
||||
title: 'Documenso Supporter Pledge.pdf',
|
||||
status: DocumentStatus.COMPLETED,
|
||||
userId: newUser.id,
|
||||
documentDataId,
|
||||
source: DocumentSource.DOCUMENT,
|
||||
},
|
||||
});
|
||||
|
||||
const recipient = await prisma.recipient.create({
|
||||
data: {
|
||||
name,
|
||||
email: email.toLowerCase(),
|
||||
token: alphaid(),
|
||||
readStatus: ReadStatus.OPENED,
|
||||
sendStatus: SendStatus.SENT,
|
||||
signingStatus: SigningStatus.SIGNED,
|
||||
signedAt: new Date(),
|
||||
documentId: document.id,
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.field.create({
|
||||
data: {
|
||||
type: FieldType.SIGNATURE,
|
||||
recipientId: recipient.id,
|
||||
documentId: document.id,
|
||||
page: 1,
|
||||
positionX: 12.2781,
|
||||
positionY: 81.5789,
|
||||
height: 6.8649,
|
||||
width: 29.5857,
|
||||
inserted: true,
|
||||
customText: '',
|
||||
|
||||
Signature: {
|
||||
create: {
|
||||
typedSignature: signatureDataUrl ? null : signatureText || name,
|
||||
signatureImageAsBase64: signatureDataUrl,
|
||||
recipientId: recipient.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await sealDocument({
|
||||
documentId: document.id,
|
||||
sendEmail: false,
|
||||
});
|
||||
} catch (error) {
|
||||
// We don't want to break the checkout process if something goes wrong here.
|
||||
// This is an additive experience for early adopters, breaking their ability
|
||||
// join would be far worse than not having a signed pledge.
|
||||
console.error('early-supporter-error', error);
|
||||
}
|
||||
};
|
||||
@ -35,12 +35,12 @@ export const isUserEnterprise = async ({
|
||||
select: {
|
||||
owner: {
|
||||
include: {
|
||||
Subscription: true,
|
||||
subscriptions: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
.then((team) => team.owner.Subscription);
|
||||
.then((team) => team.owner.subscriptions);
|
||||
} else {
|
||||
subscriptions = await prisma.user
|
||||
.findFirstOrThrow({
|
||||
@ -48,10 +48,10 @@ export const isUserEnterprise = async ({
|
||||
id: userId,
|
||||
},
|
||||
select: {
|
||||
Subscription: true,
|
||||
subscriptions: true,
|
||||
},
|
||||
})
|
||||
.then((user) => user.Subscription);
|
||||
.then((user) => user.subscriptions);
|
||||
}
|
||||
|
||||
if (subscriptions.length === 0) {
|
||||
|
||||
@ -32,12 +32,12 @@ export const isDocumentPlatform = async ({
|
||||
select: {
|
||||
owner: {
|
||||
include: {
|
||||
Subscription: true,
|
||||
subscriptions: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
.then((team) => team.owner.Subscription);
|
||||
.then((team) => team.owner.subscriptions);
|
||||
} else {
|
||||
subscriptions = await prisma.user
|
||||
.findFirstOrThrow({
|
||||
@ -45,10 +45,10 @@ export const isDocumentPlatform = async ({
|
||||
id: userId,
|
||||
},
|
||||
select: {
|
||||
Subscription: true,
|
||||
subscriptions: true,
|
||||
},
|
||||
})
|
||||
.then((user) => user.Subscription);
|
||||
.then((user) => user.subscriptions);
|
||||
}
|
||||
|
||||
if (subscriptions.length === 0) {
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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(),
|
||||
});
|
||||
|
||||
@ -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,
|
||||
});
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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({
|
||||
|
||||
@ -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,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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');
|
||||
|
||||
@ -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}`;
|
||||
|
||||
|
||||
@ -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,
|
||||
});
|
||||
|
||||
@ -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,
|
||||
});
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@ export const duplicateDocument = async ({
|
||||
const createDocumentArguments: Prisma.DocumentCreateArgs = {
|
||||
data: {
|
||||
title: document.title,
|
||||
User: {
|
||||
user: {
|
||||
connect: {
|
||||
id: document.userId,
|
||||
},
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
},
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
@ -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,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
});
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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,
|
||||
});
|
||||
|
||||
@ -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(' '),
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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,
|
||||
});
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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,
|
||||
});
|
||||
|
||||
@ -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.',
|
||||
|
||||
@ -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,
|
||||
},
|
||||
|
||||
@ -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.',
|
||||
|
||||
@ -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.',
|
||||
});
|
||||
|
||||
@ -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,
|
||||
},
|
||||
|
||||
@ -16,7 +16,7 @@ export const deleteTemplateField = async ({
|
||||
const field = await prisma.field.findFirst({
|
||||
where: {
|
||||
id: fieldId,
|
||||
Template: teamId
|
||||
template: teamId
|
||||
? {
|
||||
team: {
|
||||
id: teamId,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -29,7 +29,7 @@ export const getFieldById = async ({
|
||||
id: fieldId,
|
||||
documentId,
|
||||
templateId,
|
||||
Document: {
|
||||
document: {
|
||||
OR:
|
||||
teamId === undefined
|
||||
? [
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
@ -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}`);
|
||||
|
||||
@ -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,
|
||||
},
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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')
|
||||
|
||||
@ -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,
|
||||
),
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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,
|
||||
);
|
||||
|
||||
|
||||
@ -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,
|
||||
);
|
||||
|
||||
|
||||
@ -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, {
|
||||
|
||||
@ -23,7 +23,7 @@ export const deleteRecipient = async ({
|
||||
const recipient = await prisma.recipient.findFirst({
|
||||
where: {
|
||||
id: recipientId,
|
||||
Document: {
|
||||
document: {
|
||||
id: documentId,
|
||||
...(teamId
|
||||
? {
|
||||
|
||||
@ -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, {
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ export type GetRecipientSignaturesOptions = {
|
||||
export const getRecipientSignatures = async ({ recipientId }: GetRecipientSignaturesOptions) => {
|
||||
return await prisma.signature.findMany({
|
||||
where: {
|
||||
Field: {
|
||||
field: {
|
||||
recipientId,
|
||||
},
|
||||
},
|
||||
|
||||
@ -14,7 +14,7 @@ export const getRecipientsForDocument = async ({
|
||||
const recipients = await prisma.recipient.findMany({
|
||||
where: {
|
||||
documentId,
|
||||
Document: teamId
|
||||
document: teamId
|
||||
? {
|
||||
team: {
|
||||
id: teamId,
|
||||
|
||||
@ -14,7 +14,7 @@ export const getRecipientsForTemplate = async ({
|
||||
const recipients = await prisma.recipient.findMany({
|
||||
where: {
|
||||
templateId,
|
||||
Template: teamId
|
||||
template: teamId
|
||||
? {
|
||||
team: {
|
||||
id: teamId,
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -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,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -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,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -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,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -57,7 +57,7 @@ export const transferTeamOwnership = async ({ token }: TransferTeamOwnershipOpti
|
||||
},
|
||||
},
|
||||
include: {
|
||||
Subscription: true,
|
||||
subscriptions: true,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -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,
|
||||
});
|
||||
|
||||
@ -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: {
|
||||
|
||||
@ -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,
|
||||
});
|
||||
|
||||
@ -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,
|
||||
)
|
||||
) {
|
||||
|
||||
@ -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),
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -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,
|
||||
);
|
||||
|
||||
|
||||
@ -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: {
|
||||
|
||||
@ -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(),
|
||||
};
|
||||
};
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -46,7 +46,7 @@ export const toggleTemplateDirectLink = async ({
|
||||
}),
|
||||
},
|
||||
include: {
|
||||
Recipient: true,
|
||||
recipients: true,
|
||||
directLink: true,
|
||||
},
|
||||
});
|
||||
|
||||
@ -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,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -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,
|
||||
},
|
||||
|
||||
@ -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');
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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,
|
||||
};
|
||||
};
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -46,9 +46,9 @@ model User {
|
||||
|
||||
accounts Account[]
|
||||
sessions Session[]
|
||||
Document Document[]
|
||||
Subscription Subscription[]
|
||||
PasswordResetToken PasswordResetToken[]
|
||||
documents Document[]
|
||||
subscriptions Subscription[]
|
||||
passwordResetTokens PasswordResetToken[]
|
||||
ownedTeams Team[]
|
||||
ownedPendingTeams TeamPending[]
|
||||
teamMembers TeamMember[]
|
||||
@ -57,15 +57,15 @@ model User {
|
||||
twoFactorBackupCodes String?
|
||||
url String? @unique
|
||||
|
||||
profile UserProfile?
|
||||
VerificationToken VerificationToken[]
|
||||
ApiToken ApiToken[]
|
||||
Template Template[]
|
||||
securityAuditLogs UserSecurityAuditLog[]
|
||||
Webhooks Webhook[]
|
||||
siteSettings SiteSettings[]
|
||||
passkeys Passkey[]
|
||||
avatarImage AvatarImage? @relation(fields: [avatarImageId], references: [id], onDelete: SetNull)
|
||||
profile UserProfile?
|
||||
verificationTokens VerificationToken[]
|
||||
apiTokens ApiToken[]
|
||||
templates Template[]
|
||||
securityAuditLogs UserSecurityAuditLog[]
|
||||
webhooks Webhook[]
|
||||
siteSettings SiteSettings[]
|
||||
passkeys Passkey[]
|
||||
avatarImage AvatarImage? @relation(fields: [avatarImageId], references: [id], onDelete: SetNull)
|
||||
|
||||
@@index([email])
|
||||
}
|
||||
@ -113,7 +113,7 @@ model UserSecurityAuditLog {
|
||||
userAgent String?
|
||||
ipAddress String?
|
||||
|
||||
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
}
|
||||
|
||||
model PasswordResetToken {
|
||||
@ -122,7 +122,7 @@ model PasswordResetToken {
|
||||
createdAt DateTime @default(now())
|
||||
expiry DateTime
|
||||
userId Int
|
||||
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
}
|
||||
|
||||
model Passkey {
|
||||
@ -139,7 +139,7 @@ model Passkey {
|
||||
credentialBackedUp Boolean
|
||||
transports String[]
|
||||
|
||||
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
}
|
||||
|
||||
model AnonymousVerificationToken {
|
||||
@ -179,10 +179,10 @@ model Webhook {
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @default(now()) @updatedAt
|
||||
userId Int
|
||||
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
teamId Int?
|
||||
team Team? @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
||||
WebhookCall WebhookCall[]
|
||||
webhookCalls WebhookCall[]
|
||||
}
|
||||
|
||||
enum WebhookCallStatus {
|
||||
@ -240,7 +240,7 @@ model Subscription {
|
||||
cancelAtPeriodEnd Boolean @default(false)
|
||||
|
||||
team Team? @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
||||
User User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([userId])
|
||||
}
|
||||
@ -298,15 +298,15 @@ model Document {
|
||||
id Int @id @default(autoincrement())
|
||||
externalId String?
|
||||
userId Int
|
||||
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
authOptions Json?
|
||||
formValues Json?
|
||||
visibility DocumentVisibility @default(EVERYONE)
|
||||
title String
|
||||
status DocumentStatus @default(DRAFT)
|
||||
Recipient Recipient[]
|
||||
Field Field[]
|
||||
ShareLink DocumentShareLink[]
|
||||
recipients Recipient[]
|
||||
fields Field[]
|
||||
shareLinks DocumentShareLink[]
|
||||
documentDataId String
|
||||
documentData DocumentData @relation(fields: [documentDataId], references: [id], onDelete: Cascade)
|
||||
documentMeta DocumentMeta?
|
||||
@ -360,8 +360,8 @@ model DocumentData {
|
||||
type DocumentDataType
|
||||
data String
|
||||
initialData String
|
||||
Document Document?
|
||||
Template Template?
|
||||
document Document?
|
||||
template Template?
|
||||
}
|
||||
|
||||
enum DocumentDistributionMethod {
|
||||
@ -426,10 +426,10 @@ model Recipient {
|
||||
readStatus ReadStatus @default(NOT_OPENED)
|
||||
signingStatus SigningStatus @default(NOT_SIGNED)
|
||||
sendStatus SendStatus @default(NOT_SENT)
|
||||
Document Document? @relation(fields: [documentId], references: [id], onDelete: Cascade)
|
||||
Template Template? @relation(fields: [templateId], references: [id], onDelete: Cascade)
|
||||
Field Field[]
|
||||
Signature Signature[]
|
||||
document Document? @relation(fields: [documentId], references: [id], onDelete: Cascade)
|
||||
template Template? @relation(fields: [templateId], references: [id], onDelete: Cascade)
|
||||
fields Field[]
|
||||
signatures Signature[]
|
||||
|
||||
@@unique([documentId, email])
|
||||
@@unique([templateId, email])
|
||||
@ -466,10 +466,10 @@ model Field {
|
||||
height Decimal @default(-1)
|
||||
customText String
|
||||
inserted Boolean
|
||||
Document Document? @relation(fields: [documentId], references: [id], onDelete: Cascade)
|
||||
Template Template? @relation(fields: [templateId], references: [id], onDelete: Cascade)
|
||||
Recipient Recipient @relation(fields: [recipientId], references: [id], onDelete: Cascade)
|
||||
Signature Signature?
|
||||
document Document? @relation(fields: [documentId], references: [id], onDelete: Cascade)
|
||||
template Template? @relation(fields: [templateId], references: [id], onDelete: Cascade)
|
||||
recipient Recipient @relation(fields: [recipientId], references: [id], onDelete: Cascade)
|
||||
signature Signature?
|
||||
fieldMeta Json?
|
||||
|
||||
@@index([documentId])
|
||||
@ -485,8 +485,8 @@ model Signature {
|
||||
signatureImageAsBase64 String?
|
||||
typedSignature String?
|
||||
|
||||
Recipient Recipient @relation(fields: [recipientId], references: [id], onDelete: Cascade)
|
||||
Field Field @relation(fields: [fieldId], references: [id], onDelete: Cascade)
|
||||
recipient Recipient @relation(fields: [recipientId], references: [id], onDelete: Cascade)
|
||||
field Field @relation(fields: [fieldId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([recipientId])
|
||||
}
|
||||
@ -554,10 +554,10 @@ model Team {
|
||||
owner User @relation(fields: [ownerUserId], references: [id], onDelete: Cascade)
|
||||
subscription Subscription?
|
||||
|
||||
document Document[]
|
||||
documents Document[]
|
||||
templates Template[]
|
||||
ApiToken ApiToken[]
|
||||
Webhook Webhook[]
|
||||
apiTokens ApiToken[]
|
||||
webhooks Webhook[]
|
||||
}
|
||||
|
||||
model TeamPending {
|
||||
@ -671,9 +671,9 @@ model Template {
|
||||
|
||||
team Team? @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
||||
templateDocumentData DocumentData @relation(fields: [templateDocumentDataId], references: [id], onDelete: Cascade)
|
||||
User User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
Recipient Recipient[]
|
||||
Field Field[]
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
recipients Recipient[]
|
||||
fields Field[]
|
||||
directLink TemplateDirectLink?
|
||||
documents Document[]
|
||||
|
||||
|
||||
@ -115,7 +115,7 @@ export const seedDraftDocument = async (
|
||||
|
||||
for (const recipient of recipients) {
|
||||
const email = typeof recipient === 'string' ? recipient : recipient.email;
|
||||
const name = typeof recipient === 'string' ? recipient : recipient.name ?? '';
|
||||
const name = typeof recipient === 'string' ? recipient : (recipient.name ?? '');
|
||||
|
||||
await prisma.recipient.create({
|
||||
data: {
|
||||
@ -126,12 +126,12 @@ export const seedDraftDocument = async (
|
||||
sendStatus: SendStatus.NOT_SENT,
|
||||
signingStatus: SigningStatus.NOT_SIGNED,
|
||||
signedAt: new Date(),
|
||||
Document: {
|
||||
document: {
|
||||
connect: {
|
||||
id: document.id,
|
||||
},
|
||||
},
|
||||
Field: {
|
||||
fields: {
|
||||
create: {
|
||||
page: 1,
|
||||
type: FieldType.NAME,
|
||||
@ -184,7 +184,7 @@ export const seedPendingDocument = async (
|
||||
|
||||
for (const recipient of recipients) {
|
||||
const email = typeof recipient === 'string' ? recipient : recipient.email;
|
||||
const name = typeof recipient === 'string' ? recipient : recipient.name ?? '';
|
||||
const name = typeof recipient === 'string' ? recipient : (recipient.name ?? '');
|
||||
|
||||
await prisma.recipient.create({
|
||||
data: {
|
||||
@ -195,12 +195,12 @@ export const seedPendingDocument = async (
|
||||
sendStatus: SendStatus.SENT,
|
||||
signingStatus: SigningStatus.NOT_SIGNED,
|
||||
signedAt: new Date(),
|
||||
Document: {
|
||||
document: {
|
||||
connect: {
|
||||
id: document.id,
|
||||
},
|
||||
},
|
||||
Field: {
|
||||
fields: {
|
||||
create: {
|
||||
page: 1,
|
||||
type: FieldType.NAME,
|
||||
@ -222,7 +222,7 @@ export const seedPendingDocument = async (
|
||||
id: document.id,
|
||||
},
|
||||
include: {
|
||||
Recipient: true,
|
||||
recipients: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
@ -240,7 +240,7 @@ export const seedPendingDocumentNoFields = async ({
|
||||
|
||||
for (const recipient of recipients) {
|
||||
const email = typeof recipient === 'string' ? recipient : recipient.email;
|
||||
const name = typeof recipient === 'string' ? recipient : recipient.name ?? '';
|
||||
const name = typeof recipient === 'string' ? recipient : (recipient.name ?? '');
|
||||
|
||||
await prisma.recipient.create({
|
||||
data: {
|
||||
@ -251,7 +251,7 @@ export const seedPendingDocumentNoFields = async ({
|
||||
sendStatus: SendStatus.SENT,
|
||||
signingStatus: SigningStatus.NOT_SIGNED,
|
||||
signedAt: new Date(),
|
||||
Document: {
|
||||
document: {
|
||||
connect: {
|
||||
id: document.id,
|
||||
},
|
||||
@ -265,7 +265,7 @@ export const seedPendingDocumentNoFields = async ({
|
||||
documentId: document.id,
|
||||
},
|
||||
include: {
|
||||
Field: true,
|
||||
fields: true,
|
||||
},
|
||||
});
|
||||
|
||||
@ -301,7 +301,7 @@ export const seedPendingDocumentWithFullFields = async ({
|
||||
|
||||
for (const [recipientIndex, recipient] of recipients.entries()) {
|
||||
const email = typeof recipient === 'string' ? recipient : recipient.email;
|
||||
const name = typeof recipient === 'string' ? recipient : recipient.name ?? '';
|
||||
const name = typeof recipient === 'string' ? recipient : (recipient.name ?? '');
|
||||
|
||||
await prisma.recipient.create({
|
||||
data: {
|
||||
@ -312,12 +312,12 @@ export const seedPendingDocumentWithFullFields = async ({
|
||||
sendStatus: SendStatus.SENT,
|
||||
signingStatus: SigningStatus.NOT_SIGNED,
|
||||
signedAt: new Date(),
|
||||
Document: {
|
||||
document: {
|
||||
connect: {
|
||||
id: document.id,
|
||||
},
|
||||
},
|
||||
Field: {
|
||||
fields: {
|
||||
createMany: {
|
||||
data: fields.map((fieldType, fieldIndex) => ({
|
||||
page: 1,
|
||||
@ -342,7 +342,7 @@ export const seedPendingDocumentWithFullFields = async ({
|
||||
documentId: document.id,
|
||||
},
|
||||
include: {
|
||||
Field: true,
|
||||
fields: true,
|
||||
},
|
||||
});
|
||||
|
||||
@ -393,7 +393,7 @@ export const seedCompletedDocument = async (
|
||||
|
||||
for (const recipient of recipients) {
|
||||
const email = typeof recipient === 'string' ? recipient : recipient.email;
|
||||
const name = typeof recipient === 'string' ? recipient : recipient.name ?? '';
|
||||
const name = typeof recipient === 'string' ? recipient : (recipient.name ?? '');
|
||||
|
||||
await prisma.recipient.create({
|
||||
data: {
|
||||
@ -404,12 +404,12 @@ export const seedCompletedDocument = async (
|
||||
sendStatus: SendStatus.SENT,
|
||||
signingStatus: SigningStatus.SIGNED,
|
||||
signedAt: new Date(),
|
||||
Document: {
|
||||
document: {
|
||||
connect: {
|
||||
id: document.id,
|
||||
},
|
||||
},
|
||||
Field: {
|
||||
fields: {
|
||||
create: {
|
||||
page: 1,
|
||||
type: FieldType.NAME,
|
||||
|
||||
@ -58,7 +58,7 @@ export const seedDatabase = async () => {
|
||||
title: 'Example Document',
|
||||
documentDataId: examplePdfData.id,
|
||||
userId: exampleUser.id,
|
||||
Recipient: {
|
||||
recipients: {
|
||||
create: {
|
||||
name: String(adminUser.name),
|
||||
email: adminUser.email,
|
||||
|
||||
@ -66,12 +66,12 @@ export const seedTemplate = async (options: SeedTemplateOptions) => {
|
||||
id: documentData.id,
|
||||
},
|
||||
},
|
||||
User: {
|
||||
user: {
|
||||
connect: {
|
||||
id: userId,
|
||||
},
|
||||
},
|
||||
Recipient: {
|
||||
recipients: {
|
||||
create: {
|
||||
email: 'recipient.1@documenso.com',
|
||||
name: 'Recipient 1',
|
||||
@ -114,12 +114,12 @@ export const seedDirectTemplate = async (options: SeedTemplateOptions) => {
|
||||
id: documentData.id,
|
||||
},
|
||||
},
|
||||
User: {
|
||||
user: {
|
||||
connect: {
|
||||
id: userId,
|
||||
},
|
||||
},
|
||||
Recipient: {
|
||||
recipients: {
|
||||
create: {
|
||||
email: DIRECT_TEMPLATE_RECIPIENT_EMAIL,
|
||||
name: DIRECT_TEMPLATE_RECIPIENT_NAME,
|
||||
@ -138,12 +138,12 @@ export const seedDirectTemplate = async (options: SeedTemplateOptions) => {
|
||||
...options.createTemplateOptions,
|
||||
},
|
||||
include: {
|
||||
Recipient: true,
|
||||
User: true,
|
||||
recipients: true,
|
||||
user: true,
|
||||
},
|
||||
});
|
||||
|
||||
const directTemplateRecpient = template.Recipient.find(
|
||||
const directTemplateRecpient = template.recipients.find(
|
||||
(recipient) => recipient.email === DIRECT_TEMPLATE_RECIPIENT_EMAIL,
|
||||
);
|
||||
|
||||
@ -166,8 +166,8 @@ export const seedDirectTemplate = async (options: SeedTemplateOptions) => {
|
||||
},
|
||||
include: {
|
||||
directLink: true,
|
||||
Field: true,
|
||||
Recipient: true,
|
||||
fields: true,
|
||||
recipients: true,
|
||||
team: true,
|
||||
},
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user