mirror of
https://github.com/documenso/documenso.git
synced 2025-11-13 08:13:56 +10:00
feat: initial document audit logs implementation (#922)
Added initial implementation of document audit logs.
This commit is contained in:
@ -1,3 +1,9 @@
|
||||
import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs';
|
||||
import type { RequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
|
||||
import {
|
||||
createDocumentAuditLogData,
|
||||
diffFieldChanges,
|
||||
} from '@documenso/lib/utils/document-audit-logs';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import type { FieldType } from '@documenso/prisma/client';
|
||||
import { SendStatus, SigningStatus } from '@documenso/prisma/client';
|
||||
@ -15,12 +21,14 @@ export interface SetFieldsForDocumentOptions {
|
||||
pageWidth: number;
|
||||
pageHeight: number;
|
||||
}[];
|
||||
requestMetadata?: RequestMetadata;
|
||||
}
|
||||
|
||||
export const setFieldsForDocument = async ({
|
||||
userId,
|
||||
documentId,
|
||||
fields,
|
||||
requestMetadata,
|
||||
}: SetFieldsForDocumentOptions) => {
|
||||
const document = await prisma.document.findFirst({
|
||||
where: {
|
||||
@ -42,6 +50,17 @@ export const setFieldsForDocument = async ({
|
||||
},
|
||||
});
|
||||
|
||||
const user = await prisma.user.findFirstOrThrow({
|
||||
where: {
|
||||
id: userId,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
email: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!document) {
|
||||
throw new Error('Document not found');
|
||||
}
|
||||
@ -79,56 +98,123 @@ export const setFieldsForDocument = async ({
|
||||
);
|
||||
});
|
||||
|
||||
const persistedFields = await prisma.$transaction(
|
||||
// Disabling as wrapping promises here causes type issues
|
||||
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
||||
linkedFields.map((field) =>
|
||||
prisma.field.upsert({
|
||||
where: {
|
||||
id: field._persisted?.id ?? -1,
|
||||
documentId,
|
||||
},
|
||||
update: {
|
||||
page: field.pageNumber,
|
||||
positionX: field.pageX,
|
||||
positionY: field.pageY,
|
||||
width: field.pageWidth,
|
||||
height: field.pageHeight,
|
||||
},
|
||||
create: {
|
||||
type: field.type,
|
||||
page: field.pageNumber,
|
||||
positionX: field.pageX,
|
||||
positionY: field.pageY,
|
||||
width: field.pageWidth,
|
||||
height: field.pageHeight,
|
||||
customText: '',
|
||||
inserted: false,
|
||||
Document: {
|
||||
connect: {
|
||||
id: documentId,
|
||||
},
|
||||
const persistedFields = await prisma.$transaction(async (tx) => {
|
||||
await Promise.all(
|
||||
linkedFields.map(async (field) => {
|
||||
const fieldSignerEmail = field.signerEmail.toLowerCase();
|
||||
|
||||
const upsertedField = await tx.field.upsert({
|
||||
where: {
|
||||
id: field._persisted?.id ?? -1,
|
||||
documentId,
|
||||
},
|
||||
Recipient: {
|
||||
connect: {
|
||||
documentId_email: {
|
||||
documentId,
|
||||
email: field.signerEmail.toLowerCase(),
|
||||
update: {
|
||||
page: field.pageNumber,
|
||||
positionX: field.pageX,
|
||||
positionY: field.pageY,
|
||||
width: field.pageWidth,
|
||||
height: field.pageHeight,
|
||||
},
|
||||
create: {
|
||||
type: field.type,
|
||||
page: field.pageNumber,
|
||||
positionX: field.pageX,
|
||||
positionY: field.pageY,
|
||||
width: field.pageWidth,
|
||||
height: field.pageHeight,
|
||||
customText: '',
|
||||
inserted: false,
|
||||
Document: {
|
||||
connect: {
|
||||
id: documentId,
|
||||
},
|
||||
},
|
||||
Recipient: {
|
||||
connect: {
|
||||
documentId_email: {
|
||||
documentId,
|
||||
email: fieldSignerEmail,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (upsertedField.recipientId === null) {
|
||||
throw new Error('Not possible');
|
||||
}
|
||||
|
||||
const baseAuditLog = {
|
||||
fieldId: upsertedField.secondaryId,
|
||||
fieldRecipientEmail: fieldSignerEmail,
|
||||
fieldRecipientId: upsertedField.recipientId,
|
||||
fieldType: upsertedField.type,
|
||||
};
|
||||
|
||||
const changes = field._persisted ? diffFieldChanges(field._persisted, upsertedField) : [];
|
||||
|
||||
// Handle field updated audit log.
|
||||
if (field._persisted && changes.length > 0) {
|
||||
await tx.documentAuditLog.create({
|
||||
data: createDocumentAuditLogData({
|
||||
type: DOCUMENT_AUDIT_LOG_TYPE.FIELD_UPDATED,
|
||||
documentId: documentId,
|
||||
user,
|
||||
requestMetadata,
|
||||
data: {
|
||||
changes,
|
||||
...baseAuditLog,
|
||||
},
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
// Handle field created audit log.
|
||||
if (!field._persisted) {
|
||||
await tx.documentAuditLog.create({
|
||||
data: createDocumentAuditLogData({
|
||||
type: DOCUMENT_AUDIT_LOG_TYPE.FIELD_CREATED,
|
||||
documentId: documentId,
|
||||
user,
|
||||
requestMetadata,
|
||||
data: {
|
||||
...baseAuditLog,
|
||||
},
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
return upsertedField;
|
||||
}),
|
||||
),
|
||||
);
|
||||
);
|
||||
});
|
||||
|
||||
if (removedFields.length > 0) {
|
||||
await prisma.field.deleteMany({
|
||||
where: {
|
||||
id: {
|
||||
in: removedFields.map((field) => field.id),
|
||||
await prisma.$transaction(async (tx) => {
|
||||
await tx.field.deleteMany({
|
||||
where: {
|
||||
id: {
|
||||
in: removedFields.map((field) => field.id),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await tx.documentAuditLog.createMany({
|
||||
data: removedFields.map((field) =>
|
||||
createDocumentAuditLogData({
|
||||
type: DOCUMENT_AUDIT_LOG_TYPE.FIELD_DELETED,
|
||||
documentId: documentId,
|
||||
user,
|
||||
requestMetadata,
|
||||
data: {
|
||||
fieldId: field.secondaryId,
|
||||
fieldRecipientEmail: field.Recipient?.email ?? '',
|
||||
fieldRecipientId: field.recipientId ?? -1,
|
||||
fieldType: field.type,
|
||||
},
|
||||
}),
|
||||
),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user