Merge branch 'main' of https://github.com/documenso/documenso into document-super-delete#1020

This commit is contained in:
Rohit Saluja
2024-03-26 20:44:47 +05:30
113 changed files with 7376 additions and 1513 deletions

View File

@ -1,13 +1,30 @@
import { prisma } from '@documenso/prisma';
import type { DocumentWithRecipient } from '@documenso/prisma/types/document-with-recipient';
export interface GetDocumentAndSenderByTokenOptions {
export type GetDocumentByTokenOptions = {
token: string;
}
};
export interface GetDocumentAndRecipientByTokenOptions {
token: string;
}
export type GetDocumentAndSenderByTokenOptions = GetDocumentByTokenOptions;
export type GetDocumentAndRecipientByTokenOptions = GetDocumentByTokenOptions;
export const getDocumentByToken = async ({ token }: GetDocumentByTokenOptions) => {
if (!token) {
throw new Error('Missing token');
}
const result = await prisma.document.findFirstOrThrow({
where: {
Recipient: {
some: {
token,
},
},
},
});
return result;
};
export const getDocumentAndSenderByToken = async ({
token,

View File

@ -0,0 +1,32 @@
import { prisma } from '@documenso/prisma';
import type { DocumentWithDetails } from '@documenso/prisma/types/document';
import { getDocumentWhereInput } from './get-document-by-id';
export type GetDocumentWithDetailsByIdOptions = {
id: number;
userId: number;
teamId?: number;
};
export const getDocumentWithDetailsById = async ({
id,
userId,
teamId,
}: GetDocumentWithDetailsByIdOptions): Promise<DocumentWithDetails> => {
const documentWhereInput = await getDocumentWhereInput({
documentId: id,
userId,
teamId,
});
return await prisma.document.findFirstOrThrow({
where: documentWhereInput,
include: {
documentData: true,
documentMeta: true,
Recipient: true,
Field: true,
},
});
};

View File

@ -24,6 +24,13 @@ export const sendCompletedEmail = async ({ documentId, requestMetadata }: SendDo
include: {
documentData: true,
Recipient: true,
User: true,
team: {
select: {
id: true,
url: true,
},
},
},
});
@ -35,61 +42,116 @@ export const sendCompletedEmail = async ({ documentId, requestMetadata }: SendDo
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: {
address: email,
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,
},
}),
});
}),
);
};