mirror of
https://github.com/documenso/documenso.git
synced 2025-11-13 08:13:56 +10:00
feat: enhance document attachment handling and audit logging
- Added support for attachment updates in the updateDocument functionc. - Introduced new audit log type for document attachments updates. - Updated ZDocumentAuditLog schemas to include attachment-related events. - Modified AddSettingsFormPartial to handle attachment IDs and types correctly. - Set default value for attachment type in the Prisma schema.
This commit is contained in:
@ -69,6 +69,7 @@ export const updateDocument = async ({
|
||||
},
|
||||
},
|
||||
},
|
||||
attachments: true,
|
||||
},
|
||||
});
|
||||
|
||||
@ -160,6 +161,8 @@ export const updateDocument = async ({
|
||||
documentGlobalActionAuth === undefined || documentGlobalActionAuth === newGlobalActionAuth;
|
||||
const isDocumentVisibilitySame =
|
||||
data.visibility === undefined || data.visibility === document.visibility;
|
||||
const isAttachmentsSame =
|
||||
data.attachments === undefined || data.attachments === document.attachments;
|
||||
|
||||
const auditLogs: CreateDocumentAuditLogDataResponse[] = [];
|
||||
|
||||
@ -239,6 +242,20 @@ export const updateDocument = async ({
|
||||
);
|
||||
}
|
||||
|
||||
if (data.attachments) {
|
||||
auditLogs.push(
|
||||
createDocumentAuditLogData({
|
||||
type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_ATTACHMENTS_UPDATED,
|
||||
documentId,
|
||||
metadata: requestMetadata,
|
||||
data: {
|
||||
from: document.attachments,
|
||||
to: data.attachments,
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// Early return if nothing is required.
|
||||
if (auditLogs.length === 0 && data.useLegacyFieldInsertion === undefined) {
|
||||
return document;
|
||||
@ -260,18 +277,42 @@ export const updateDocument = async ({
|
||||
visibility: data.visibility as DocumentVisibility,
|
||||
useLegacyFieldInsertion: data.useLegacyFieldInsertion,
|
||||
authOptions,
|
||||
attachments: {
|
||||
deleteMany: {},
|
||||
create:
|
||||
data.attachments?.map((attachment) => ({
|
||||
type: 'LINK',
|
||||
label: attachment.label,
|
||||
url: attachment.url,
|
||||
})) || [],
|
||||
},
|
||||
});
|
||||
|
||||
if (data.attachments) {
|
||||
await tx.attachment.deleteMany({
|
||||
where: {
|
||||
documentId,
|
||||
id: {
|
||||
notIn: data.attachments.map((a) => a.id),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
await Promise.all(
|
||||
data.attachments.map(
|
||||
async (attachment) =>
|
||||
await tx.attachment.upsert({
|
||||
where: {
|
||||
id: attachment.id,
|
||||
documentId,
|
||||
},
|
||||
update: {
|
||||
label: attachment.label,
|
||||
url: attachment.url,
|
||||
},
|
||||
create: {
|
||||
id: attachment.id,
|
||||
label: attachment.label,
|
||||
url: attachment.url,
|
||||
documentId,
|
||||
},
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
await tx.documentAuditLog.createMany({
|
||||
data: auditLogs,
|
||||
});
|
||||
|
||||
@ -39,6 +39,7 @@ export const ZDocumentAuditLogTypeSchema = z.enum([
|
||||
'DOCUMENT_TITLE_UPDATED', // When the document title is updated.
|
||||
'DOCUMENT_EXTERNAL_ID_UPDATED', // When the document external ID is updated.
|
||||
'DOCUMENT_MOVED_TO_TEAM', // When the document is moved to a team.
|
||||
'DOCUMENT_ATTACHMENTS_UPDATED', // When the document attachments are updated.
|
||||
]);
|
||||
|
||||
export const ZDocumentAuditLogEmailTypeSchema = z.enum([
|
||||
@ -551,6 +552,29 @@ export const ZDocumentAuditLogEventDocumentMovedToTeamSchema = z.object({
|
||||
}),
|
||||
});
|
||||
|
||||
/**
|
||||
* Event: Document attachments updated.
|
||||
*/
|
||||
export const ZDocumentAuditLogEventDocumentAttachmentsUpdatedSchema = z.object({
|
||||
type: z.literal(DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_ATTACHMENTS_UPDATED),
|
||||
data: z.object({
|
||||
from: z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
label: z.string(),
|
||||
url: z.string(),
|
||||
}),
|
||||
),
|
||||
to: z.array(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
label: z.string(),
|
||||
url: z.string(),
|
||||
}),
|
||||
),
|
||||
}),
|
||||
});
|
||||
|
||||
export const ZDocumentAuditLogBaseSchema = z.object({
|
||||
id: z.string(),
|
||||
createdAt: z.date(),
|
||||
@ -582,6 +606,7 @@ export const ZDocumentAuditLogSchema = ZDocumentAuditLogBaseSchema.and(
|
||||
ZDocumentAuditLogEventDocumentSentSchema,
|
||||
ZDocumentAuditLogEventDocumentTitleUpdatedSchema,
|
||||
ZDocumentAuditLogEventDocumentExternalIdUpdatedSchema,
|
||||
ZDocumentAuditLogEventDocumentAttachmentsUpdatedSchema,
|
||||
ZDocumentAuditLogEventFieldCreatedSchema,
|
||||
ZDocumentAuditLogEventFieldRemovedSchema,
|
||||
ZDocumentAuditLogEventFieldUpdatedSchema,
|
||||
|
||||
@ -62,7 +62,6 @@ export const ZDocumentSchema = DocumentSchema.pick({
|
||||
fields: ZFieldSchema.array(),
|
||||
attachments: AttachmentSchema.pick({
|
||||
id: true,
|
||||
type: true,
|
||||
label: true,
|
||||
url: true,
|
||||
})
|
||||
|
||||
@ -388,6 +388,10 @@ export const formatDocumentAuditLogAction = (
|
||||
anonymous: msg`Document completed`,
|
||||
identified: msg`Document completed`,
|
||||
}))
|
||||
.with({ type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_ATTACHMENTS_UPDATED }, ({ data }) => ({
|
||||
anonymous: msg`Document attachments updated`,
|
||||
identified: msg`${prefix} updated the document attachments ${data.to.map((a) => a.label).join(', ')}`,
|
||||
}))
|
||||
.exhaustive();
|
||||
|
||||
return {
|
||||
|
||||
@ -0,0 +1,2 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Attachment" ALTER COLUMN "type" SET DEFAULT 'LINK';
|
||||
@ -323,7 +323,7 @@ enum AttachmentType {
|
||||
|
||||
model Attachment {
|
||||
id String @id @default(uuid())
|
||||
type AttachmentType
|
||||
type AttachmentType @default(LINK)
|
||||
label String
|
||||
url String
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@ -97,9 +97,11 @@ export const AddSettingsFormPartial = ({
|
||||
|
||||
const defaultAttachments = [
|
||||
{
|
||||
id: '',
|
||||
formId: initialId,
|
||||
label: '',
|
||||
url: '',
|
||||
type: 'LINK',
|
||||
},
|
||||
];
|
||||
|
||||
@ -123,7 +125,12 @@ export const AddSettingsFormPartial = ({
|
||||
language: document.documentMeta?.language ?? 'en',
|
||||
signatureTypes: extractTeamSignatureSettings(document.documentMeta),
|
||||
},
|
||||
attachments: document.attachments ?? defaultAttachments,
|
||||
attachments:
|
||||
document.attachments?.map((attachment) => ({
|
||||
...attachment,
|
||||
id: String(attachment.id),
|
||||
formId: String(attachment.id),
|
||||
})) ?? defaultAttachments,
|
||||
},
|
||||
});
|
||||
|
||||
@ -136,6 +143,22 @@ export const AddSettingsFormPartial = ({
|
||||
name: 'attachments',
|
||||
});
|
||||
|
||||
const onRemoveAttachment = (index: number) => {
|
||||
const attachment = attachments[index];
|
||||
|
||||
const formStateIndex =
|
||||
form.getValues('attachments')?.findIndex((a) => a.formId === attachment.formId) ?? -1;
|
||||
|
||||
if (formStateIndex !== -1) {
|
||||
removeAttachment(formStateIndex);
|
||||
|
||||
const updatedAttachments =
|
||||
form.getValues('attachments')?.filter((a) => a.formId !== attachment.formId) ?? [];
|
||||
|
||||
form.setValue('attachments', updatedAttachments);
|
||||
}
|
||||
};
|
||||
|
||||
const { stepIndex, currentStep, totalSteps, previousStep } = useStep();
|
||||
|
||||
const documentHasBeenSent = recipients.some(
|
||||
@ -144,11 +167,11 @@ export const AddSettingsFormPartial = ({
|
||||
|
||||
const onAddAttachment = () => {
|
||||
appendAttachment({
|
||||
id: nanoid(12),
|
||||
formId: nanoid(12),
|
||||
label: '',
|
||||
url: '',
|
||||
// fix this
|
||||
id: '',
|
||||
type: 'LINK',
|
||||
});
|
||||
};
|
||||
|
||||
@ -533,7 +556,7 @@ export const AddSettingsFormPartial = ({
|
||||
|
||||
<div className="flex-none pt-8">
|
||||
<button
|
||||
onClick={() => removeAttachment(index)}
|
||||
onClick={() => onRemoveAttachment(index)}
|
||||
className="hover:bg-muted rounded-md"
|
||||
>
|
||||
<Trash className="h-4 w-4" />
|
||||
|
||||
@ -63,6 +63,7 @@ export const ZAddSettingsFormSchema = z.object({
|
||||
id: true,
|
||||
label: true,
|
||||
url: true,
|
||||
type: true,
|
||||
})
|
||||
.extend({
|
||||
formId: z.string().min(1),
|
||||
|
||||
Reference in New Issue
Block a user