Compare commits

..

1 Commits

Author SHA1 Message Date
Catalin Pit
9d21913b90 feat: add default recipients for teams and orgs 2025-11-26 12:16:38 +02:00
8 changed files with 73 additions and 5 deletions

View File

@@ -11,6 +11,7 @@ import {
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
import { normalizePdf as makeNormalizedPdf } from '@documenso/lib/server-only/pdf/normalize-pdf';
import { ZDefaultRecipientsSchema } from '@documenso/lib/types/default-recipients';
import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs';
import type { ApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
import { nanoid, prefixedId } from '@documenso/lib/universal/id';
@@ -306,8 +307,22 @@ export const createEnvelope = async ({
const firstEnvelopeItem = envelope.envelopeItems[0];
const defaultRecipients = settings.defaultRecipients
? ZDefaultRecipientsSchema.parse(settings.defaultRecipients)
: [];
const mappedDefaultRecipients: CreateEnvelopeRecipientOptions[] = defaultRecipients.map(
(recipient) => ({
email: recipient.email,
name: recipient.name,
role: recipient.role,
}),
);
const allRecipients = [...(data.recipients || []), ...mappedDefaultRecipients];
await Promise.all(
(data.recipients || []).map(async (recipient) => {
allRecipients.map(async (recipient) => {
const recipientAuthOptions = createRecipientAuthOptions({
accessAuth: recipient.accessAuth ?? [],
actionAuth: recipient.actionAuth ?? [],

View File

@@ -19,6 +19,7 @@ import { prisma } from '@documenso/prisma';
import { DEFAULT_DOCUMENT_DATE_FORMAT } from '../../constants/date-formats';
import type { SupportedLanguageCodes } from '../../constants/i18n';
import { AppError, AppErrorCode } from '../../errors/app-error';
import { ZDefaultRecipientsSchema } from '../../types/default-recipients';
import { DOCUMENT_AUDIT_LOG_TYPE } from '../../types/document-audit-logs';
import { ZRecipientAuthOptionsSchema } from '../../types/document-auth';
import type { TDocumentEmailSettings } from '../../types/document-email';
@@ -396,6 +397,30 @@ export const createDocumentFromTemplate = async ({
};
});
const defaultRecipients = settings.defaultRecipients
? ZDefaultRecipientsSchema.parse(settings.defaultRecipients)
: [];
const defaultRecipientsFinal: FinalRecipient[] = defaultRecipients.map((recipient) => {
const authOptions = ZRecipientAuthOptionsSchema.parse({});
return {
templateRecipientId: -1,
fields: [],
name: recipient.name || recipient.email,
email: recipient.email,
role: recipient.role,
signingOrder: null,
authOptions: createRecipientAuthOptions({
accessAuth: authOptions.accessAuth,
actionAuth: authOptions.actionAuth,
}),
token: nanoid(),
};
});
const allFinalRecipients = [...finalRecipients, ...defaultRecipientsFinal];
// Key = original envelope item ID
// Value = duplicated envelope item ID.
const oldEnvelopeItemToNewEnvelopeItemIdMap: Record<string, string> = {};
@@ -515,7 +540,7 @@ export const createDocumentFromTemplate = async ({
documentMetaId: documentMeta.id,
recipients: {
createMany: {
data: finalRecipients.map((recipient) => {
data: allFinalRecipients.map((recipient) => {
const authOptions = ZRecipientAuthOptionsSchema.parse(recipient?.authOptions);
return {
@@ -596,7 +621,7 @@ export const createDocumentFromTemplate = async ({
}
}
Object.values(finalRecipients).forEach(({ token, fields }) => {
Object.values(allFinalRecipients).forEach(({ token, fields }) => {
const recipient = envelope.recipients.find((recipient) => recipient.token === token);
if (!recipient) {

View File

@@ -0,0 +1,12 @@
import { RecipientRole } from '@prisma/client';
import { z } from 'zod';
export const ZDefaultRecipientSchema = z.object({
email: z.string().email(),
name: z.string(),
role: z.nativeEnum(RecipientRole),
});
export const ZDefaultRecipientsSchema = z.array(ZDefaultRecipientSchema);
export type TDefaultRecipients = z.infer<typeof ZDefaultRecipientsSchema>;

View File

@@ -135,5 +135,7 @@ export const generateDefaultOrganisationSettings = (): Omit<
emailReplyTo: null,
// emailReplyToName: null,
emailDocumentSettings: DEFAULT_DOCUMENT_EMAIL_SETTINGS,
defaultRecipients: null,
};
};

View File

@@ -202,6 +202,8 @@ export const generateDefaultTeamSettings = (): Omit<TeamGlobalSettings, 'id' | '
emailId: null,
emailReplyTo: null,
// emailReplyToName: null,
defaultRecipients: null,
};
};

View File

@@ -797,7 +797,7 @@ enum OrganisationMemberInviteStatus {
DECLINED
}
/// @zod.import(["import { ZDocumentEmailSettingsSchema } from '@documenso/lib/types/document-email';"])
/// @zod.import(["import { ZDocumentEmailSettingsSchema } from '@documenso/lib/types/document-email';", "import { ZDefaultRecipientsSchema } from '@documenso/lib/types/default-recipients';"])
model OrganisationGlobalSettings {
id String @id
organisation Organisation?
@@ -814,6 +814,8 @@ model OrganisationGlobalSettings {
uploadSignatureEnabled Boolean @default(true)
drawSignatureEnabled Boolean @default(true)
defaultRecipients Json? /// [DefaultRecipient[]] @zod.custom.use(ZDefaultRecipientsSchema)
emailId String?
email OrganisationEmail? @relation(fields: [emailId], references: [id])
@@ -827,7 +829,7 @@ model OrganisationGlobalSettings {
brandingCompanyDetails String @default("")
}
/// @zod.import(["import { ZDocumentEmailSettingsSchema } from '@documenso/lib/types/document-email';"])
/// @zod.import(["import { ZDocumentEmailSettingsSchema } from '@documenso/lib/types/document-email';", "import { ZDefaultRecipientsSchema } from '@documenso/lib/types/default-recipients';"])
model TeamGlobalSettings {
id String @id
team Team?
@@ -845,6 +847,8 @@ model TeamGlobalSettings {
uploadSignatureEnabled Boolean?
drawSignatureEnabled Boolean?
defaultRecipients Json? /// [DefaultRecipient[]] @zod.custom.use(ZDefaultRecipientsSchema)
emailId String?
email OrganisationEmail? @relation(fields: [emailId], references: [id])

View File

@@ -51,6 +51,9 @@ export const updateTeamSettingsRoute = authenticatedProcedure
emailReplyTo,
// emailReplyToName,
emailDocumentSettings,
// Default recipients settings.
defaultRecipients,
} = data;
if (Object.values(data).length === 0) {
@@ -160,6 +163,7 @@ export const updateTeamSettingsRoute = authenticatedProcedure
// emailReplyToName,
emailDocumentSettings:
emailDocumentSettings === null ? Prisma.DbNull : emailDocumentSettings,
defaultRecipients: defaultRecipients === null ? Prisma.DbNull : defaultRecipients,
},
},
},

View File

@@ -1,6 +1,7 @@
import { z } from 'zod';
import { SUPPORTED_LANGUAGE_CODES } from '@documenso/lib/constants/i18n';
import { ZDefaultRecipientsSchema } from '@documenso/lib/types/default-recipients';
import { ZDocumentEmailSettingsSchema } from '@documenso/lib/types/document-email';
import {
ZDocumentMetaDateFormatSchema,
@@ -38,6 +39,9 @@ export const ZUpdateTeamSettingsRequestSchema = z.object({
emailReplyTo: z.string().email().nullish(),
// emailReplyToName: z.string().nullish(),
emailDocumentSettings: ZDocumentEmailSettingsSchema.nullish(),
// Default recipients settings.
defaultRecipients: ZDefaultRecipientsSchema.nullish(),
}),
});