From a7594c9b3c8fe4e934c3c2efbe1684e96d8cc59f Mon Sep 17 00:00:00 2001 From: Lucas Smith Date: Sat, 16 Mar 2024 11:06:33 +0000 Subject: [PATCH] fix: update sending logic --- .../lib/server-only/document/seal-document.ts | 5 +- .../document/send-completed-email.ts | 168 +++++++++++------- 2 files changed, 109 insertions(+), 64 deletions(-) diff --git a/packages/lib/server-only/document/seal-document.ts b/packages/lib/server-only/document/seal-document.ts index d9cf8d392..95b7d9dc4 100644 --- a/packages/lib/server-only/document/seal-document.ts +++ b/packages/lib/server-only/document/seal-document.ts @@ -12,7 +12,6 @@ import { DocumentStatus, RecipientRole, SigningStatus } from '@documenso/prisma/ import { WebhookTriggerEvents } from '@documenso/prisma/client'; import { signPdf } from '@documenso/signing'; -import { getRequiredServerComponentSession } from '../../next-auth/get-server-component-session'; import type { RequestMetadata } from '../../universal/extract-request-metadata'; import { getFile } from '../../universal/upload/get-file'; import { putFile } from '../../universal/upload/put-file'; @@ -47,8 +46,6 @@ export const sealDocument = async ({ const { documentData } = document; - const { user: documentOwner } = await getRequiredServerComponentSession(); - if (!documentData) { throw new Error(`Document ${document.id} has no document data`); } @@ -172,7 +169,7 @@ export const sealDocument = async ({ }); if (sendEmail && !isResealing) { - await sendCompletedEmail({ documentId, requestMetadata, documentOwner }); + await sendCompletedEmail({ documentId, requestMetadata }); } await triggerWebhook({ diff --git a/packages/lib/server-only/document/send-completed-email.ts b/packages/lib/server-only/document/send-completed-email.ts index b797231c8..7ff99bbdf 100644 --- a/packages/lib/server-only/document/send-completed-email.ts +++ b/packages/lib/server-only/document/send-completed-email.ts @@ -4,7 +4,6 @@ import { mailer } from '@documenso/email/mailer'; import { render } from '@documenso/email/render'; import { DocumentCompletedEmailTemplate } from '@documenso/email/templates/document-completed'; import { prisma } from '@documenso/prisma'; -import type { User } from '@documenso/prisma/client'; import { NEXT_PUBLIC_WEBAPP_URL } from '../../constants/app'; import { DOCUMENT_AUDIT_LOG_TYPE } from '../../types/document-audit-logs'; @@ -15,14 +14,9 @@ import { createDocumentAuditLogData } from '../../utils/document-audit-logs'; export interface SendDocumentOptions { documentId: number; requestMetadata?: RequestMetadata; - documentOwner: User; } -export const sendCompletedEmail = async ({ - documentId, - requestMetadata, - documentOwner, -}: SendDocumentOptions) => { +export const sendCompletedEmail = async ({ documentId, requestMetadata }: SendDocumentOptions) => { const document = await prisma.document.findUnique({ where: { id: documentId, @@ -30,6 +24,13 @@ export const sendCompletedEmail = async ({ include: { documentData: true, Recipient: true, + User: true, + team: { + select: { + id: true, + url: true, + }, + }, }, }); @@ -41,69 +42,116 @@ export const sendCompletedEmail = async ({ throw new Error('Document has no recipients'); } - const buffer = await getFile(document.documentData); + const { User: owner } = document; + + const completedDocument = await getFile(document.documentData); + + const assetBaseUrl = NEXT_PUBLIC_WEBAPP_URL() || 'http://localhost:3000'; + + let documentOwnerDownloadLink = `${NEXT_PUBLIC_WEBAPP_URL()}/documents/${document.id}`; + + if (document.team?.url) { + documentOwnerDownloadLink = `${NEXT_PUBLIC_WEBAPP_URL()}/t/${document.team.url}/documents/${ + document.id + }`; + } + + // If the document owner is not a recipient then send the email to them separately + if (!document.Recipient.find((recipient) => recipient.email === owner.email)) { + const template = createElement(DocumentCompletedEmailTemplate, { + documentName: document.title, + assetBaseUrl, + downloadLink: documentOwnerDownloadLink, + }); + + await mailer.sendMail({ + to: [ + { + name: owner.name || '', + address: owner.email, + }, + ], + from: { + name: process.env.NEXT_PRIVATE_SMTP_FROM_NAME || 'Documenso', + address: process.env.NEXT_PRIVATE_SMTP_FROM_ADDRESS || 'noreply@documenso.com', + }, + subject: 'Signing Complete!', + html: render(template), + text: render(template, { plainText: true }), + attachments: [ + { + filename: document.title, + content: Buffer.from(completedDocument), + }, + ], + }); + + await prisma.documentAuditLog.create({ + data: createDocumentAuditLogData({ + type: DOCUMENT_AUDIT_LOG_TYPE.EMAIL_SENT, + documentId: document.id, + user: null, + requestMetadata, + data: { + emailType: 'DOCUMENT_COMPLETED', + recipientEmail: owner.email, + recipientName: owner.name, + recipientId: owner.id, + recipientRole: 'OWNER', + isResending: false, + }, + }), + }); + } await Promise.all( document.Recipient.map(async (recipient) => { - const { email, name, token } = recipient; - - const assetBaseUrl = NEXT_PUBLIC_WEBAPP_URL() || 'http://localhost:3000'; + const downloadLink = `${NEXT_PUBLIC_WEBAPP_URL()}/sign/${recipient.token}/complete`; const template = createElement(DocumentCompletedEmailTemplate, { documentName: document.title, assetBaseUrl, - downloadLink: `${NEXT_PUBLIC_WEBAPP_URL()}/sign/${token}/complete`, + downloadLink: recipient.email === owner.email ? documentOwnerDownloadLink : downloadLink, }); - await prisma.$transaction( - async (tx) => { - await mailer.sendMail({ - to: [ - // To send email to recipient of the document - { - address: email, - name, - }, - // To send email to owner of the document - { - address: documentOwner.email, - name: documentOwner.name!, - }, - ], - from: { - name: process.env.NEXT_PRIVATE_SMTP_FROM_NAME || 'Documenso', - address: process.env.NEXT_PRIVATE_SMTP_FROM_ADDRESS || 'noreply@documenso.com', - }, - subject: 'Signing Complete!', - html: render(template), - text: render(template, { plainText: true }), - attachments: [ - { - filename: document.title, - content: Buffer.from(buffer), - }, - ], - }); - - await tx.documentAuditLog.create({ - data: createDocumentAuditLogData({ - type: DOCUMENT_AUDIT_LOG_TYPE.EMAIL_SENT, - documentId: document.id, - user: null, - requestMetadata, - data: { - emailType: 'DOCUMENT_COMPLETED', - recipientEmail: recipient.email, - recipientName: recipient.name, - recipientId: recipient.id, - recipientRole: recipient.role, - isResending: false, - }, - }), - }); + await mailer.sendMail({ + to: [ + { + name: recipient.name, + address: recipient.email, + }, + ], + from: { + name: process.env.NEXT_PRIVATE_SMTP_FROM_NAME || 'Documenso', + address: process.env.NEXT_PRIVATE_SMTP_FROM_ADDRESS || 'noreply@documenso.com', }, - { timeout: 30_000 }, - ); + subject: 'Signing Complete!', + html: render(template), + text: render(template, { plainText: true }), + attachments: [ + { + filename: document.title, + content: Buffer.from(completedDocument), + }, + ], + }); + + await prisma.documentAuditLog.create({ + data: createDocumentAuditLogData({ + type: DOCUMENT_AUDIT_LOG_TYPE.EMAIL_SENT, + documentId: document.id, + user: null, + requestMetadata, + data: { + emailType: 'DOCUMENT_COMPLETED', + recipientEmail: recipient.email, + recipientName: recipient.name, + recipientId: recipient.id, + recipientRole: recipient.role, + isResending: false, + }, + }), + }); }), ); };