mirror of
https://github.com/documenso/documenso.git
synced 2025-11-10 04:22:32 +10:00
## Description General enhancements for templates. ## Changes Made Added the following changes to the template flow: - Allow adding document meta settings - Allow adding email settings - Allow adding document access & action authentication - Allow adding recipient action authentication - Save the state between template steps similar to how it works for documents Other changes: - Extract common fields between document and template flows - Remove the title field from "Use template" since we now have it as part of the template flow - Add new API endpoint for generating templates ## Testing Performed Added E2E tests for templates and creating documents from templates
302 lines
8.5 KiB
TypeScript
302 lines
8.5 KiB
TypeScript
import { z } from 'zod';
|
|
|
|
import { ZUrlSchema } from '@documenso/lib/schemas/common';
|
|
import {
|
|
FieldType,
|
|
ReadStatus,
|
|
RecipientRole,
|
|
SendStatus,
|
|
SigningStatus,
|
|
} from '@documenso/prisma/client';
|
|
|
|
/**
|
|
* Documents
|
|
*/
|
|
export const ZGetDocumentsQuerySchema = z.object({
|
|
page: z.coerce.number().min(1).optional().default(1),
|
|
perPage: z.coerce.number().min(1).optional().default(1),
|
|
});
|
|
|
|
export type TGetDocumentsQuerySchema = z.infer<typeof ZGetDocumentsQuerySchema>;
|
|
|
|
export const ZDeleteDocumentMutationSchema = null;
|
|
|
|
export type TDeleteDocumentMutationSchema = typeof ZDeleteDocumentMutationSchema;
|
|
|
|
export const ZSuccessfulDocumentResponseSchema = z.object({
|
|
id: z.number(),
|
|
userId: z.number(),
|
|
teamId: z.number().nullish(),
|
|
title: z.string(),
|
|
status: z.string(),
|
|
documentDataId: z.string(),
|
|
createdAt: z.date(),
|
|
updatedAt: z.date(),
|
|
completedAt: z.date().nullable(),
|
|
});
|
|
|
|
export const ZSuccessfulGetDocumentResponseSchema = ZSuccessfulDocumentResponseSchema.extend({
|
|
recipients: z.lazy(() => z.array(ZSuccessfulRecipientResponseSchema)),
|
|
});
|
|
|
|
export type TSuccessfulGetDocumentResponseSchema = z.infer<
|
|
typeof ZSuccessfulGetDocumentResponseSchema
|
|
>;
|
|
|
|
export type TSuccessfulDocumentResponseSchema = z.infer<typeof ZSuccessfulDocumentResponseSchema>;
|
|
|
|
export const ZSendDocumentForSigningMutationSchema = null;
|
|
|
|
export type TSendDocumentForSigningMutationSchema = typeof ZSendDocumentForSigningMutationSchema;
|
|
|
|
export const ZUploadDocumentSuccessfulSchema = z.object({
|
|
url: z.string(),
|
|
key: z.string(),
|
|
});
|
|
|
|
export const ZDownloadDocumentSuccessfulSchema = z.object({
|
|
downloadUrl: z.string(),
|
|
});
|
|
|
|
export type TUploadDocumentSuccessfulSchema = z.infer<typeof ZUploadDocumentSuccessfulSchema>;
|
|
|
|
export const ZCreateDocumentMutationSchema = z.object({
|
|
title: z.string().min(1),
|
|
recipients: z.array(
|
|
z.object({
|
|
name: z.string().min(1),
|
|
email: z.string().email().min(1),
|
|
role: z.nativeEnum(RecipientRole).optional().default(RecipientRole.SIGNER),
|
|
}),
|
|
),
|
|
meta: z
|
|
.object({
|
|
subject: z.string(),
|
|
message: z.string(),
|
|
timezone: z.string(),
|
|
dateFormat: z.string(),
|
|
redirectUrl: z.string(),
|
|
})
|
|
.partial(),
|
|
formValues: z.record(z.string(), z.union([z.string(), z.boolean(), z.number()])).optional(),
|
|
});
|
|
|
|
export type TCreateDocumentMutationSchema = z.infer<typeof ZCreateDocumentMutationSchema>;
|
|
|
|
export const ZCreateDocumentMutationResponseSchema = z.object({
|
|
uploadUrl: z.string().min(1),
|
|
documentId: z.number(),
|
|
recipients: z.array(
|
|
z.object({
|
|
recipientId: z.number(),
|
|
token: z.string(),
|
|
role: z.nativeEnum(RecipientRole),
|
|
}),
|
|
),
|
|
});
|
|
|
|
export type TCreateDocumentMutationResponseSchema = z.infer<
|
|
typeof ZCreateDocumentMutationResponseSchema
|
|
>;
|
|
|
|
export const ZCreateDocumentFromTemplateMutationSchema = z.object({
|
|
title: z.string().min(1),
|
|
recipients: z.array(
|
|
z.object({
|
|
name: z.string().min(1),
|
|
email: z.string().email().min(1),
|
|
role: z.nativeEnum(RecipientRole).optional().default(RecipientRole.SIGNER),
|
|
}),
|
|
),
|
|
meta: z
|
|
.object({
|
|
subject: z.string(),
|
|
message: z.string(),
|
|
timezone: z.string(),
|
|
dateFormat: z.string(),
|
|
redirectUrl: z.string(),
|
|
})
|
|
.partial()
|
|
.optional(),
|
|
formValues: z.record(z.string(), z.union([z.string(), z.boolean(), z.number()])).optional(),
|
|
});
|
|
|
|
export type TCreateDocumentFromTemplateMutationSchema = z.infer<
|
|
typeof ZCreateDocumentFromTemplateMutationSchema
|
|
>;
|
|
|
|
export const ZCreateDocumentFromTemplateMutationResponseSchema = z.object({
|
|
documentId: z.number(),
|
|
recipients: z.array(
|
|
z.object({
|
|
recipientId: z.number(),
|
|
name: z.string(),
|
|
email: z.string().email().min(1),
|
|
token: z.string(),
|
|
role: z.nativeEnum(RecipientRole).optional().default(RecipientRole.SIGNER),
|
|
}),
|
|
),
|
|
});
|
|
|
|
export type TCreateDocumentFromTemplateMutationResponseSchema = z.infer<
|
|
typeof ZCreateDocumentFromTemplateMutationResponseSchema
|
|
>;
|
|
|
|
export const ZGenerateDocumentFromTemplateMutationSchema = z.object({
|
|
title: z.string().optional(),
|
|
recipients: z
|
|
.array(
|
|
z.object({
|
|
id: z.number(),
|
|
name: z.string().optional(),
|
|
email: z.string().email().min(1),
|
|
}),
|
|
)
|
|
.refine(
|
|
(schema) => {
|
|
const emails = schema.map((signer) => signer.email.toLowerCase());
|
|
const ids = schema.map((signer) => signer.id);
|
|
|
|
return new Set(emails).size === emails.length && new Set(ids).size === ids.length;
|
|
},
|
|
{ message: 'Recipient IDs and emails must be unique' },
|
|
),
|
|
meta: z
|
|
.object({
|
|
subject: z.string(),
|
|
message: z.string(),
|
|
timezone: z.string(),
|
|
dateFormat: z.string(),
|
|
redirectUrl: ZUrlSchema,
|
|
})
|
|
.partial()
|
|
.optional(),
|
|
formValues: z.record(z.string(), z.union([z.string(), z.boolean(), z.number()])).optional(),
|
|
});
|
|
|
|
export type TGenerateDocumentFromTemplateMutationSchema = z.infer<
|
|
typeof ZGenerateDocumentFromTemplateMutationSchema
|
|
>;
|
|
|
|
export const ZGenerateDocumentFromTemplateMutationResponseSchema = z.object({
|
|
documentId: z.number(),
|
|
recipients: z.array(
|
|
z.object({
|
|
recipientId: z.number(),
|
|
name: z.string(),
|
|
email: z.string().email().min(1),
|
|
token: z.string(),
|
|
role: z.nativeEnum(RecipientRole),
|
|
}),
|
|
),
|
|
});
|
|
|
|
export type TGenerateDocumentFromTemplateMutationResponseSchema = z.infer<
|
|
typeof ZGenerateDocumentFromTemplateMutationResponseSchema
|
|
>;
|
|
|
|
export const ZCreateRecipientMutationSchema = z.object({
|
|
name: z.string().min(1),
|
|
email: z.string().email().min(1),
|
|
role: z.nativeEnum(RecipientRole).optional().default(RecipientRole.SIGNER),
|
|
});
|
|
|
|
/**
|
|
* Recipients
|
|
*/
|
|
export type TCreateRecipientMutationSchema = z.infer<typeof ZCreateRecipientMutationSchema>;
|
|
|
|
export const ZUpdateRecipientMutationSchema = ZCreateRecipientMutationSchema.partial();
|
|
|
|
export type TUpdateRecipientMutationSchema = z.infer<typeof ZUpdateRecipientMutationSchema>;
|
|
|
|
export const ZDeleteRecipientMutationSchema = null;
|
|
|
|
export type TDeleteRecipientMutationSchema = typeof ZDeleteRecipientMutationSchema;
|
|
|
|
export const ZSuccessfulRecipientResponseSchema = z.object({
|
|
id: z.number(),
|
|
// !: This handles the fact that we have null documentId's for templates
|
|
// !: while we won't need the default we must add it to satisfy typescript
|
|
documentId: z.number().nullish().default(-1),
|
|
email: z.string().email().min(1),
|
|
name: z.string(),
|
|
role: z.nativeEnum(RecipientRole),
|
|
token: z.string(),
|
|
// !: Not used for now
|
|
// expired: z.string(),
|
|
signedAt: z.date().nullable(),
|
|
readStatus: z.nativeEnum(ReadStatus),
|
|
signingStatus: z.nativeEnum(SigningStatus),
|
|
sendStatus: z.nativeEnum(SendStatus),
|
|
});
|
|
|
|
export type TSuccessfulRecipientResponseSchema = z.infer<typeof ZSuccessfulRecipientResponseSchema>;
|
|
|
|
/**
|
|
* Fields
|
|
*/
|
|
export const ZCreateFieldMutationSchema = z.object({
|
|
recipientId: z.number(),
|
|
type: z.nativeEnum(FieldType),
|
|
pageNumber: z.number(),
|
|
pageX: z.number(),
|
|
pageY: z.number(),
|
|
pageWidth: z.number(),
|
|
pageHeight: z.number(),
|
|
});
|
|
|
|
export type TCreateFieldMutationSchema = z.infer<typeof ZCreateFieldMutationSchema>;
|
|
|
|
export const ZUpdateFieldMutationSchema = ZCreateFieldMutationSchema.partial();
|
|
|
|
export type TUpdateFieldMutationSchema = z.infer<typeof ZUpdateFieldMutationSchema>;
|
|
|
|
export const ZDeleteFieldMutationSchema = null;
|
|
|
|
export type TDeleteFieldMutationSchema = typeof ZDeleteFieldMutationSchema;
|
|
|
|
export const ZSuccessfulFieldResponseSchema = z.object({
|
|
id: z.number(),
|
|
documentId: z.number(),
|
|
recipientId: z.number(),
|
|
type: z.nativeEnum(FieldType),
|
|
pageNumber: z.number(),
|
|
pageX: z.number(),
|
|
pageY: z.number(),
|
|
pageWidth: z.number(),
|
|
pageHeight: z.number(),
|
|
customText: z.string(),
|
|
inserted: z.boolean(),
|
|
});
|
|
|
|
export type TSuccessfulFieldResponseSchema = z.infer<typeof ZSuccessfulFieldResponseSchema>;
|
|
|
|
export const ZSuccessfulResponseSchema = z.object({
|
|
documents: ZSuccessfulDocumentResponseSchema.array(),
|
|
totalPages: z.number(),
|
|
});
|
|
|
|
export type TSuccessfulResponseSchema = z.infer<typeof ZSuccessfulResponseSchema>;
|
|
|
|
export const ZSuccessfulSigningResponseSchema = z.object({
|
|
message: z.string(),
|
|
});
|
|
|
|
export type TSuccessfulSigningResponseSchema = z.infer<typeof ZSuccessfulSigningResponseSchema>;
|
|
|
|
/**
|
|
* General
|
|
*/
|
|
export const ZAuthorizationHeadersSchema = z.object({
|
|
authorization: z.string(),
|
|
});
|
|
|
|
export type TAuthorizationHeadersSchema = z.infer<typeof ZAuthorizationHeadersSchema>;
|
|
|
|
export const ZUnsuccessfulResponseSchema = z.object({
|
|
message: z.string(),
|
|
});
|
|
|
|
export type TUnsuccessfulResponseSchema = z.infer<typeof ZUnsuccessfulResponseSchema>;
|