diff --git a/apps/marketing/next.config.js b/apps/marketing/next.config.js index 0f7b7ad5c..c8c89e45d 100644 --- a/apps/marketing/next.config.js +++ b/apps/marketing/next.config.js @@ -22,7 +22,7 @@ const FONT_CAVEAT_BYTES = fs.readFileSync( const config = { experimental: { outputFileTracingRoot: path.join(__dirname, '../../'), - serverComponentsExternalPackages: ['@node-rs/bcrypt', '@documenso/pdf-sign'], + serverComponentsExternalPackages: ['@node-rs/bcrypt', '@documenso/pdf-sign', 'playwright'], serverActions: { bodySizeLimit: '50mb', }, diff --git a/apps/web/next.config.js b/apps/web/next.config.js index af82847c0..85d3097ca 100644 --- a/apps/web/next.config.js +++ b/apps/web/next.config.js @@ -23,7 +23,7 @@ const config = { output: process.env.DOCKER_OUTPUT ? 'standalone' : undefined, experimental: { outputFileTracingRoot: path.join(__dirname, '../../'), - serverComponentsExternalPackages: ['@node-rs/bcrypt', '@documenso/pdf-sign'], + serverComponentsExternalPackages: ['@node-rs/bcrypt', '@documenso/pdf-sign', 'playwright'], serverActions: { bodySizeLimit: '50mb', }, diff --git a/apps/web/src/app/(dashboard)/documents/[id]/logs/download-audit-log-button.tsx b/apps/web/src/app/(dashboard)/documents/[id]/logs/download-audit-log-button.tsx index fce4d4855..0847d63fa 100644 --- a/apps/web/src/app/(dashboard)/documents/[id]/logs/download-audit-log-button.tsx +++ b/apps/web/src/app/(dashboard)/documents/[id]/logs/download-audit-log-button.tsx @@ -5,6 +5,7 @@ import { DownloadIcon } from 'lucide-react'; import { trpc } from '@documenso/trpc/react'; import { cn } from '@documenso/ui/lib/utils'; import { Button } from '@documenso/ui/primitives/button'; +import { useToast } from '@documenso/ui/primitives/use-toast'; export type DownloadAuditLogButtonProps = { className?: string; @@ -12,40 +13,52 @@ export type DownloadAuditLogButtonProps = { }; export const DownloadAuditLogButton = ({ className, documentId }: DownloadAuditLogButtonProps) => { + const { toast } = useToast(); + const { mutateAsync: downloadAuditLogs, isLoading } = trpc.document.downloadAuditLogs.useMutation(); const onDownloadAuditLogsClick = async () => { - const { url } = await downloadAuditLogs({ documentId }); + try { + const { url } = await downloadAuditLogs({ documentId }); - const iframe = Object.assign(document.createElement('iframe'), { - src: url, - }); + const iframe = Object.assign(document.createElement('iframe'), { + src: url, + }); - Object.assign(iframe.style, { - position: 'fixed', - top: '0', - left: '0', - width: '0', - height: '0', - }); + Object.assign(iframe.style, { + position: 'fixed', + top: '0', + left: '0', + width: '0', + height: '0', + }); - const onLoaded = () => { - if (iframe.contentDocument?.readyState === 'complete') { - iframe.contentWindow?.print(); + const onLoaded = () => { + if (iframe.contentDocument?.readyState === 'complete') { + iframe.contentWindow?.print(); - iframe.contentWindow?.addEventListener('afterprint', () => { - document.body.removeChild(iframe); - }); - } - }; + iframe.contentWindow?.addEventListener('afterprint', () => { + document.body.removeChild(iframe); + }); + } + }; - // When the iframe has loaded, print the iframe and remove it from the dom - iframe.addEventListener('load', onLoaded); + // When the iframe has loaded, print the iframe and remove it from the dom + iframe.addEventListener('load', onLoaded); - document.body.appendChild(iframe); + document.body.appendChild(iframe); - onLoaded(); + onLoaded(); + } catch (error) { + console.error(error); + + toast({ + title: 'Something went wrong', + description: 'Sorry, we were unable to download the audit logs. Please try again later.', + variant: 'destructive', + }); + } }; return ( diff --git a/apps/web/src/app/(dashboard)/documents/[id]/logs/download-certificate-button.tsx b/apps/web/src/app/(dashboard)/documents/[id]/logs/download-certificate-button.tsx index e0ae395b4..49a330b94 100644 --- a/apps/web/src/app/(dashboard)/documents/[id]/logs/download-certificate-button.tsx +++ b/apps/web/src/app/(dashboard)/documents/[id]/logs/download-certificate-button.tsx @@ -5,6 +5,7 @@ import { DownloadIcon } from 'lucide-react'; import { trpc } from '@documenso/trpc/react'; import { cn } from '@documenso/ui/lib/utils'; import { Button } from '@documenso/ui/primitives/button'; +import { useToast } from '@documenso/ui/primitives/use-toast'; export type DownloadCertificateButtonProps = { className?: string; @@ -15,40 +16,52 @@ export const DownloadCertificateButton = ({ className, documentId, }: DownloadCertificateButtonProps) => { + const { toast } = useToast(); + const { mutateAsync: downloadCertificate, isLoading } = trpc.document.downloadCertificate.useMutation(); const onDownloadCertificatesClick = async () => { - const { url } = await downloadCertificate({ documentId }); + try { + const { url } = await downloadCertificate({ documentId }); - const iframe = Object.assign(document.createElement('iframe'), { - src: url, - }); + const iframe = Object.assign(document.createElement('iframe'), { + src: url, + }); - Object.assign(iframe.style, { - position: 'fixed', - top: '0', - left: '0', - width: '0', - height: '0', - }); + Object.assign(iframe.style, { + position: 'fixed', + top: '0', + left: '0', + width: '0', + height: '0', + }); - const onLoaded = () => { - if (iframe.contentDocument?.readyState === 'complete') { - iframe.contentWindow?.print(); + const onLoaded = () => { + if (iframe.contentDocument?.readyState === 'complete') { + iframe.contentWindow?.print(); - iframe.contentWindow?.addEventListener('afterprint', () => { - document.body.removeChild(iframe); - }); - } - }; + iframe.contentWindow?.addEventListener('afterprint', () => { + document.body.removeChild(iframe); + }); + } + }; - // When the iframe has loaded, print the iframe and remove it from the dom - iframe.addEventListener('load', onLoaded); + // When the iframe has loaded, print the iframe and remove it from the dom + iframe.addEventListener('load', onLoaded); - document.body.appendChild(iframe); + document.body.appendChild(iframe); - onLoaded(); + onLoaded(); + } catch (error) { + console.error(error); + + toast({ + title: 'Something went wrong', + description: 'Sorry, we were unable to download the certificate. Please try again later.', + variant: 'destructive', + }); + } }; return ( diff --git a/apps/web/src/app/(internal)/%5F%5Fhtmltopdf/certificate/page.tsx b/apps/web/src/app/(internal)/%5F%5Fhtmltopdf/certificate/page.tsx index 690f0eb78..4924e832b 100644 --- a/apps/web/src/app/(internal)/%5F%5Fhtmltopdf/certificate/page.tsx +++ b/apps/web/src/app/(internal)/%5F%5Fhtmltopdf/certificate/page.tsx @@ -12,10 +12,7 @@ import { getEntireDocument } from '@documenso/lib/server-only/admin/get-entire-d import { decryptSecondaryData } from '@documenso/lib/server-only/crypto/decrypt'; import { getDocumentCertificateAuditLogs } from '@documenso/lib/server-only/document/get-document-certificate-audit-logs'; import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs'; -import { - ZDocumentAuthOptionsSchema, - ZRecipientAuthOptionsSchema, -} from '@documenso/lib/types/document-auth'; +import { extractDocumentAuthMethods } from '@documenso/lib/utils/document-auth'; import { FieldType } from '@documenso/prisma/client'; import { Card, CardContent } from '@documenso/ui/primitives/card'; import { @@ -93,40 +90,30 @@ export default async function SigningCertificate({ searchParams }: SigningCertif return 'Unknown'; } - const documentAuthOptions = ZDocumentAuthOptionsSchema.parse(document.authOptions); - const recipientAuthOptions = ZRecipientAuthOptionsSchema.parse(recipient.authOptions); + const extractedAuthMethods = extractDocumentAuthMethods({ + documentAuth: document.authOptions, + recipientAuth: recipient.authOptions, + }); let authLevel = 'Email'; - if ( - documentAuthOptions.globalAccessAuth === 'ACCOUNT' || - recipientAuthOptions.accessAuth === 'ACCOUNT' - ) { + if (extractedAuthMethods.derivedRecipientAccessAuth === 'ACCOUNT') { authLevel = 'Account Authentication'; } - if ( - documentAuthOptions.globalActionAuth === 'ACCOUNT' || - recipientAuthOptions.actionAuth === 'ACCOUNT' - ) { + if (extractedAuthMethods.derivedRecipientActionAuth === 'ACCOUNT') { authLevel = 'Account Re-Authentication'; } - if ( - documentAuthOptions.globalActionAuth === 'TWO_FACTOR_AUTH' || - recipientAuthOptions.actionAuth === 'TWO_FACTOR_AUTH' - ) { - authLevel = 'Two Factor Re-Authentication'; + if (extractedAuthMethods.derivedRecipientActionAuth === 'TWO_FACTOR_AUTH') { + authLevel = 'Two-Factor Re-Authentication'; } - if ( - documentAuthOptions.globalActionAuth === 'PASSKEY' || - recipientAuthOptions.actionAuth === 'PASSKEY' - ) { + if (extractedAuthMethods.derivedRecipientActionAuth === 'PASSKEY') { authLevel = 'Passkey Re-Authentication'; } - if (recipientAuthOptions.actionAuth === 'EXPLICIT_NONE') { + if (extractedAuthMethods.derivedRecipientActionAuth === 'EXPLICIT_NONE') { authLevel = 'Email'; } @@ -284,13 +271,6 @@ export default async function SigningCertificate({ searchParams }: SigningCertif
- - {/*
- Authentication: {'
IP: {'