fix: address per-document audit log review feedback

- backfill DocumentMeta.includeAuditLog from the effective team/org
  setting so documents created before the column keep embedding audit
  logs after deploy
- default includeAuditLog in the webhook payload schema so resending
  historical WebhookCall payloads stays backward-compatible
- allow audit-log embedding to be changed after a document is sent
  (drop the server guards and the editor checkbox lock)
- restore the commented change-detection block in updateEnvelope
This commit is contained in:
ephraimduncan
2026-06-16 11:40:36 +00:00
parent ecc99b8e4f
commit 77889270b8
5 changed files with 53 additions and 61 deletions
@@ -915,7 +915,7 @@ export const EnvelopeEditorSettingsDialog = ({ trigger, ...props }: EnvelopeEdit
<Checkbox
id="include-audit-log"
checked={field.value}
disabled={field.disabled || envelopeHasBeenSent}
disabled={field.disabled}
onCheckedChange={(checked) => field.onChange(Boolean(checked))}
/>
</FormControl>
@@ -2,13 +2,7 @@ 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,
RecipientRole,
SendStatus,
} from '@prisma/client';
import { type DocumentDistributionMethod, type DocumentSigningOrder, EnvelopeType } from '@prisma/client';
import type { SupportedLanguageCodes } from '../../constants/i18n';
import { AppError, AppErrorCode } from '../../errors/app-error';
@@ -99,28 +93,6 @@ 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: {
@@ -4,14 +4,7 @@ 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,
RecipientRole,
SendStatus,
WebhookTriggerEvents,
} from '@prisma/client';
import { DocumentStatus, EnvelopeType, FolderType, WebhookTriggerEvents } from '@prisma/client';
import { isDeepEqual } from 'remeda';
import { TEAM_DOCUMENT_VISIBILITY_MAP } from '../../constants/teams';
@@ -144,28 +137,6 @@ 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.
@@ -211,6 +182,11 @@ 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[] = [];
@@ -290,6 +266,36 @@ 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: {
+1 -1
View File
@@ -56,7 +56,7 @@ export const ZWebhookDocumentMetaSchema = z.object({
drawSignatureEnabled: z.boolean(),
language: z.string(),
distributionMethod: z.nativeEnum(DocumentDistributionMethod),
includeAuditLog: z.boolean(),
includeAuditLog: z.boolean().default(false),
emailSettings: z.any().nullable(),
});
@@ -1,2 +1,16 @@
-- AlterTable
ALTER TABLE "DocumentMeta" ADD COLUMN "includeAuditLog" BOOLEAN NOT NULL DEFAULT false;
-- Backfill existing rows from the effective team/organisation setting. Before this
-- column existed the sealing flow read `includeAuditLog` from the team settings
-- (falling back to the organisation default), so documents created prior to this
-- migration must keep that resolved value to avoid silently dropping audit-log
-- embedding after deploy.
UPDATE "DocumentMeta" AS dm
SET "includeAuditLog" = COALESCE(tgs."includeAuditLog", ogs."includeAuditLog")
FROM "Envelope" e
JOIN "Team" t ON t."id" = e."teamId"
JOIN "TeamGlobalSettings" tgs ON tgs."id" = t."teamGlobalSettingsId"
JOIN "Organisation" o ON o."id" = t."organisationId"
JOIN "OrganisationGlobalSettings" ogs ON ogs."id" = o."organisationGlobalSettingsId"
WHERE e."documentMetaId" = dm."id";