mirror of
https://github.com/documenso/documenso.git
synced 2026-07-25 17:35:05 +10:00
feat: configure audit log embedding per document
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -40,6 +40,7 @@ export const ZEnvelopeForSigningResponse = z.object({
|
||||
documentMeta: DocumentMetaSchema.pick({
|
||||
signingOrder: true,
|
||||
distributionMethod: true,
|
||||
includeAuditLog: true,
|
||||
timezone: true,
|
||||
dateFormat: true,
|
||||
redirectUrl: true,
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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}`,
|
||||
});
|
||||
|
||||
@@ -47,6 +47,7 @@ export const generateSampleWebhookPayload = (event: WebhookTriggerEvents, webhoo
|
||||
drawSignatureEnabled: true,
|
||||
language: 'en',
|
||||
distributionMethod: DocumentDistributionMethod.EMAIL,
|
||||
includeAuditLog: false,
|
||||
emailSettings: null,
|
||||
},
|
||||
recipients: [
|
||||
|
||||
Reference in New Issue
Block a user