diff --git a/packages/api/v1/implementation.ts b/packages/api/v1/implementation.ts index 95fc86880..7465433e1 100644 --- a/packages/api/v1/implementation.ts +++ b/packages/api/v1/implementation.ts @@ -23,7 +23,7 @@ import { getFieldsForDocument } from '@documenso/lib/server-only/field/get-field import { updateField } from '@documenso/lib/server-only/field/update-field'; import { insertFormValuesInPdf } from '@documenso/lib/server-only/pdf/insert-form-values-in-pdf'; import { deleteRecipient } from '@documenso/lib/server-only/recipient/delete-recipient'; -import { getRecipientById } from '@documenso/lib/server-only/recipient/get-recipient-by-id'; +import { getRecipientByIdV1Api } from '@documenso/lib/server-only/recipient/get-recipient-by-id-v1-api'; import { getRecipientsForDocument } from '@documenso/lib/server-only/recipient/get-recipients-for-document'; import { setRecipientsForDocument } from '@documenso/lib/server-only/recipient/set-recipients-for-document'; import { updateRecipient } from '@documenso/lib/server-only/recipient/update-recipient'; @@ -999,7 +999,7 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, { throw new Error('Invalid page number'); } - const recipient = await getRecipientById({ + const recipient = await getRecipientByIdV1Api({ id: Number(recipientId), documentId: Number(documentId), }).catch(() => null); @@ -1144,7 +1144,7 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, { }; } - const recipient = await getRecipientById({ + const recipient = await getRecipientByIdV1Api({ id: Number(recipientId), documentId: Number(documentId), }).catch(() => null); @@ -1248,7 +1248,7 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, { }; } - const recipient = await getRecipientById({ + const recipient = await getRecipientByIdV1Api({ id: Number(field.recipientId), documentId: Number(documentId), }).catch(() => null); diff --git a/packages/lib/server-only/recipient/get-recipient-by-id-v1-api.ts b/packages/lib/server-only/recipient/get-recipient-by-id-v1-api.ts new file mode 100644 index 000000000..6f5cef204 --- /dev/null +++ b/packages/lib/server-only/recipient/get-recipient-by-id-v1-api.ts @@ -0,0 +1,21 @@ +import { prisma } from '@documenso/prisma'; + +export type GetRecipientByIdOptions = { + id: number; + documentId: number; +}; + +export const getRecipientByIdV1Api = async ({ documentId, id }: GetRecipientByIdOptions) => { + const recipient = await prisma.recipient.findFirst({ + where: { + documentId, + id, + }, + }); + + if (!recipient) { + throw new Error('Recipient not found'); + } + + return recipient; +}; diff --git a/packages/lib/server-only/recipient/get-recipient-by-id.ts b/packages/lib/server-only/recipient/get-recipient-by-id.ts index 0db306b80..52b98019f 100644 --- a/packages/lib/server-only/recipient/get-recipient-by-id.ts +++ b/packages/lib/server-only/recipient/get-recipient-by-id.ts @@ -1,20 +1,63 @@ +import type { z } from 'zod'; + import { prisma } from '@documenso/prisma'; +import { FieldSchema, RecipientSchema } from '@documenso/prisma/generated/zod'; + +import { AppError, AppErrorCode } from '../../errors/app-error'; export type GetRecipientByIdOptions = { - id: number; - documentId: number; + recipientId: number; + userId: number; + teamId?: number; }; -export const getRecipientById = async ({ documentId, id }: GetRecipientByIdOptions) => { +export const ZGetRecipientByIdResponseSchema = RecipientSchema.extend({ + Field: FieldSchema.array(), +}); + +export type TGetRecipientByIdResponse = z.infer; + +/** + * Get a recipient by ID. This will also return the recipient signing token so + * be careful when using this. + */ +export const getRecipientById = async ({ + recipientId, + userId, + teamId, +}: GetRecipientByIdOptions): Promise => { const recipient = await prisma.recipient.findFirst({ where: { - documentId, - id, + id: recipientId, + Document: { + OR: [ + teamId === undefined + ? { + userId, + teamId: null, + } + : { + teamId, + team: { + members: { + some: { + userId, + }, + }, + }, + }, + ], + }, + }, + include: { + Field: true, }, }); if (!recipient) { - throw new Error('Recipient not found'); + throw new AppError(AppErrorCode.NOT_FOUND, { + message: 'Recipient not found', + }); } return recipient; diff --git a/packages/trpc/server/field-router/router.ts b/packages/trpc/server/field-router/router.ts index d1b31e9a8..b42bb3a6b 100644 --- a/packages/trpc/server/field-router/router.ts +++ b/packages/trpc/server/field-router/router.ts @@ -33,7 +33,8 @@ export const fieldRouter = router({ method: 'GET', path: '/field/{fieldId}', summary: 'Get field', - description: 'Returns a document or template field', + description: + 'Returns a single field. If you want to retrieve all the fields for a document or template, use the "Get Document" or "Get Template" request.', tags: ['Fields'], }, }) @@ -119,7 +120,7 @@ export const fieldRouter = router({ }), /** - * @internal + * @private */ signFieldWithToken: procedure .input(ZSignFieldWithTokenMutationSchema) @@ -138,7 +139,7 @@ export const fieldRouter = router({ }), /** - * @internal + * @private */ removeSignedFieldWithToken: procedure .input(ZRemovedSignedFieldWithTokenMutationSchema) diff --git a/packages/trpc/server/recipient-router/router.ts b/packages/trpc/server/recipient-router/router.ts index f440f54ea..3fa0d63c3 100644 --- a/packages/trpc/server/recipient-router/router.ts +++ b/packages/trpc/server/recipient-router/router.ts @@ -1,5 +1,9 @@ import { completeDocumentWithToken } from '@documenso/lib/server-only/document/complete-document-with-token'; import { rejectDocumentWithToken } from '@documenso/lib/server-only/document/reject-document-with-token'; +import { + ZGetRecipientByIdResponseSchema, + getRecipientById, +} from '@documenso/lib/server-only/recipient/get-recipient-by-id'; import { ZSetRecipientsForDocumentResponseSchema, setRecipientsForDocument, @@ -15,12 +19,39 @@ import { ZAddSignersMutationSchema, ZAddTemplateSignersMutationSchema, ZCompleteDocumentWithTokenMutationSchema, + ZGetRecipientQuerySchema, ZRejectDocumentWithTokenMutationSchema, } from './schema'; export const recipientRouter = router({ /** - * @internal + * @public + */ + getRecipient: authenticatedProcedure + .meta({ + openapi: { + method: 'GET', + path: '/recipient/{recipientId}', + summary: 'Get recipient', + description: + 'Returns a single recipient. If you want to retrieve all the recipients for a document or template, use the "Get Document" or "Get Template" request.', + tags: ['Recipients'], + }, + }) + .input(ZGetRecipientQuerySchema) + .output(ZGetRecipientByIdResponseSchema) + .query(async ({ input, ctx }) => { + const { recipientId, teamId } = input; + + return await getRecipientById({ + userId: ctx.user.id, + teamId, + recipientId, + }); + }), + + /** + * @public */ addSigners: authenticatedProcedure .meta({ @@ -53,7 +84,7 @@ export const recipientRouter = router({ }), /** - * @internal + * @public */ addTemplateSigners: authenticatedProcedure .meta({ @@ -85,7 +116,7 @@ export const recipientRouter = router({ }), /** - * @internal + * @private */ completeDocumentWithToken: procedure .input(ZCompleteDocumentWithTokenMutationSchema) @@ -102,7 +133,7 @@ export const recipientRouter = router({ }), /** - * @internal + * @private */ rejectDocumentWithToken: procedure .input(ZRejectDocumentWithTokenMutationSchema) diff --git a/packages/trpc/server/recipient-router/schema.ts b/packages/trpc/server/recipient-router/schema.ts index 60e47a439..9dea0b42c 100644 --- a/packages/trpc/server/recipient-router/schema.ts +++ b/packages/trpc/server/recipient-router/schema.ts @@ -6,6 +6,11 @@ import { } from '@documenso/lib/types/document-auth'; import { RecipientRole } from '@documenso/prisma/client'; +export const ZGetRecipientQuerySchema = z.object({ + recipientId: z.number(), + teamId: z.number().optional(), +}); + export const ZAddSignersMutationSchema = z .object({ documentId: z.number(), diff --git a/packages/trpc/server/template-router/router.ts b/packages/trpc/server/template-router/router.ts index df5c2ab93..0a438b300 100644 --- a/packages/trpc/server/template-router/router.ts +++ b/packages/trpc/server/template-router/router.ts @@ -445,7 +445,7 @@ export const templateRouter = router({ }), /** - * @internal + * @private */ updateTemplateTypedSignatureSettings: authenticatedProcedure .input(ZUpdateTemplateTypedSignatureSettingsMutationSchema)