mirror of
https://github.com/documenso/documenso.git
synced 2025-11-12 15:53:02 +10:00
fix: remove marketing (#1562)
This commit is contained in:
@ -6,7 +6,6 @@ import { fieldRouter } from './field-router/router';
|
||||
import { profileRouter } from './profile-router/router';
|
||||
import { recipientRouter } from './recipient-router/router';
|
||||
import { shareLinkRouter } from './share-link-router/router';
|
||||
import { singleplayerRouter } from './singleplayer-router/router';
|
||||
import { teamRouter } from './team-router/router';
|
||||
import { templateRouter } from './template-router/router';
|
||||
import { router } from './trpc';
|
||||
@ -22,7 +21,6 @@ export const appRouter = router({
|
||||
admin: adminRouter,
|
||||
shareLink: shareLinkRouter,
|
||||
apiToken: apiTokenRouter,
|
||||
singleplayer: singleplayerRouter,
|
||||
team: teamRouter,
|
||||
template: templateRouter,
|
||||
webhook: webhookRouter,
|
||||
|
||||
@ -1,42 +0,0 @@
|
||||
import { DateTime } from 'luxon';
|
||||
import { match } from 'ts-pattern';
|
||||
|
||||
import { FieldType, Prisma } from '@documenso/prisma/client';
|
||||
|
||||
import type { TCreateSinglePlayerDocumentMutationSchema } from './schema';
|
||||
|
||||
/**
|
||||
* Map the fields provided by the user to fields compatible with Prisma.
|
||||
*
|
||||
* Signature fields are handled separately.
|
||||
*
|
||||
* @param field The field passed in by the user.
|
||||
* @param signer The details of the person who is signing this document.
|
||||
* @returns A field compatible with Prisma.
|
||||
*/
|
||||
export const mapField = (
|
||||
field: TCreateSinglePlayerDocumentMutationSchema['fields'][number],
|
||||
signer: TCreateSinglePlayerDocumentMutationSchema['signer'],
|
||||
) => {
|
||||
const customText = match(field.type)
|
||||
.with(FieldType.DATE, () => DateTime.now().toFormat('yyyy-MM-dd hh:mm a'))
|
||||
.with(FieldType.EMAIL, () => signer.email)
|
||||
.with(FieldType.NAME, () => signer.name)
|
||||
.with(FieldType.TEXT, () => signer.customText)
|
||||
.with(FieldType.NUMBER, () => signer.customText)
|
||||
.with(FieldType.RADIO, () => signer.customText)
|
||||
.with(FieldType.CHECKBOX, () => signer.customText)
|
||||
.with(FieldType.DROPDOWN, () => signer.customText)
|
||||
.otherwise(() => '');
|
||||
|
||||
return {
|
||||
type: field.type,
|
||||
page: field.page,
|
||||
positionX: new Prisma.Decimal(field.positionX),
|
||||
positionY: new Prisma.Decimal(field.positionY),
|
||||
width: new Prisma.Decimal(field.width),
|
||||
height: new Prisma.Decimal(field.height),
|
||||
customText,
|
||||
inserted: true,
|
||||
};
|
||||
};
|
||||
@ -1,182 +0,0 @@
|
||||
import { createElement } from 'react';
|
||||
|
||||
import { PDFDocument } from 'pdf-lib';
|
||||
|
||||
import { mailer } from '@documenso/email/mailer';
|
||||
import { DocumentSelfSignedEmailTemplate } from '@documenso/email/templates/document-self-signed';
|
||||
import { NEXT_PUBLIC_WEBAPP_URL } from '@documenso/lib/constants/app';
|
||||
import { FROM_ADDRESS, FROM_NAME, SERVICE_USER_EMAIL } from '@documenso/lib/constants/email';
|
||||
import { insertFieldInPDF } from '@documenso/lib/server-only/pdf/insert-field-in-pdf';
|
||||
import { alphaid } from '@documenso/lib/universal/id';
|
||||
import { getFile } from '@documenso/lib/universal/upload/get-file';
|
||||
import { putPdfFile } from '@documenso/lib/universal/upload/put-file';
|
||||
import { renderEmailWithI18N } from '@documenso/lib/utils/render-email-with-i18n';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import {
|
||||
DocumentSource,
|
||||
DocumentStatus,
|
||||
FieldType,
|
||||
ReadStatus,
|
||||
SendStatus,
|
||||
SigningStatus,
|
||||
} from '@documenso/prisma/client';
|
||||
import { signPdf } from '@documenso/signing';
|
||||
|
||||
import { procedure, router } from '../trpc';
|
||||
import { mapField } from './helper';
|
||||
import { ZCreateSinglePlayerDocumentMutationSchema } from './schema';
|
||||
|
||||
export const singleplayerRouter = router({
|
||||
createSinglePlayerDocument: procedure
|
||||
.input(ZCreateSinglePlayerDocumentMutationSchema)
|
||||
.mutation(async ({ input }) => {
|
||||
const { signer, fields, documentData, documentName, fieldMeta } = input;
|
||||
|
||||
const document = await getFile({
|
||||
data: documentData.data,
|
||||
type: documentData.type,
|
||||
});
|
||||
|
||||
const doc = await PDFDocument.load(document);
|
||||
|
||||
const createdAt = new Date();
|
||||
|
||||
const isBase64 = signer.signature.startsWith('data:image/png;base64,');
|
||||
const signatureImageAsBase64 = isBase64 ? signer.signature : null;
|
||||
const typedSignature = !isBase64 ? signer.signature : null;
|
||||
|
||||
// Update the document with the fields inserted.
|
||||
for (const field of fields) {
|
||||
const isSignatureField = field.type === FieldType.SIGNATURE;
|
||||
|
||||
await insertFieldInPDF(doc, {
|
||||
...mapField(field, signer),
|
||||
Signature: isSignatureField
|
||||
? {
|
||||
created: createdAt,
|
||||
signatureImageAsBase64,
|
||||
typedSignature,
|
||||
// Dummy data.
|
||||
id: -1,
|
||||
recipientId: -1,
|
||||
fieldId: -1,
|
||||
}
|
||||
: null,
|
||||
// Dummy data.
|
||||
id: -1,
|
||||
secondaryId: '-1',
|
||||
documentId: -1,
|
||||
templateId: null,
|
||||
recipientId: -1,
|
||||
fieldMeta: fieldMeta || null,
|
||||
});
|
||||
}
|
||||
|
||||
const unsignedPdfBytes = await doc.save();
|
||||
|
||||
const signedPdfBuffer = await signPdf({ pdf: Buffer.from(unsignedPdfBytes) });
|
||||
|
||||
const { token } = await prisma.$transaction(
|
||||
async (tx) => {
|
||||
const token = alphaid();
|
||||
|
||||
// Fetch service user who will be the owner of the document.
|
||||
const serviceUser = await tx.user.findFirstOrThrow({
|
||||
where: {
|
||||
email: SERVICE_USER_EMAIL,
|
||||
},
|
||||
});
|
||||
|
||||
const { id: documentDataId } = await putPdfFile({
|
||||
name: `${documentName}.pdf`,
|
||||
type: 'application/pdf',
|
||||
arrayBuffer: async () => Promise.resolve(signedPdfBuffer),
|
||||
});
|
||||
|
||||
// Create document.
|
||||
const document = await tx.document.create({
|
||||
data: {
|
||||
source: DocumentSource.DOCUMENT,
|
||||
title: documentName,
|
||||
status: DocumentStatus.COMPLETED,
|
||||
documentDataId,
|
||||
userId: serviceUser.id,
|
||||
createdAt,
|
||||
},
|
||||
});
|
||||
|
||||
// Create recipient.
|
||||
const recipient = await tx.recipient.create({
|
||||
data: {
|
||||
documentId: document.id,
|
||||
name: signer.name,
|
||||
email: signer.email,
|
||||
token,
|
||||
signedAt: createdAt,
|
||||
readStatus: ReadStatus.OPENED,
|
||||
signingStatus: SigningStatus.SIGNED,
|
||||
sendStatus: SendStatus.SENT,
|
||||
},
|
||||
});
|
||||
|
||||
// Create fields and signatures.
|
||||
await Promise.all(
|
||||
fields.map(async (field) => {
|
||||
const insertedField = await tx.field.create({
|
||||
data: {
|
||||
documentId: document.id,
|
||||
recipientId: recipient.id,
|
||||
...mapField(field, signer),
|
||||
},
|
||||
});
|
||||
|
||||
if (field.type === FieldType.SIGNATURE || field.type === FieldType.FREE_SIGNATURE) {
|
||||
await tx.signature.create({
|
||||
data: {
|
||||
fieldId: insertedField.id,
|
||||
signatureImageAsBase64,
|
||||
typedSignature,
|
||||
recipientId: recipient.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
return { document, token };
|
||||
},
|
||||
{
|
||||
maxWait: 5000,
|
||||
timeout: 30000,
|
||||
},
|
||||
);
|
||||
|
||||
const template = createElement(DocumentSelfSignedEmailTemplate, {
|
||||
documentName: documentName,
|
||||
assetBaseUrl: NEXT_PUBLIC_WEBAPP_URL() || 'http://localhost:3000',
|
||||
});
|
||||
|
||||
const [html, text] = await Promise.all([
|
||||
renderEmailWithI18N(template),
|
||||
renderEmailWithI18N(template, { plainText: true }),
|
||||
]);
|
||||
|
||||
// Send email to signer.
|
||||
await mailer.sendMail({
|
||||
to: {
|
||||
address: signer.email,
|
||||
name: signer.name,
|
||||
},
|
||||
from: {
|
||||
name: FROM_NAME,
|
||||
address: FROM_ADDRESS,
|
||||
},
|
||||
subject: 'Document signed',
|
||||
html,
|
||||
text,
|
||||
attachments: [{ content: signedPdfBuffer, filename: documentName }],
|
||||
});
|
||||
|
||||
return token;
|
||||
}),
|
||||
});
|
||||
@ -1,33 +0,0 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { ZFieldMetaSchema } from '@documenso/lib/types/field-meta';
|
||||
import { DocumentDataType, FieldType } from '@documenso/prisma/client';
|
||||
|
||||
export const ZCreateSinglePlayerDocumentMutationSchema = z.object({
|
||||
documentData: z.object({
|
||||
data: z.string(),
|
||||
type: z.nativeEnum(DocumentDataType),
|
||||
}),
|
||||
documentName: z.string(),
|
||||
signer: z.object({
|
||||
email: z.string().email().min(1),
|
||||
name: z.string(),
|
||||
signature: z.string(),
|
||||
customText: z.string(),
|
||||
}),
|
||||
fields: z.array(
|
||||
z.object({
|
||||
page: z.number(),
|
||||
type: z.nativeEnum(FieldType),
|
||||
positionX: z.number(),
|
||||
positionY: z.number(),
|
||||
width: z.number(),
|
||||
height: z.number(),
|
||||
}),
|
||||
),
|
||||
fieldMeta: ZFieldMetaSchema,
|
||||
});
|
||||
|
||||
export type TCreateSinglePlayerDocumentMutationSchema = z.infer<
|
||||
typeof ZCreateSinglePlayerDocumentMutationSchema
|
||||
>;
|
||||
Reference in New Issue
Block a user