diff --git a/apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx b/apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx index 73f8cf7e5..4413c335f 100644 --- a/apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx +++ b/apps/remix/app/components/general/envelope-editor/envelope-editor-settings-dialog.tsx @@ -41,6 +41,7 @@ import { TemplateTypeSelect, TemplateTypeTooltip } from '@documenso/ui/component import { cn } from '@documenso/ui/lib/utils'; import { Button } from '@documenso/ui/primitives/button'; import { CardDescription, CardHeader, CardTitle } from '@documenso/ui/primitives/card'; +import { Checkbox } from '@documenso/ui/primitives/checkbox'; import { Combobox } from '@documenso/ui/primitives/combobox'; import { Dialog, @@ -50,7 +51,15 @@ import { DialogTitle, DialogTrigger, } from '@documenso/ui/primitives/dialog'; -import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form'; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '@documenso/ui/primitives/form/form'; import { Input } from '@documenso/ui/primitives/input'; import { MultiSelectCombobox } from '@documenso/ui/primitives/multi-select-combobox'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@documenso/ui/primitives/select'; @@ -93,6 +102,7 @@ export const ZAddSettingsFormSchema = z.object({ timezone: ZDocumentMetaTimezoneSchema.default(DEFAULT_DOCUMENT_TIME_ZONE), dateFormat: ZDocumentMetaDateFormatSchema.default(DEFAULT_DOCUMENT_DATE_FORMAT), distributionMethod: z.nativeEnum(DocumentDistributionMethod).optional().default(DocumentDistributionMethod.EMAIL), + includeAuditLog: z.boolean().default(false), redirectUrl: z .string() .optional() @@ -181,6 +191,7 @@ export const EnvelopeEditorSettingsDialog = ({ trigger, ...props }: EnvelopeEdit // eslint-disable-next-line @typescript-eslint/consistent-type-assertions dateFormat: (envelope.documentMeta.dateFormat ?? DEFAULT_DOCUMENT_DATE_FORMAT) as TDocumentMetaDateFormat, distributionMethod: envelope.documentMeta.distributionMethod || DocumentDistributionMethod.EMAIL, + includeAuditLog: envelope.documentMeta.includeAuditLog, redirectUrl: envelope.documentMeta.redirectUrl ?? '', language: envelope.documentMeta.language ?? 'en', emailId: envelope.documentMeta.emailId ?? null, @@ -236,6 +247,7 @@ export const EnvelopeEditorSettingsDialog = ({ trigger, ...props }: EnvelopeEdit emailReplyTo, envelopeExpirationPeriod, reminderSettings, + includeAuditLog, } = data.meta; const parsedGlobalAccessAuth = z.array(ZDocumentAccessAuthTypesSchema).safeParse(data.globalAccessAuth); @@ -265,6 +277,7 @@ export const EnvelopeEditorSettingsDialog = ({ trigger, ...props }: EnvelopeEdit uploadSignatureEnabled: signatureTypes.includes(DocumentSignatureType.UPLOAD), envelopeExpirationPeriod, reminderSettings, + includeAuditLog, }, }); @@ -892,6 +905,35 @@ export const EnvelopeEditorSettingsDialog = ({ trigger, ...props }: EnvelopeEdit )} /> + ( + +
+ + field.onChange(Boolean(checked))} + /> + + + + Include audit logs in downloaded PDF + +
+ + + + Audit logs remain available to download separately from the document logs page. + + +
+ )} + /> + {!isEmbedded && ( { + const teamSettings = await prisma.teamGlobalSettings.findFirstOrThrow({ + where: { + team: { + id: teamId, + }, + }, + }); + + await prisma.teamGlobalSettings.update({ + where: { + id: teamSettings.id, + }, + data, + }); +}; + +const getFirstEnvelopeItemSignedPageCount = async (envelopeId: string, token: string) => { + const envelopeItem = await prisma.envelopeItem.findFirstOrThrow({ + where: { + envelopeId, + }, + }); + + const documentUrl = getEnvelopeItemPdfUrl({ + type: 'download', + envelopeItem, + token, + version: 'signed', + }); + + const response = await fetch(documentUrl); + + expect(response.ok).toBe(true); + + const pdfData = await response.arrayBuffer(); + const pdfDoc = await PDF.load(new Uint8Array(pdfData)); + + return pdfDoc.getPageCount(); +}; + +const completeSigning = async ({ + page, + signingUrl, + recipientToken, + fieldId, +}: { + page: Page; + signingUrl: string; + recipientToken: string; + fieldId: number; +}) => { + await page.goto(signingUrl); + + await signSignaturePad(page); + + await page.locator(`#field-${fieldId}`).getByRole('button').click(); + await expect(page.locator(`#field-${fieldId}`)).toHaveAttribute('data-inserted', 'true'); + + await page.getByRole('button', { name: 'Complete' }).click(); + await page.getByRole('button', { name: 'Sign' }).click({ force: true }); + await page.waitForURL(/\/complete$/); + + await expect(async () => { + const { status } = await getDocumentByToken({ + token: recipientToken, + }); + + expect(status).toBe(DocumentStatus.COMPLETED); + }).toPass(); +}; + +test.describe('Document audit log embedding', () => { + test('new documents derive audit-log embedding from team settings', async ({ request }) => { + const context = await apiCreateTestContext('e2e-audit-log-default'); + + await updateTeamDocumentSettings(context.team.id, { + includeAuditLog: true, + }); + + const { envelope } = await apiSeedDraftDocument(request, { + context, + }); + + expect(envelope.documentMeta.includeAuditLog).toBe(true); + + await updateTeamDocumentSettings(context.team.id, { + includeAuditLog: false, + }); + + const documentMeta = await prisma.documentMeta.findFirstOrThrow({ + where: { + id: envelope.documentMeta.id, + }, + }); + + expect(documentMeta.includeAuditLog).toBe(true); + }); + + test('meta.includeAuditLog true appends audit-log pages when team default is false', async ({ page, request }) => { + const context = await apiCreateTestContext('e2e-audit-log-override-true'); + + await updateTeamDocumentSettings(context.team.id, { + includeAuditLog: false, + includeSigningCertificate: false, + }); + + const { distributeResult, envelope } = await apiSeedPendingDocument(request, { + context, + meta: { + includeAuditLog: true, + }, + }); + + expect(envelope.documentMeta.includeAuditLog).toBe(true); + + const signer = distributeResult.recipients[0]; + const signatureField = envelope.fields.find((field) => field.recipientId === signer.id); + + if (!signatureField) { + throw new Error('Signature field not found'); + } + + const baselinePageCount = await getFirstEnvelopeItemSignedPageCount(envelope.id, signer.token); + + await completeSigning({ + page, + signingUrl: signer.signingUrl, + recipientToken: signer.token, + fieldId: signatureField.id, + }); + + await expect(async () => { + const signedPageCount = await getFirstEnvelopeItemSignedPageCount(envelope.id, signer.token); + + expect(signedPageCount).toBe(baselinePageCount + 1); + }).toPass(); + }); + + test('meta.includeAuditLog false skips embedded audit logs when team default is true', async ({ page, request }) => { + const context = await apiCreateTestContext('e2e-audit-log-override-false'); + + await updateTeamDocumentSettings(context.team.id, { + includeAuditLog: true, + includeSigningCertificate: false, + }); + + const { distributeResult, envelope, team, user } = await apiSeedPendingDocument(request, { + context, + meta: { + includeAuditLog: false, + }, + }); + + expect(envelope.documentMeta.includeAuditLog).toBe(false); + + const signer = distributeResult.recipients[0]; + const signatureField = envelope.fields.find((field) => field.recipientId === signer.id); + + if (!signatureField) { + throw new Error('Signature field not found'); + } + + const baselinePageCount = await getFirstEnvelopeItemSignedPageCount(envelope.id, signer.token); + + await completeSigning({ + page, + signingUrl: signer.signingUrl, + recipientToken: signer.token, + fieldId: signatureField.id, + }); + + await expect(async () => { + const signedPageCount = await getFirstEnvelopeItemSignedPageCount(envelope.id, signer.token); + + expect(signedPageCount).toBe(baselinePageCount); + }).toPass(); + + await apiSignin({ + page, + email: user.email, + redirectPath: `/t/${team.url}/documents/${envelope.id}/logs`, + }); + + const downloadPromise = page.waitForEvent('download'); + + await page.getByRole('button', { name: 'Download Audit Logs' }).click(); + + const download = await downloadPromise; + + expect(download.suggestedFilename()).toContain('Audit Logs.pdf'); + }); +}); diff --git a/packages/lib/jobs/definitions/internal/seal-document.handler.ts b/packages/lib/jobs/definitions/internal/seal-document.handler.ts index 7748d7451..c62d3ea35 100644 --- a/packages/lib/jobs/definitions/internal/seal-document.handler.ts +++ b/packages/lib/jobs/definitions/internal/seal-document.handler.ts @@ -177,7 +177,7 @@ export const run = async ({ payload, io }: { payload: TSealDocumentJobDefinition const usePlaywrightPdf = NEXT_PRIVATE_USE_PLAYWRIGHT_PDF(); const needsCertificate = settings.includeSigningCertificate; - const needsAuditLog = settings.includeAuditLog; + const needsAuditLog = envelope.documentMeta.includeAuditLog; const newDocumentData: Array<{ oldDocumentDataId: string; newDocumentDataId: string }> = []; diff --git a/packages/lib/server-only/document-meta/upsert-document-meta.ts b/packages/lib/server-only/document-meta/upsert-document-meta.ts index 770c3ceb3..81b35b5db 100644 --- a/packages/lib/server-only/document-meta/upsert-document-meta.ts +++ b/packages/lib/server-only/document-meta/upsert-document-meta.ts @@ -2,7 +2,13 @@ import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-log import type { ApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata'; import { createDocumentAuditLogData, diffDocumentMetaChanges } from '@documenso/lib/utils/document-audit-logs'; import { prisma } from '@documenso/prisma'; -import { type DocumentDistributionMethod, type DocumentSigningOrder, EnvelopeType } from '@prisma/client'; +import { + type DocumentDistributionMethod, + type DocumentSigningOrder, + EnvelopeType, + RecipientRole, + SendStatus, +} from '@prisma/client'; import type { SupportedLanguageCodes } from '../../constants/i18n'; import { AppError, AppErrorCode } from '../../errors/app-error'; @@ -25,6 +31,7 @@ export type CreateDocumentMetaOptions = { signingOrder?: DocumentSigningOrder; allowDictateNextSigner?: boolean; distributionMethod?: DocumentDistributionMethod; + includeAuditLog?: boolean; typedSignatureEnabled?: boolean; uploadSignatureEnabled?: boolean; drawSignatureEnabled?: boolean; @@ -47,6 +54,7 @@ export const updateDocumentMeta = async ({ emailReplyTo, emailSettings, distributionMethod, + includeAuditLog, typedSignatureEnabled, uploadSignatureEnabled, drawSignatureEnabled, @@ -91,6 +99,28 @@ export const updateDocumentMeta = async ({ } } + if ( + envelope.type === EnvelopeType.DOCUMENT && + includeAuditLog !== undefined && + includeAuditLog !== envelope.documentMeta.includeAuditLog + ) { + const sentRecipientCount = await prisma.recipient.count({ + where: { + envelopeId: envelope.id, + role: { + not: RecipientRole.CC, + }, + sendStatus: SendStatus.SENT, + }, + }); + + if (sentRecipientCount > 0) { + throw new AppError(AppErrorCode.INVALID_BODY, { + message: 'Audit log embedding can only be changed before the document is sent', + }); + } + } + return await prisma.$transaction(async (tx) => { const upsertedDocumentMeta = await tx.documentMeta.update({ where: { @@ -108,6 +138,7 @@ export const updateDocumentMeta = async ({ emailReplyTo, emailSettings, distributionMethod, + includeAuditLog, typedSignatureEnabled, uploadSignatureEnabled, drawSignatureEnabled, diff --git a/packages/lib/server-only/envelope/get-envelope-for-recipient-signing.ts b/packages/lib/server-only/envelope/get-envelope-for-recipient-signing.ts index bde38be18..f3dffdb77 100644 --- a/packages/lib/server-only/envelope/get-envelope-for-recipient-signing.ts +++ b/packages/lib/server-only/envelope/get-envelope-for-recipient-signing.ts @@ -40,6 +40,7 @@ export const ZEnvelopeForSigningResponse = z.object({ documentMeta: DocumentMetaSchema.pick({ signingOrder: true, distributionMethod: true, + includeAuditLog: true, timezone: true, dateFormat: true, redirectUrl: true, diff --git a/packages/lib/server-only/envelope/update-envelope.ts b/packages/lib/server-only/envelope/update-envelope.ts index 4bb70e516..10b966231 100644 --- a/packages/lib/server-only/envelope/update-envelope.ts +++ b/packages/lib/server-only/envelope/update-envelope.ts @@ -4,7 +4,14 @@ import type { CreateDocumentAuditLogDataResponse } from '@documenso/lib/utils/do import { createDocumentAuditLogData } from '@documenso/lib/utils/document-audit-logs'; import { prisma } from '@documenso/prisma'; import type { DocumentMeta, DocumentVisibility, Prisma, TemplateType } from '@prisma/client'; -import { DocumentStatus, EnvelopeType, FolderType, WebhookTriggerEvents } from '@prisma/client'; +import { + DocumentStatus, + EnvelopeType, + FolderType, + RecipientRole, + SendStatus, + WebhookTriggerEvents, +} from '@prisma/client'; import { isDeepEqual } from 'remeda'; import { TEAM_DOCUMENT_VISIBILITY_MAP } from '../../constants/teams'; @@ -137,6 +144,28 @@ export const updateEnvelope = async ({ } } + if ( + envelope.type === EnvelopeType.DOCUMENT && + meta.includeAuditLog !== undefined && + meta.includeAuditLog !== envelope.documentMeta.includeAuditLog + ) { + const sentRecipientCount = await prisma.recipient.count({ + where: { + envelopeId: envelope.id, + role: { + not: RecipientRole.CC, + }, + sendStatus: SendStatus.SENT, + }, + }); + + if (sentRecipientCount > 0) { + throw new AppError(AppErrorCode.INVALID_BODY, { + message: 'Audit log embedding can only be changed before the document is sent', + }); + } + } + let folderUpdateQuery: Prisma.FolderUpdateOneWithoutEnvelopesNestedInput | undefined; // Validate folder ID. @@ -182,11 +211,6 @@ export const updateEnvelope = async ({ const isGlobalActionSame = documentGlobalActionAuth === undefined || isDeepEqual(documentGlobalActionAuth, newGlobalActionAuth); const isDocumentVisibilitySame = data.visibility === undefined || data.visibility === envelope.visibility; - const isFolderSame = data.folderId === undefined || data.folderId === envelope.folderId; - const isTemplateTypeSame = data.templateType === undefined || data.templateType === envelope.templateType; - const isPublicDescriptionSame = - data.publicDescription === undefined || data.publicDescription === envelope.publicDescription; - const isPublicTitleSame = data.publicTitle === undefined || data.publicTitle === envelope.publicTitle; const auditLogs: CreateDocumentAuditLogDataResponse[] = []; @@ -266,36 +290,6 @@ export const updateEnvelope = async ({ ); } - // Todo: Decide if we want to log moving the document around. - // if (!isFolderSame) { - // auditLogs.push( - // createDocumentAuditLogData({ - // type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_FOLDER_UPDATED, - // envelopeId: envelope.id, - // metadata: requestMetadata, - // data: { - // from: envelope.folderId, - // to: data.folderId || '', - // }, - // }), - // ); - // } - - // Todo: Determine if changes are made - // Commented out since we didn't detect the changes to sequence. - // const isMetaSame = isDeepEqual(envelope.documentMeta, meta); - // Early return if nothing is required. - // if ( - // auditLogs.length === 0 && - // data.useLegacyFieldInsertion === undefined && - // isFolderSame && - // isTemplateTypeSame && - // isPublicDescriptionSame && - // isPublicTitleSame - // ) { - // return envelope; - // } - const updatedEnvelope = await prisma.$transaction(async (tx) => { const result = await tx.envelope.update({ where: { diff --git a/packages/lib/server-only/template/create-document-from-template.ts b/packages/lib/server-only/template/create-document-from-template.ts index 9469a417e..a8267750d 100644 --- a/packages/lib/server-only/template/create-document-from-template.ts +++ b/packages/lib/server-only/template/create-document-from-template.ts @@ -105,6 +105,7 @@ export type CreateDocumentFromTemplateOptions = { language?: SupportedLanguageCodes; distributionMethod?: DocumentDistributionMethod; allowDictateNextSigner?: boolean; + includeAuditLog?: boolean; emailSettings?: TDocumentEmailSettings; typedSignatureEnabled?: boolean; uploadSignatureEnabled?: boolean; @@ -513,6 +514,7 @@ export const createDocumentFromTemplate = async ({ dateFormat: override?.dateFormat || template.documentMeta?.dateFormat, redirectUrl: override?.redirectUrl || template.documentMeta?.redirectUrl, distributionMethod: override?.distributionMethod || template.documentMeta?.distributionMethod, + includeAuditLog: override?.includeAuditLog ?? template.documentMeta?.includeAuditLog, emailSettings: override?.emailSettings || template.documentMeta?.emailSettings, signingOrder: override?.signingOrder || template.documentMeta?.signingOrder, language: override?.language || template.documentMeta?.language || settings.documentLanguage, @@ -666,7 +668,7 @@ export const createDocumentFromTemplate = async ({ const date = new Date(selector.value); - if (isNaN(date.getTime())) { + if (Number.isNaN(date.getTime())) { throw new AppError(AppErrorCode.INVALID_BODY, { message: `Invalid date value for field ${field.id}: ${selector.value}`, }); diff --git a/packages/lib/server-only/webhooks/trigger/generate-sample-data.ts b/packages/lib/server-only/webhooks/trigger/generate-sample-data.ts index 340e6790f..f4d8b2192 100644 --- a/packages/lib/server-only/webhooks/trigger/generate-sample-data.ts +++ b/packages/lib/server-only/webhooks/trigger/generate-sample-data.ts @@ -47,6 +47,7 @@ export const generateSampleWebhookPayload = (event: WebhookTriggerEvents, webhoo drawSignatureEnabled: true, language: 'en', distributionMethod: DocumentDistributionMethod.EMAIL, + includeAuditLog: false, emailSettings: null, }, recipients: [ diff --git a/packages/lib/types/document-meta.ts b/packages/lib/types/document-meta.ts index 12c1cf87c..7b295934b 100644 --- a/packages/lib/types/document-meta.ts +++ b/packages/lib/types/document-meta.ts @@ -19,6 +19,7 @@ import { ZDocumentEmailSettingsSchema } from './document-email'; export const ZDocumentMetaSchema = DocumentMetaSchema.pick({ signingOrder: true, distributionMethod: true, + includeAuditLog: true, id: true, subject: true, message: true, @@ -93,6 +94,10 @@ export const ZDocumentMetaDistributionMethodSchema = z .nativeEnum(DocumentDistributionMethod) .describe('The distribution method to use when sending the document to the recipients.'); +export const ZDocumentMetaIncludeAuditLogSchema = z + .boolean() + .describe('Whether to include the audit logs in the sealed document PDF.'); + export const ZDocumentMetaTypedSignatureEnabledSchema = z .boolean() .describe('Whether to allow recipients to sign using a typed signature.'); @@ -116,6 +121,7 @@ export const ZDocumentMetaCreateSchema = z.object({ timezone: ZDocumentMetaTimezoneSchema.optional(), dateFormat: ZDocumentMetaDateFormatSchema.optional(), distributionMethod: ZDocumentMetaDistributionMethodSchema.optional(), + includeAuditLog: ZDocumentMetaIncludeAuditLogSchema.optional(), signingOrder: z.nativeEnum(DocumentSigningOrder).optional(), allowDictateNextSigner: z.boolean().optional(), redirectUrl: ZDocumentMetaRedirectUrlSchema.optional(), diff --git a/packages/lib/types/document.ts b/packages/lib/types/document.ts index 2205d9191..ca98408ba 100644 --- a/packages/lib/types/document.ts +++ b/packages/lib/types/document.ts @@ -53,6 +53,7 @@ export const ZDocumentSchema = LegacyDocumentSchema.pick({ documentMeta: DocumentMetaSchema.pick({ signingOrder: true, distributionMethod: true, + includeAuditLog: true, id: true, subject: true, message: true, diff --git a/packages/lib/types/envelope-editor.ts b/packages/lib/types/envelope-editor.ts index cfa07fae7..b1d9b0e66 100644 --- a/packages/lib/types/envelope-editor.ts +++ b/packages/lib/types/envelope-editor.ts @@ -270,6 +270,7 @@ export const ZEditorEnvelopeSchema = EnvelopeSchema.pick({ documentMeta: DocumentMetaSchema.pick({ signingOrder: true, distributionMethod: true, + includeAuditLog: true, id: true, subject: true, message: true, diff --git a/packages/lib/types/envelope.ts b/packages/lib/types/envelope.ts index 2692252a0..96d53cf11 100644 --- a/packages/lib/types/envelope.ts +++ b/packages/lib/types/envelope.ts @@ -40,6 +40,7 @@ export const ZEnvelopeSchema = EnvelopeSchema.pick({ documentMeta: DocumentMetaSchema.pick({ signingOrder: true, distributionMethod: true, + includeAuditLog: true, id: true, subject: true, message: true, diff --git a/packages/lib/types/template.ts b/packages/lib/types/template.ts index bf43851c9..f2785720c 100644 --- a/packages/lib/types/template.ts +++ b/packages/lib/types/template.ts @@ -56,6 +56,7 @@ export const ZTemplateSchema = TemplateSchema.pick({ drawSignatureEnabled: true, allowDictateNextSigner: true, distributionMethod: true, + includeAuditLog: true, redirectUrl: true, language: true, emailSettings: true, @@ -149,6 +150,7 @@ export const ZTemplateManySchema = TemplateSchema.pick({ templateMeta: DocumentMetaSchema.pick({ signingOrder: true, distributionMethod: true, + includeAuditLog: true, }).nullable(), directLink: LegacyTemplateDirectLinkSchema.pick({ token: true, diff --git a/packages/lib/types/webhook-payload.ts b/packages/lib/types/webhook-payload.ts index a3462da8d..7042c0a7d 100644 --- a/packages/lib/types/webhook-payload.ts +++ b/packages/lib/types/webhook-payload.ts @@ -56,6 +56,7 @@ export const ZWebhookDocumentMetaSchema = z.object({ drawSignatureEnabled: z.boolean(), language: z.string(), distributionMethod: z.nativeEnum(DocumentDistributionMethod), + includeAuditLog: z.boolean(), emailSettings: z.any().nullable(), }); diff --git a/packages/lib/utils/document.ts b/packages/lib/utils/document.ts index 7a9e9eb97..cff8a571e 100644 --- a/packages/lib/utils/document.ts +++ b/packages/lib/utils/document.ts @@ -44,6 +44,7 @@ export const extractDerivedDocumentMeta = ( signingOrder: meta.signingOrder || DocumentSigningOrder.PARALLEL, allowDictateNextSigner: meta.allowDictateNextSigner ?? false, distributionMethod: meta.distributionMethod || DocumentDistributionMethod.EMAIL, // Todo: Make this a setting. + includeAuditLog: meta.includeAuditLog ?? settings.includeAuditLog, // Signature settings. typedSignatureEnabled: meta.typedSignatureEnabled ?? settings.typedSignatureEnabled, diff --git a/packages/prisma/migrations/20260521000000_add_document_meta_include_audit_log/migration.sql b/packages/prisma/migrations/20260521000000_add_document_meta_include_audit_log/migration.sql new file mode 100644 index 000000000..6df1ec32b --- /dev/null +++ b/packages/prisma/migrations/20260521000000_add_document_meta_include_audit_log/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "DocumentMeta" ADD COLUMN "includeAuditLog" BOOLEAN NOT NULL DEFAULT false; diff --git a/packages/prisma/schema.prisma b/packages/prisma/schema.prisma index 9af17faeb..2bdbeb823 100644 --- a/packages/prisma/schema.prisma +++ b/packages/prisma/schema.prisma @@ -524,6 +524,7 @@ model DocumentMeta { language String @default("en") distributionMethod DocumentDistributionMethod @default(EMAIL) + includeAuditLog Boolean @default(false) emailSettings Json? /// [DocumentEmailSettings] @zod.custom.use(ZDocumentEmailSettingsSchema) emailReplyTo String? diff --git a/packages/trpc/server/document-router/distribute-document.ts b/packages/trpc/server/document-router/distribute-document.ts index f0b3c5333..11b51b10d 100644 --- a/packages/trpc/server/document-router/distribute-document.ts +++ b/packages/trpc/server/document-router/distribute-document.ts @@ -37,6 +37,7 @@ export const distributeDocumentRoute = authenticatedProcedure timezone: meta.timezone, redirectUrl: meta.redirectUrl, distributionMethod: meta.distributionMethod, + includeAuditLog: meta.includeAuditLog, emailSettings: meta.emailSettings ?? undefined, language: meta.language, emailId: meta.emailId, diff --git a/packages/trpc/server/document-router/distribute-document.types.ts b/packages/trpc/server/document-router/distribute-document.types.ts index e44554f20..e94228f97 100644 --- a/packages/trpc/server/document-router/distribute-document.types.ts +++ b/packages/trpc/server/document-router/distribute-document.types.ts @@ -3,6 +3,7 @@ import { ZDocumentEmailSettingsSchema } from '@documenso/lib/types/document-emai import { ZDocumentMetaDateFormatSchema, ZDocumentMetaDistributionMethodSchema, + ZDocumentMetaIncludeAuditLogSchema, ZDocumentMetaLanguageSchema, ZDocumentMetaMessageSchema, ZDocumentMetaRedirectUrlSchema, @@ -33,6 +34,7 @@ export const ZDistributeDocumentRequestSchema = z.object({ timezone: ZDocumentMetaTimezoneSchema.optional(), dateFormat: ZDocumentMetaDateFormatSchema.optional(), distributionMethod: ZDocumentMetaDistributionMethodSchema.optional(), + includeAuditLog: ZDocumentMetaIncludeAuditLogSchema.optional(), redirectUrl: ZDocumentMetaRedirectUrlSchema.optional(), language: ZDocumentMetaLanguageSchema.optional(), emailId: z.string().nullish(), diff --git a/packages/trpc/server/embedding-router/create-embedding-document.types.ts b/packages/trpc/server/embedding-router/create-embedding-document.types.ts index bdbdd1436..e4009be7f 100644 --- a/packages/trpc/server/embedding-router/create-embedding-document.types.ts +++ b/packages/trpc/server/embedding-router/create-embedding-document.types.ts @@ -3,6 +3,7 @@ import { ZDocumentMetaDateFormatSchema, ZDocumentMetaDistributionMethodSchema, ZDocumentMetaDrawSignatureEnabledSchema, + ZDocumentMetaIncludeAuditLogSchema, ZDocumentMetaLanguageSchema, ZDocumentMetaMessageSchema, ZDocumentMetaRedirectUrlSchema, @@ -59,6 +60,7 @@ export const ZCreateEmbeddingDocumentRequestSchema = z.object({ timezone: ZDocumentMetaTimezoneSchema.optional(), dateFormat: ZDocumentMetaDateFormatSchema.optional(), distributionMethod: ZDocumentMetaDistributionMethodSchema.optional(), + includeAuditLog: ZDocumentMetaIncludeAuditLogSchema.optional(), signingOrder: z.nativeEnum(DocumentSigningOrder).optional(), redirectUrl: ZDocumentMetaRedirectUrlSchema.optional(), language: ZDocumentMetaLanguageSchema.optional(), diff --git a/packages/trpc/server/embedding-router/create-embedding-template.types.ts b/packages/trpc/server/embedding-router/create-embedding-template.types.ts index 8bacaacf0..0bdd60f1c 100644 --- a/packages/trpc/server/embedding-router/create-embedding-template.types.ts +++ b/packages/trpc/server/embedding-router/create-embedding-template.types.ts @@ -3,6 +3,7 @@ import { ZDocumentMetaDateFormatSchema, ZDocumentMetaDistributionMethodSchema, ZDocumentMetaDrawSignatureEnabledSchema, + ZDocumentMetaIncludeAuditLogSchema, ZDocumentMetaLanguageSchema, ZDocumentMetaMessageSchema, ZDocumentMetaRedirectUrlSchema, @@ -56,6 +57,7 @@ export const ZCreateEmbeddingTemplateRequestSchema = z.object({ timezone: ZDocumentMetaTimezoneSchema.optional(), dateFormat: ZDocumentMetaDateFormatSchema.optional(), distributionMethod: ZDocumentMetaDistributionMethodSchema.optional(), + includeAuditLog: ZDocumentMetaIncludeAuditLogSchema.optional(), signingOrder: z.nativeEnum(DocumentSigningOrder).optional(), redirectUrl: ZDocumentMetaRedirectUrlSchema.optional(), language: ZDocumentMetaLanguageSchema.optional(), diff --git a/packages/trpc/server/embedding-router/get-multi-sign-document.types.ts b/packages/trpc/server/embedding-router/get-multi-sign-document.types.ts index 22f6d4cff..e978c9d86 100644 --- a/packages/trpc/server/embedding-router/get-multi-sign-document.types.ts +++ b/packages/trpc/server/embedding-router/get-multi-sign-document.types.ts @@ -21,6 +21,7 @@ export const ZGetMultiSignDocumentResponseSchema = ZDocumentLiteSchema.extend({ documentMeta: DocumentMetaSchema.pick({ signingOrder: true, distributionMethod: true, + includeAuditLog: true, id: true, subject: true, message: true, diff --git a/packages/trpc/server/embedding-router/update-embedding-document.types.ts b/packages/trpc/server/embedding-router/update-embedding-document.types.ts index 753ab7224..e0b1562f6 100644 --- a/packages/trpc/server/embedding-router/update-embedding-document.types.ts +++ b/packages/trpc/server/embedding-router/update-embedding-document.types.ts @@ -3,6 +3,7 @@ import { ZDocumentMetaDateFormatSchema, ZDocumentMetaDistributionMethodSchema, ZDocumentMetaDrawSignatureEnabledSchema, + ZDocumentMetaIncludeAuditLogSchema, ZDocumentMetaLanguageSchema, ZDocumentMetaMessageSchema, ZDocumentMetaRedirectUrlSchema, @@ -60,6 +61,7 @@ export const ZUpdateEmbeddingDocumentRequestSchema = z.object({ timezone: ZDocumentMetaTimezoneSchema.optional(), dateFormat: ZDocumentMetaDateFormatSchema.optional(), distributionMethod: ZDocumentMetaDistributionMethodSchema.optional(), + includeAuditLog: ZDocumentMetaIncludeAuditLogSchema.optional(), signingOrder: z.nativeEnum(DocumentSigningOrder).optional(), redirectUrl: ZDocumentMetaRedirectUrlSchema.optional(), language: ZDocumentMetaLanguageSchema.optional(), diff --git a/packages/trpc/server/embedding-router/update-embedding-template.types.ts b/packages/trpc/server/embedding-router/update-embedding-template.types.ts index 6fa3571f7..bae9a66c1 100644 --- a/packages/trpc/server/embedding-router/update-embedding-template.types.ts +++ b/packages/trpc/server/embedding-router/update-embedding-template.types.ts @@ -3,6 +3,7 @@ import { ZDocumentMetaDateFormatSchema, ZDocumentMetaDistributionMethodSchema, ZDocumentMetaDrawSignatureEnabledSchema, + ZDocumentMetaIncludeAuditLogSchema, ZDocumentMetaLanguageSchema, ZDocumentMetaMessageSchema, ZDocumentMetaRedirectUrlSchema, @@ -60,6 +61,7 @@ export const ZUpdateEmbeddingTemplateRequestSchema = z.object({ timezone: ZDocumentMetaTimezoneSchema.optional(), dateFormat: ZDocumentMetaDateFormatSchema.optional(), distributionMethod: ZDocumentMetaDistributionMethodSchema.optional(), + includeAuditLog: ZDocumentMetaIncludeAuditLogSchema.optional(), signingOrder: z.nativeEnum(DocumentSigningOrder).optional(), redirectUrl: ZDocumentMetaRedirectUrlSchema.optional(), language: ZDocumentMetaLanguageSchema.optional(), diff --git a/packages/trpc/server/envelope-router/distribute-envelope.ts b/packages/trpc/server/envelope-router/distribute-envelope.ts index e75c3efe3..5b389beef 100644 --- a/packages/trpc/server/envelope-router/distribute-envelope.ts +++ b/packages/trpc/server/envelope-router/distribute-envelope.ts @@ -37,6 +37,7 @@ export const distributeEnvelopeRoute = authenticatedProcedure timezone: meta.timezone, redirectUrl: meta.redirectUrl, distributionMethod: meta.distributionMethod, + includeAuditLog: meta.includeAuditLog, emailSettings: meta.emailSettings ?? undefined, language: meta.language, emailId: meta.emailId, diff --git a/packages/trpc/server/envelope-router/distribute-envelope.types.ts b/packages/trpc/server/envelope-router/distribute-envelope.types.ts index 8ea40454f..1f34621f9 100644 --- a/packages/trpc/server/envelope-router/distribute-envelope.types.ts +++ b/packages/trpc/server/envelope-router/distribute-envelope.types.ts @@ -23,6 +23,7 @@ export const ZDistributeEnvelopeRequestSchema = z.object({ timezone: true, dateFormat: true, distributionMethod: true, + includeAuditLog: true, redirectUrl: true, language: true, emailId: true, diff --git a/packages/trpc/server/envelope-router/use-envelope.types.ts b/packages/trpc/server/envelope-router/use-envelope.types.ts index 942e459e7..ca38f89b1 100644 --- a/packages/trpc/server/envelope-router/use-envelope.types.ts +++ b/packages/trpc/server/envelope-router/use-envelope.types.ts @@ -5,6 +5,7 @@ import { ZDocumentMetaDateFormatSchema, ZDocumentMetaDistributionMethodSchema, ZDocumentMetaDrawSignatureEnabledSchema, + ZDocumentMetaIncludeAuditLogSchema, ZDocumentMetaLanguageSchema, ZDocumentMetaMessageSchema, ZDocumentMetaRedirectUrlSchema, @@ -89,6 +90,7 @@ export const ZUseEnvelopePayloadSchema = z.object({ dateFormat: ZDocumentMetaDateFormatSchema.optional(), redirectUrl: ZDocumentMetaRedirectUrlSchema.optional(), distributionMethod: ZDocumentMetaDistributionMethodSchema.optional(), + includeAuditLog: ZDocumentMetaIncludeAuditLogSchema.optional(), emailSettings: ZDocumentEmailSettingsSchema.optional(), language: ZDocumentMetaLanguageSchema.optional(), typedSignatureEnabled: ZDocumentMetaTypedSignatureEnabledSchema.optional(), diff --git a/packages/trpc/server/template-router/get-templates-by-ids.ts b/packages/trpc/server/template-router/get-templates-by-ids.ts index ba696f160..9bbcd31e3 100644 --- a/packages/trpc/server/template-router/get-templates-by-ids.ts +++ b/packages/trpc/server/template-router/get-templates-by-ids.ts @@ -61,6 +61,7 @@ export const getTemplatesByIdsRoute = authenticatedProcedure select: { signingOrder: true, distributionMethod: true, + includeAuditLog: true, }, }, directLink: { @@ -106,6 +107,7 @@ export const getTemplatesByIdsRoute = authenticatedProcedure ? { signingOrder: envelope.documentMeta.signingOrder, distributionMethod: envelope.documentMeta.distributionMethod, + includeAuditLog: envelope.documentMeta.includeAuditLog, } : null, directLink: envelope.directLink