feat: audit logs for copying links

This commit is contained in:
Ephraim Atta-Duncan
2025-01-20 03:24:30 +00:00
parent 80dfbeb16f
commit 8b95b9a7c0
13 changed files with 178 additions and 30 deletions

View File

@ -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_SIGNING_LINK_COPIED', // When a signing link is copied.
]);
export const ZDocumentAuditLogEmailTypeSchema = z.enum([
@ -225,6 +226,16 @@ export const ZDocumentAuditLogEventDocumentDeletedSchema = z.object({
}),
});
/**
* Event: Document signing link copied.
*/
export const ZDocumentAuditLogEventDocumentSigningLinkCopiedSchema = z.object({
type: z.literal(DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_SIGNING_LINK_COPIED),
data: ZBaseRecipientDataSchema.extend({
isBulkCopy: z.boolean(),
}),
});
/**
* Event: Document field inserted.
*/
@ -490,6 +501,7 @@ export const ZDocumentAuditLogSchema = ZDocumentAuditLogBaseSchema.and(
ZDocumentAuditLogEventDocumentCompletedSchema,
ZDocumentAuditLogEventDocumentCreatedSchema,
ZDocumentAuditLogEventDocumentDeletedSchema,
ZDocumentAuditLogEventDocumentSigningLinkCopiedSchema,
ZDocumentAuditLogEventDocumentMovedToTeamSchema,
ZDocumentAuditLogEventDocumentFieldInsertedSchema,
ZDocumentAuditLogEventDocumentFieldUninsertedSchema,

View File

@ -385,6 +385,10 @@ export const formatDocumentAuditLogAction = (
anonymous: msg`Document completed`,
identified: msg`Document completed`,
}))
.with({ type: DOCUMENT_AUDIT_LOG_TYPE.DOCUMENT_SIGNING_LINK_COPIED }, () => ({
anonymous: msg`Document signing link copied`,
identified: msg`${prefix} copied the document signing link`,
}))
.exhaustive();
return {

View File

@ -25,6 +25,8 @@ import { sendDocument } from '@documenso/lib/server-only/document/send-document'
import { updateDocument } from '@documenso/lib/server-only/document/update-document';
import { symmetricEncrypt } from '@documenso/lib/universal/crypto';
import { getPresignPostUrl } from '@documenso/lib/universal/upload/server-actions';
import { createDocumentAuditLogData } from '@documenso/lib/utils/document-audit-logs';
import { prisma } from '@documenso/prisma';
import { DocumentDataType, DocumentStatus } from '@documenso/prisma/client';
import { authenticatedProcedure, procedure, router } from '../trpc';
@ -626,4 +628,37 @@ export const documentRouter = router({
url: `${NEXT_PUBLIC_WEBAPP_URL()}/__htmltopdf/certificate?d=${encrypted}`,
};
}),
createAuditLog: authenticatedProcedure
.input(
z.object({
documentId: z.number(),
type: z.literal('DOCUMENT_SIGNING_LINK_COPIED'),
data: z.object({
recipientEmail: z.string(),
recipientName: z.string(),
recipientId: z.number(),
recipientRole: z.string(),
isBulkCopy: z.boolean(),
}),
}),
)
.mutation(async ({ input, ctx }) => {
const { documentId, type, data } = input;
console.log('input', input);
console.log('copiedddd');
const auditLog = await prisma.documentAuditLog.create({
data: createDocumentAuditLogData({
type,
data,
documentId,
user: ctx.user,
metadata: ctx.metadata,
}),
});
return auditLog;
}),
});

View File

@ -16,6 +16,7 @@ import {
DocumentStatus,
RecipientRole,
} from '@documenso/prisma/client';
import { trpc } from '@documenso/trpc/react';
import { DocumentSendEmailMessageHelper } from '@documenso/ui/components/document/document-send-email-message-helper';
import { Tabs, TabsList, TabsTrigger } from '@documenso/ui/primitives/tabs';
@ -58,6 +59,8 @@ export const AddSubjectFormPartial = ({
}: AddSubjectFormProps) => {
const { _ } = useLingui();
const { mutateAsync: createAuditLog } = trpc.document.createAuditLog.useMutation();
const {
register,
handleSubmit,
@ -98,6 +101,25 @@ export const AddSubjectFormPartial = ({
const onFormSubmit = handleSubmit(onSubmit);
const { currentStep, totalSteps, previousStep } = useStep();
const onCopyLink = (recipient: Recipient) => {
toast({
title: _(msg`Copied to clipboard`),
description: _(msg`The signing link has been copied to your clipboard.`),
});
void createAuditLog({
documentId: document.id,
type: 'DOCUMENT_SIGNING_LINK_COPIED',
data: {
recipientEmail: recipient.email,
recipientName: recipient.name,
recipientId: recipient.id,
recipientRole: recipient.role,
isBulkCopy: false,
},
});
};
return (
<>
<DocumentFlowFormContainerHeader
@ -236,14 +258,7 @@ export const AddSubjectFormPartial = ({
{recipient.role !== RecipientRole.CC && (
<CopyTextButton
value={formatSigningLink(recipient.token)}
onCopySuccess={() => {
toast({
title: _(msg`Copied to clipboard`),
description: _(
msg`The signing link has been copied to your clipboard.`,
),
});
}}
onCopySuccess={() => void onCopyLink(recipient)}
badgeContentUncopied={
<p className="ml-1 text-xs">
<Trans>Copy</Trans>