mirror of
https://github.com/documenso/documenso.git
synced 2026-07-22 16:03:39 +10:00
ba0dead96f
Currently direct templates can be created without the required signatures fields for signers. This means that the document can be fully signed by everyone but will ultimately fail the sealing step which leaves the document in an unrecoverable state.
267 lines
6.8 KiB
TypeScript
267 lines
6.8 KiB
TypeScript
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
|
|
import {
|
|
DIRECT_TEMPLATE_RECIPIENT_EMAIL,
|
|
DIRECT_TEMPLATE_RECIPIENT_NAME,
|
|
} from '@documenso/lib/constants/direct-templates';
|
|
import { incrementTemplateId } from '@documenso/lib/server-only/envelope/increment-id';
|
|
import { FIELD_SIGNATURE_META_DEFAULT_VALUES } from '@documenso/lib/types/field-meta';
|
|
import { SignatureLevel } from '@documenso/lib/types/signature-level';
|
|
import { prefixedId } from '@documenso/lib/universal/id';
|
|
|
|
import { prisma } from '..';
|
|
import type { Prisma, User } from '../client';
|
|
import {
|
|
DocumentDataType,
|
|
DocumentSource,
|
|
EnvelopeType,
|
|
FieldType,
|
|
ReadStatus,
|
|
RecipientRole,
|
|
SendStatus,
|
|
SigningStatus,
|
|
} from '../client';
|
|
|
|
const examplePdf = fs.readFileSync(path.join(__dirname, '../../../assets/example.pdf')).toString('base64');
|
|
|
|
type SeedTemplateOptions = {
|
|
title?: string;
|
|
userId: number;
|
|
teamId: number;
|
|
internalVersion?: 1 | 2;
|
|
createTemplateOptions?: Partial<Prisma.EnvelopeUncheckedCreateInput>;
|
|
/**
|
|
* Only used by seedDirectTemplate. Creates a signature field for the direct
|
|
* recipient so the seeded direct template is valid. Defaults to true.
|
|
*/
|
|
createDirectRecipientSignatureField?: boolean;
|
|
};
|
|
|
|
type CreateTemplateOptions = {
|
|
key?: string | number;
|
|
createTemplateOptions?: Partial<Prisma.EnvelopeUncheckedCreateInput>;
|
|
};
|
|
|
|
export const seedBlankTemplate = async (owner: User, teamId: number, options: CreateTemplateOptions = {}) => {
|
|
const { key, createTemplateOptions = {} } = options;
|
|
|
|
const documentData = await prisma.documentData.create({
|
|
data: {
|
|
type: DocumentDataType.BYTES_64,
|
|
data: examplePdf,
|
|
initialData: examplePdf,
|
|
},
|
|
});
|
|
|
|
const templateId = await incrementTemplateId();
|
|
|
|
const documentMeta = await prisma.documentMeta.create({
|
|
data: {},
|
|
});
|
|
|
|
return await prisma.envelope.create({
|
|
data: {
|
|
id: prefixedId('envelope'),
|
|
secondaryId: templateId.formattedTemplateId,
|
|
internalVersion: 1,
|
|
signatureLevel: SignatureLevel.SES,
|
|
type: EnvelopeType.TEMPLATE,
|
|
title: `[TEST] Template ${key}`,
|
|
teamId,
|
|
envelopeItems: {
|
|
create: {
|
|
id: prefixedId('envelope_item'),
|
|
title: `[TEST] Template ${key}`,
|
|
documentDataId: documentData.id,
|
|
order: 1,
|
|
},
|
|
},
|
|
userId: owner.id,
|
|
source: DocumentSource.TEMPLATE,
|
|
documentMetaId: documentMeta.id,
|
|
...createTemplateOptions,
|
|
},
|
|
include: {
|
|
envelopeItems: {
|
|
include: {
|
|
documentData: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
};
|
|
|
|
export const seedTemplate = async (options: SeedTemplateOptions) => {
|
|
const { title = 'Untitled', userId, teamId } = options;
|
|
|
|
const documentData = await prisma.documentData.create({
|
|
data: {
|
|
type: DocumentDataType.BYTES_64,
|
|
data: examplePdf,
|
|
initialData: examplePdf,
|
|
},
|
|
});
|
|
|
|
const templateId = await incrementTemplateId();
|
|
|
|
const documentMeta = await prisma.documentMeta.create({
|
|
data: {},
|
|
});
|
|
|
|
return await prisma.envelope.create({
|
|
data: {
|
|
id: prefixedId('envelope'),
|
|
secondaryId: templateId.formattedTemplateId,
|
|
internalVersion: options.internalVersion ?? 1,
|
|
signatureLevel: SignatureLevel.SES,
|
|
type: EnvelopeType.TEMPLATE,
|
|
title,
|
|
envelopeItems: {
|
|
create: {
|
|
id: prefixedId('envelope_item'),
|
|
title,
|
|
documentDataId: documentData.id,
|
|
order: 1,
|
|
},
|
|
},
|
|
source: DocumentSource.TEMPLATE,
|
|
documentMetaId: documentMeta.id,
|
|
userId,
|
|
teamId,
|
|
recipients: {
|
|
create: {
|
|
email: 'recipient.1@documenso.com',
|
|
name: 'Recipient 1',
|
|
token: Math.random().toString().slice(2, 7),
|
|
sendStatus: SendStatus.NOT_SENT,
|
|
signingStatus: SigningStatus.NOT_SIGNED,
|
|
readStatus: ReadStatus.NOT_OPENED,
|
|
role: RecipientRole.SIGNER,
|
|
},
|
|
},
|
|
},
|
|
include: {
|
|
envelopeItems: {
|
|
include: {
|
|
documentData: true,
|
|
},
|
|
},
|
|
recipients: true,
|
|
},
|
|
});
|
|
};
|
|
|
|
export const seedDirectTemplate = async (options: SeedTemplateOptions) => {
|
|
const { title = 'Untitled', userId, teamId } = options;
|
|
|
|
const documentData = await prisma.documentData.create({
|
|
data: {
|
|
type: DocumentDataType.BYTES_64,
|
|
data: examplePdf,
|
|
initialData: examplePdf,
|
|
},
|
|
});
|
|
|
|
const templateId = await incrementTemplateId();
|
|
|
|
const documentMeta = await prisma.documentMeta.create({
|
|
data: {},
|
|
});
|
|
|
|
const template = await prisma.envelope.create({
|
|
data: {
|
|
id: prefixedId('envelope'),
|
|
secondaryId: templateId.formattedTemplateId,
|
|
internalVersion: options.internalVersion ?? 1,
|
|
signatureLevel: SignatureLevel.SES,
|
|
type: EnvelopeType.TEMPLATE,
|
|
title,
|
|
envelopeItems: {
|
|
create: {
|
|
id: prefixedId('envelope_item'),
|
|
title,
|
|
documentDataId: documentData.id,
|
|
order: 1,
|
|
},
|
|
},
|
|
source: DocumentSource.TEMPLATE,
|
|
documentMetaId: documentMeta.id,
|
|
userId,
|
|
teamId,
|
|
recipients: {
|
|
create: {
|
|
signingOrder: 1,
|
|
email: DIRECT_TEMPLATE_RECIPIENT_EMAIL,
|
|
name: DIRECT_TEMPLATE_RECIPIENT_NAME,
|
|
token: Math.random().toString().slice(2, 7),
|
|
},
|
|
},
|
|
...options.createTemplateOptions,
|
|
},
|
|
include: {
|
|
recipients: true,
|
|
user: true,
|
|
},
|
|
});
|
|
|
|
const directTemplateRecipient = template.recipients.find(
|
|
(recipient) => recipient.email === DIRECT_TEMPLATE_RECIPIENT_EMAIL,
|
|
);
|
|
|
|
if (!directTemplateRecipient) {
|
|
throw new Error('Need to create a direct template recipient');
|
|
}
|
|
|
|
await prisma.templateDirectLink.create({
|
|
data: {
|
|
envelopeId: template.id,
|
|
enabled: true,
|
|
token: Math.random().toString(),
|
|
directTemplateRecipientId: directTemplateRecipient.id,
|
|
},
|
|
});
|
|
|
|
const { createDirectRecipientSignatureField = true } = options;
|
|
|
|
if (createDirectRecipientSignatureField) {
|
|
const envelopeItem = await prisma.envelopeItem.findFirstOrThrow({
|
|
where: { envelopeId: template.id },
|
|
});
|
|
|
|
await prisma.field.create({
|
|
data: {
|
|
envelopeId: template.id,
|
|
envelopeItemId: envelopeItem.id,
|
|
recipientId: directTemplateRecipient.id,
|
|
type: FieldType.SIGNATURE,
|
|
page: 1,
|
|
positionX: 5,
|
|
positionY: 10,
|
|
width: 20,
|
|
height: 5,
|
|
customText: '',
|
|
inserted: false,
|
|
fieldMeta: FIELD_SIGNATURE_META_DEFAULT_VALUES,
|
|
},
|
|
});
|
|
}
|
|
|
|
return await prisma.envelope.findFirstOrThrow({
|
|
where: {
|
|
id: template.id,
|
|
},
|
|
include: {
|
|
directLink: true,
|
|
fields: true,
|
|
recipients: true,
|
|
team: true,
|
|
envelopeItems: {
|
|
select: {
|
|
documentData: true,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
};
|