mirror of
https://github.com/documenso/documenso.git
synced 2026-07-27 02:15:05 +10:00
feat: add recipient role editing and audit log PDF download in admin (#2594)
- Allow admins to update recipient role from document detail page - Add download button to export audit logs as PDF - Display recipient status details in accordion - Add LocalTime component with hover popover for timestamps
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
import { EnvelopeType } from '@prisma/client';
|
||||
|
||||
import { PDF_SIZE_A4_72PPI } from '@documenso/lib/constants/pdf';
|
||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||
import { generateAuditLogPdf } from '@documenso/lib/server-only/pdf/generate-audit-log-pdf';
|
||||
import { unsafeBuildEnvelopeIdQuery } from '@documenso/lib/utils/envelope';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
import { adminProcedure } from '../trpc';
|
||||
import {
|
||||
ZAdminDownloadDocumentAuditLogsRequestSchema,
|
||||
ZAdminDownloadDocumentAuditLogsResponseSchema,
|
||||
} from './download-document-audit-logs.types';
|
||||
|
||||
export const downloadDocumentAuditLogsRoute = adminProcedure
|
||||
.input(ZAdminDownloadDocumentAuditLogsRequestSchema)
|
||||
.output(ZAdminDownloadDocumentAuditLogsResponseSchema)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const { envelopeId } = input;
|
||||
|
||||
ctx.logger.info({
|
||||
input: {
|
||||
envelopeId,
|
||||
},
|
||||
});
|
||||
|
||||
const envelope = await prisma.envelope.findFirst({
|
||||
where: unsafeBuildEnvelopeIdQuery(
|
||||
{
|
||||
type: 'envelopeId',
|
||||
id: envelopeId,
|
||||
},
|
||||
EnvelopeType.DOCUMENT,
|
||||
),
|
||||
include: {
|
||||
documentMeta: true,
|
||||
envelopeItems: true,
|
||||
user: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
email: true,
|
||||
},
|
||||
},
|
||||
recipients: {
|
||||
orderBy: {
|
||||
id: 'asc',
|
||||
},
|
||||
},
|
||||
fields: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!envelope) {
|
||||
throw new AppError(AppErrorCode.NOT_FOUND, {
|
||||
message: 'Envelope not found',
|
||||
});
|
||||
}
|
||||
|
||||
const auditLogPdf = await generateAuditLogPdf({
|
||||
envelope,
|
||||
recipients: envelope.recipients,
|
||||
fields: envelope.fields,
|
||||
language: envelope.documentMeta.language,
|
||||
envelopeOwner: {
|
||||
email: envelope.user.email,
|
||||
name: envelope.user.name || '',
|
||||
},
|
||||
envelopeItems: envelope.envelopeItems.map((item) => item.title),
|
||||
pageWidth: PDF_SIZE_A4_72PPI.width,
|
||||
pageHeight: PDF_SIZE_A4_72PPI.height,
|
||||
});
|
||||
|
||||
const result = await auditLogPdf.save();
|
||||
|
||||
const base64 = Buffer.from(result).toString('base64');
|
||||
|
||||
return {
|
||||
data: base64,
|
||||
envelopeTitle: envelope.title,
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
export const ZAdminDownloadDocumentAuditLogsRequestSchema = z.object({
|
||||
envelopeId: z.string(),
|
||||
});
|
||||
|
||||
export const ZAdminDownloadDocumentAuditLogsResponseSchema = z.object({
|
||||
data: z.string(),
|
||||
envelopeTitle: z.string(),
|
||||
});
|
||||
|
||||
export type TAdminDownloadDocumentAuditLogsRequest = z.infer<
|
||||
typeof ZAdminDownloadDocumentAuditLogsRequestSchema
|
||||
>;
|
||||
export type TAdminDownloadDocumentAuditLogsResponse = z.infer<
|
||||
typeof ZAdminDownloadDocumentAuditLogsResponseSchema
|
||||
>;
|
||||
@@ -6,6 +6,7 @@ import { deleteDocumentRoute } from './delete-document';
|
||||
import { deleteSubscriptionClaimRoute } from './delete-subscription-claim';
|
||||
import { deleteUserRoute } from './delete-user';
|
||||
import { disableUserRoute } from './disable-user';
|
||||
import { downloadDocumentAuditLogsRoute } from './download-document-audit-logs';
|
||||
import { enableUserRoute } from './enable-user';
|
||||
import { findAdminOrganisationsRoute } from './find-admin-organisations';
|
||||
import { findDocumentAuditLogsRoute } from './find-document-audit-logs';
|
||||
@@ -71,6 +72,7 @@ export const adminRouter = router({
|
||||
reseal: resealDocumentRoute,
|
||||
findJobs: findDocumentJobsRoute,
|
||||
findAuditLogs: findDocumentAuditLogsRoute,
|
||||
downloadAuditLogs: downloadDocumentAuditLogsRoute,
|
||||
},
|
||||
recipient: {
|
||||
update: updateRecipientRoute,
|
||||
|
||||
@@ -10,7 +10,7 @@ export const updateRecipientRoute = adminProcedure
|
||||
.input(ZUpdateRecipientRequestSchema)
|
||||
.output(ZUpdateRecipientResponseSchema)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const { id, name, email } = input;
|
||||
const { id, name, email, role } = input;
|
||||
|
||||
ctx.logger.info({
|
||||
input: {
|
||||
@@ -18,5 +18,5 @@ export const updateRecipientRoute = adminProcedure
|
||||
},
|
||||
});
|
||||
|
||||
await updateRecipient({ id, name, email });
|
||||
await updateRecipient({ id, name, email, role });
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ export const ZUpdateRecipientRequestSchema = z.object({
|
||||
id: z.number().min(1),
|
||||
name: z.string().optional(),
|
||||
email: z.string().email().optional(),
|
||||
role: z.enum(['CC', 'SIGNER', 'VIEWER', 'APPROVER', 'ASSISTANT']).optional(),
|
||||
});
|
||||
|
||||
export const ZUpdateRecipientResponseSchema = z.void();
|
||||
|
||||
Reference in New Issue
Block a user