From 67501b45cf58c7ce9046cb049881d349a86b9807 Mon Sep 17 00:00:00 2001 From: Catalin Pit Date: Fri, 22 Aug 2025 17:12:17 +0300 Subject: [PATCH] feat: create document in a specific folder (#1965) --- packages/api/v1/implementation.ts | 2 ++ packages/api/v1/schema.ts | 12 +++++++++++ .../document/create-document-v2.ts | 21 ++++++++++++++++++- .../template/create-document-from-template.ts | 20 ++++++++++++++++++ .../trpc/server/document-router/router.ts | 2 ++ .../trpc/server/document-router/schema.ts | 6 ++++++ .../trpc/server/template-router/router.ts | 11 ++++++++-- .../trpc/server/template-router/schema.ts | 6 ++++++ 8 files changed, 77 insertions(+), 3 deletions(-) diff --git a/packages/api/v1/implementation.ts b/packages/api/v1/implementation.ts index e8afd9af4..e9fcbf4d8 100644 --- a/packages/api/v1/implementation.ts +++ b/packages/api/v1/implementation.ts @@ -330,6 +330,7 @@ export const ApiContractV1Implementation = tsr.router(ApiContractV1, { userId: user.id, teamId: team?.id, formValues: body.formValues, + folderId: body.folderId, documentDataId: documentData.id, requestMetadata: metadata, }); @@ -736,6 +737,7 @@ export const ApiContractV1Implementation = tsr.router(ApiContractV1, { teamId: team?.id, recipients: body.recipients, prefillFields: body.prefillFields, + folderId: body.folderId, override: { title: body.title, ...body.meta, diff --git a/packages/api/v1/schema.ts b/packages/api/v1/schema.ts index 81f1b7a79..c33120ae3 100644 --- a/packages/api/v1/schema.ts +++ b/packages/api/v1/schema.ts @@ -136,6 +136,12 @@ export type TUploadDocumentSuccessfulSchema = z.infer>; requestMetadata: ApiRequestMetadata; @@ -59,7 +61,7 @@ export const createDocumentV2 = async ({ meta, requestMetadata, }: CreateDocumentOptions) => { - const { title, formValues } = data; + const { title, formValues, folderId } = data; const team = await prisma.team.findFirst({ where: buildTeamWhereQuery({ teamId, userId }), @@ -78,6 +80,22 @@ export const createDocumentV2 = async ({ }); } + if (folderId) { + const folder = await prisma.folder.findUnique({ + where: { + id: folderId, + type: FolderType.DOCUMENT, + team: buildTeamWhereQuery({ teamId, userId }), + }, + }); + + if (!folder) { + throw new AppError(AppErrorCode.NOT_FOUND, { + message: 'Folder not found', + }); + } + } + const settings = await getTeamSettings({ userId, teamId, @@ -164,6 +182,7 @@ export const createDocumentV2 = async ({ teamId, authOptions, visibility, + folderId, formValues, source: DocumentSource.DOCUMENT, documentMeta: { diff --git a/packages/lib/server-only/template/create-document-from-template.ts b/packages/lib/server-only/template/create-document-from-template.ts index 35946a155..b6ee8b222 100644 --- a/packages/lib/server-only/template/create-document-from-template.ts +++ b/packages/lib/server-only/template/create-document-from-template.ts @@ -2,6 +2,7 @@ import type { DocumentDistributionMethod, DocumentSigningOrder } from '@prisma/c import { DocumentSource, type Field, + FolderType, type Recipient, RecipientRole, SendStatus, @@ -69,6 +70,7 @@ export type CreateDocumentFromTemplateOptions = { email: string; signingOrder?: number | null; }[]; + folderId?: string; prefillFields?: TFieldMetaPrefillFieldsSchema[]; customDocumentDataId?: string; @@ -274,6 +276,7 @@ export const createDocumentFromTemplate = async ({ customDocumentDataId, override, requestMetadata, + folderId, prefillFields, }: CreateDocumentFromTemplateOptions) => { const template = await prisma.template.findUnique({ @@ -298,6 +301,22 @@ export const createDocumentFromTemplate = async ({ }); } + if (folderId) { + const folder = await prisma.folder.findUnique({ + where: { + id: folderId, + type: FolderType.DOCUMENT, + team: buildTeamWhereQuery({ teamId, userId }), + }, + }); + + if (!folder) { + throw new AppError(AppErrorCode.NOT_FOUND, { + message: 'Folder not found', + }); + } + } + const settings = await getTeamSettings({ userId, teamId, @@ -368,6 +387,7 @@ export const createDocumentFromTemplate = async ({ externalId: externalId || template.externalId, templateId: template.id, userId, + folderId, teamId: template.teamId, title: override?.title || template.title, documentDataId: documentData.id, diff --git a/packages/trpc/server/document-router/router.ts b/packages/trpc/server/document-router/router.ts index e6da221ac..8d3cc8020 100644 --- a/packages/trpc/server/document-router/router.ts +++ b/packages/trpc/server/document-router/router.ts @@ -284,6 +284,7 @@ export const documentRouter = router({ globalActionAuth, recipients, meta, + folderId, } = input; const { remaining } = await getServerLimits({ userId: user.id, teamId }); @@ -316,6 +317,7 @@ export const documentRouter = router({ globalAccessAuth, globalActionAuth, recipients, + folderId, }, meta, requestMetadata: ctx.metadata, diff --git a/packages/trpc/server/document-router/schema.ts b/packages/trpc/server/document-router/schema.ts index 36eca0e26..22425a2f4 100644 --- a/packages/trpc/server/document-router/schema.ts +++ b/packages/trpc/server/document-router/schema.ts @@ -209,6 +209,12 @@ export const ZCreateDocumentV2RequestSchema = z.object({ globalAccessAuth: z.array(ZDocumentAccessAuthTypesSchema).optional(), globalActionAuth: z.array(ZDocumentActionAuthTypesSchema).optional(), formValues: ZDocumentFormValuesSchema.optional(), + folderId: z + .string() + .describe( + 'The ID of the folder to create the document in. If not provided, the document will be created in the root folder.', + ) + .optional(), recipients: z .array( ZCreateRecipientSchema.extend({ diff --git a/packages/trpc/server/template-router/router.ts b/packages/trpc/server/template-router/router.ts index c52f78223..a9041ad3e 100644 --- a/packages/trpc/server/template-router/router.ts +++ b/packages/trpc/server/template-router/router.ts @@ -339,8 +339,14 @@ export const templateRouter = router({ .output(ZCreateDocumentFromTemplateResponseSchema) .mutation(async ({ ctx, input }) => { const { teamId } = ctx; - const { templateId, recipients, distributeDocument, customDocumentDataId, prefillFields } = - input; + const { + templateId, + recipients, + distributeDocument, + customDocumentDataId, + prefillFields, + folderId, + } = input; ctx.logger.info({ input: { @@ -361,6 +367,7 @@ export const templateRouter = router({ recipients, customDocumentDataId, requestMetadata: ctx.metadata, + folderId, prefillFields, }); diff --git a/packages/trpc/server/template-router/schema.ts b/packages/trpc/server/template-router/schema.ts index 31284ac58..c1100b99e 100644 --- a/packages/trpc/server/template-router/schema.ts +++ b/packages/trpc/server/template-router/schema.ts @@ -117,6 +117,12 @@ export const ZCreateDocumentFromTemplateRequestSchema = z.object({ 'The data ID of an alternative PDF to use when creating the document. If not provided, the PDF attached to the template will be used.', ) .optional(), + folderId: z + .string() + .describe( + 'The ID of the folder to create the document in. If not provided, the document will be created in the root folder.', + ) + .optional(), prefillFields: z .array(ZFieldMetaPrefillFieldsSchema) .describe(