mirror of
https://github.com/documenso/documenso.git
synced 2025-11-12 15:53:02 +10:00
feat: add field and recipient endpoints
This commit is contained in:
@ -4,14 +4,20 @@ import {
|
||||
ZSendDocumentForSigningMutationSchema as SendDocumentMutationSchema,
|
||||
ZAuthorizationHeadersSchema,
|
||||
ZCreateDocumentMutationSchema,
|
||||
ZCreateFieldMutationSchema,
|
||||
ZCreateRecipientMutationSchema,
|
||||
ZDeleteDocumentMutationSchema,
|
||||
ZDeleteFieldMutationSchema,
|
||||
ZDeleteRecipientMutationSchema,
|
||||
ZGetDocumentsQuerySchema,
|
||||
ZSuccessfulDocumentResponseSchema,
|
||||
ZSuccessfulFieldResponseSchema,
|
||||
ZSuccessfulRecipientResponseSchema,
|
||||
ZSuccessfulResponseSchema,
|
||||
ZSuccessfulSigningResponseSchema,
|
||||
ZUnsuccessfulResponseSchema,
|
||||
ZUpdateFieldMutationSchema,
|
||||
ZUpdateRecipientMutationSchema,
|
||||
ZUploadDocumentSuccessfulSchema,
|
||||
} from './schema';
|
||||
|
||||
@ -93,6 +99,76 @@ export const ApiContractV1 = c.router(
|
||||
},
|
||||
summary: 'Create a recipient for a document',
|
||||
},
|
||||
|
||||
updateRecipient: {
|
||||
method: 'PATCH',
|
||||
path: '/api/v1/documents/:id/recipients/:recipientId',
|
||||
body: ZUpdateRecipientMutationSchema,
|
||||
responses: {
|
||||
200: ZSuccessfulRecipientResponseSchema,
|
||||
400: ZUnsuccessfulResponseSchema,
|
||||
401: ZUnsuccessfulResponseSchema,
|
||||
404: ZUnsuccessfulResponseSchema,
|
||||
500: ZUnsuccessfulResponseSchema,
|
||||
},
|
||||
summary: 'Update a recipient for a document',
|
||||
},
|
||||
|
||||
deleteRecipient: {
|
||||
method: 'DELETE',
|
||||
path: '/api/v1/documents/:id/recipients/:recipientId',
|
||||
body: ZDeleteRecipientMutationSchema,
|
||||
responses: {
|
||||
200: ZSuccessfulRecipientResponseSchema,
|
||||
400: ZUnsuccessfulResponseSchema,
|
||||
401: ZUnsuccessfulResponseSchema,
|
||||
404: ZUnsuccessfulResponseSchema,
|
||||
500: ZUnsuccessfulResponseSchema,
|
||||
},
|
||||
summary: 'Delete a recipient from a document',
|
||||
},
|
||||
|
||||
createField: {
|
||||
method: 'POST',
|
||||
path: '/api/v1/documents/:id/fields',
|
||||
body: ZCreateFieldMutationSchema,
|
||||
responses: {
|
||||
200: ZSuccessfulFieldResponseSchema,
|
||||
400: ZUnsuccessfulResponseSchema,
|
||||
401: ZUnsuccessfulResponseSchema,
|
||||
404: ZUnsuccessfulResponseSchema,
|
||||
500: ZUnsuccessfulResponseSchema,
|
||||
},
|
||||
summary: 'Create a field for a document',
|
||||
},
|
||||
|
||||
updateField: {
|
||||
method: 'PATCH',
|
||||
path: '/api/v1/documents/:id/fields/:fieldId',
|
||||
body: ZUpdateFieldMutationSchema,
|
||||
responses: {
|
||||
200: ZSuccessfulFieldResponseSchema,
|
||||
400: ZUnsuccessfulResponseSchema,
|
||||
401: ZUnsuccessfulResponseSchema,
|
||||
404: ZUnsuccessfulResponseSchema,
|
||||
500: ZUnsuccessfulResponseSchema,
|
||||
},
|
||||
summary: 'Update a field for a document',
|
||||
},
|
||||
|
||||
deleteField: {
|
||||
method: 'DELETE',
|
||||
path: '/api/v1/documents/:id/fields/:fieldId',
|
||||
body: ZDeleteFieldMutationSchema,
|
||||
responses: {
|
||||
200: ZSuccessfulFieldResponseSchema,
|
||||
400: ZUnsuccessfulResponseSchema,
|
||||
401: ZUnsuccessfulResponseSchema,
|
||||
404: ZUnsuccessfulResponseSchema,
|
||||
500: ZUnsuccessfulResponseSchema,
|
||||
},
|
||||
summary: 'Delete a field from a document',
|
||||
},
|
||||
},
|
||||
{
|
||||
baseHeaders: ZAuthorizationHeadersSchema,
|
||||
|
||||
@ -4,10 +4,17 @@ import { deleteDocument } from '@documenso/lib/server-only/document/delete-docum
|
||||
import { findDocuments } from '@documenso/lib/server-only/document/find-documents';
|
||||
import { getDocumentById } from '@documenso/lib/server-only/document/get-document-by-id';
|
||||
import { sendDocument } from '@documenso/lib/server-only/document/send-document';
|
||||
import { createField } from '@documenso/lib/server-only/field/create-field';
|
||||
import { deleteField } from '@documenso/lib/server-only/field/delete-field';
|
||||
import { getFieldById } from '@documenso/lib/server-only/field/get-field-by-id';
|
||||
import { updateField } from '@documenso/lib/server-only/field/update-field';
|
||||
import { deleteRecipient } from '@documenso/lib/server-only/recipient/delete-recipient';
|
||||
import { getRecipientById } from '@documenso/lib/server-only/recipient/get-recipient-by-id';
|
||||
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';
|
||||
import { getPresignPostUrl } from '@documenso/lib/universal/upload/server-actions';
|
||||
import { DocumentStatus } from '@documenso/prisma/client';
|
||||
import { DocumentStatus, SigningStatus } from '@documenso/prisma/client';
|
||||
|
||||
import { ApiContractV1 } from './contract';
|
||||
import { authenticatedMiddleware } from './middleware/authenticated';
|
||||
@ -250,4 +257,347 @@ export const ApiContractV1Implementation = createNextRoute(ApiContractV1, {
|
||||
};
|
||||
}
|
||||
}),
|
||||
|
||||
updateRecipient: authenticatedMiddleware(async (args, user) => {
|
||||
const { id: documentId, recipientId } = args.params;
|
||||
const { name, email } = args.body;
|
||||
|
||||
const document = await getDocumentById({
|
||||
id: Number(documentId),
|
||||
userId: user.id,
|
||||
});
|
||||
|
||||
if (!document) {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
message: 'Document not found',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (document.status === DocumentStatus.COMPLETED) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
message: 'Document is already completed',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const updatedRecipient = await updateRecipient({
|
||||
documentId: Number(documentId),
|
||||
recipientId: Number(recipientId),
|
||||
email,
|
||||
name,
|
||||
}).catch(() => null);
|
||||
|
||||
if (!updatedRecipient) {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
message: 'Recipient not found',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
body: updatedRecipient,
|
||||
};
|
||||
}),
|
||||
|
||||
deleteRecipient: authenticatedMiddleware(async (args, user) => {
|
||||
const { id: documentId, recipientId } = args.params;
|
||||
|
||||
const document = await getDocumentById({
|
||||
id: Number(documentId),
|
||||
userId: user.id,
|
||||
});
|
||||
|
||||
if (!document) {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
message: 'Document not found',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (document.status === DocumentStatus.COMPLETED) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
message: 'Document is already completed',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const deletedRecipient = await deleteRecipient({
|
||||
documentId: Number(documentId),
|
||||
recipientId: Number(recipientId),
|
||||
}).catch(() => null);
|
||||
|
||||
if (!deletedRecipient) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
message: 'Unable to delete recipient',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
body: deletedRecipient,
|
||||
};
|
||||
}),
|
||||
|
||||
createField: authenticatedMiddleware(async (args, user) => {
|
||||
const { id: documentId } = args.params;
|
||||
const { recipientId, type, pageNumber, pageWidth, pageHeight, pageX, pageY } = args.body;
|
||||
|
||||
const document = await getDocumentById({
|
||||
id: Number(documentId),
|
||||
userId: user.id,
|
||||
});
|
||||
|
||||
if (!document) {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
message: 'Document not found',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (document.status === DocumentStatus.COMPLETED) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
message: 'Document is already completed',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const recipient = await getRecipientById({
|
||||
id: Number(recipientId),
|
||||
documentId: Number(documentId),
|
||||
}).catch(() => null);
|
||||
|
||||
if (!recipient) {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
message: 'Recipient not found',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (recipient.signingStatus === SigningStatus.SIGNED) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
message: 'Recipient has already signed the document',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const field = await createField({
|
||||
documentId: Number(documentId),
|
||||
recipientId: Number(recipientId),
|
||||
type,
|
||||
pageNumber,
|
||||
pageX,
|
||||
pageY,
|
||||
pageWidth,
|
||||
pageHeight,
|
||||
});
|
||||
|
||||
const remappedField = {
|
||||
documentId: field.documentId,
|
||||
recipientId: field.recipientId ?? -1,
|
||||
type: field.type,
|
||||
pageNumber: field.page,
|
||||
pageX: Number(field.positionX),
|
||||
pageY: Number(field.positionY),
|
||||
pageWidth: Number(field.width),
|
||||
pageHeight: Number(field.height),
|
||||
customText: field.customText,
|
||||
inserted: field.inserted,
|
||||
};
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
body: remappedField,
|
||||
};
|
||||
}),
|
||||
|
||||
updateField: authenticatedMiddleware(async (args, user) => {
|
||||
const { id: documentId, fieldId } = args.params;
|
||||
const { recipientId, type, pageNumber, pageWidth, pageHeight, pageX, pageY } = args.body;
|
||||
|
||||
const document = await getDocumentById({
|
||||
id: Number(documentId),
|
||||
userId: user.id,
|
||||
});
|
||||
|
||||
if (!document) {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
message: 'Document not found',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (document.status === DocumentStatus.COMPLETED) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
message: 'Document is already completed',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const recipient = await getRecipientById({
|
||||
id: Number(recipientId),
|
||||
documentId: Number(documentId),
|
||||
}).catch(() => null);
|
||||
|
||||
if (!recipient) {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
message: 'Recipient not found',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (recipient.signingStatus === SigningStatus.SIGNED) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
message: 'Recipient has already signed the document',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const updatedField = await updateField({
|
||||
fieldId: Number(fieldId),
|
||||
documentId: Number(documentId),
|
||||
recipientId: recipientId ? Number(recipientId) : undefined,
|
||||
type,
|
||||
pageNumber,
|
||||
pageX,
|
||||
pageY,
|
||||
pageWidth,
|
||||
pageHeight,
|
||||
});
|
||||
|
||||
const remappedField = {
|
||||
documentId: updatedField.documentId,
|
||||
recipientId: updatedField.recipientId ?? -1,
|
||||
type: updatedField.type,
|
||||
pageNumber: updatedField.page,
|
||||
pageX: Number(updatedField.positionX),
|
||||
pageY: Number(updatedField.positionY),
|
||||
pageWidth: Number(updatedField.width),
|
||||
pageHeight: Number(updatedField.height),
|
||||
customText: updatedField.customText,
|
||||
inserted: updatedField.inserted,
|
||||
};
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
body: remappedField,
|
||||
};
|
||||
}),
|
||||
|
||||
deleteField: authenticatedMiddleware(async (args, user) => {
|
||||
const { id: documentId, fieldId } = args.params;
|
||||
|
||||
const document = await getDocumentById({
|
||||
id: Number(documentId),
|
||||
userId: user.id,
|
||||
});
|
||||
|
||||
if (!document) {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
message: 'Document not found',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (document.status === DocumentStatus.COMPLETED) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
message: 'Document is already completed',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const field = await getFieldById({
|
||||
fieldId: Number(fieldId),
|
||||
documentId: Number(documentId),
|
||||
}).catch(() => null);
|
||||
|
||||
if (!field) {
|
||||
return {
|
||||
status: 404,
|
||||
body: {
|
||||
message: 'Field not found',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const recipient = await getRecipientById({
|
||||
id: Number(field.recipientId),
|
||||
documentId: Number(documentId),
|
||||
}).catch(() => null);
|
||||
|
||||
if (recipient?.signingStatus === SigningStatus.SIGNED) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
message: 'Recipient has already signed the document',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const deletedField = await deleteField({
|
||||
documentId: Number(documentId),
|
||||
fieldId: Number(fieldId),
|
||||
}).catch(() => null);
|
||||
|
||||
if (!deletedField) {
|
||||
return {
|
||||
status: 400,
|
||||
body: {
|
||||
message: 'Unable to delete field',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const remappedField = {
|
||||
documentId: deletedField.documentId,
|
||||
recipientId: deletedField.recipientId ?? -1,
|
||||
type: deletedField.type,
|
||||
pageNumber: deletedField.page,
|
||||
pageX: Number(deletedField.positionX),
|
||||
pageY: Number(deletedField.positionY),
|
||||
pageWidth: Number(deletedField.width),
|
||||
pageHeight: Number(deletedField.height),
|
||||
customText: deletedField.customText,
|
||||
inserted: deletedField.inserted,
|
||||
};
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
body: remappedField,
|
||||
};
|
||||
}),
|
||||
});
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
import { ReadStatus, SendStatus, SigningStatus } from '@documenso/prisma/client';
|
||||
import { FieldType, ReadStatus, SendStatus, SigningStatus } from '@documenso/prisma/client';
|
||||
|
||||
/**
|
||||
* Documents
|
||||
*/
|
||||
export const ZGetDocumentsQuerySchema = z.object({
|
||||
page: z.string().optional(),
|
||||
perPage: z.string().optional(),
|
||||
@ -49,8 +52,19 @@ export const ZCreateRecipientMutationSchema = z.object({
|
||||
email: z.string().email().min(1),
|
||||
});
|
||||
|
||||
/**
|
||||
* 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(),
|
||||
documentId: z.number(),
|
||||
@ -67,6 +81,44 @@ export const ZSuccessfulRecipientResponseSchema = z.object({
|
||||
|
||||
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({
|
||||
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(),
|
||||
@ -80,14 +132,17 @@ export const ZSuccessfulSigningResponseSchema = z.object({
|
||||
|
||||
export type TSuccessfulSigningResponseSchema = z.infer<typeof ZSuccessfulSigningResponseSchema>;
|
||||
|
||||
export const ZUnsuccessfulResponseSchema = z.object({
|
||||
message: z.string(),
|
||||
});
|
||||
|
||||
export type TUnsuccessfulResponseSchema = z.infer<typeof ZUnsuccessfulResponseSchema>;
|
||||
|
||||
/**
|
||||
* 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>;
|
||||
|
||||
41
packages/lib/server-only/field/create-field.ts
Normal file
41
packages/lib/server-only/field/create-field.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import type { FieldType } from '@documenso/prisma/client';
|
||||
|
||||
export type CreateFieldOptions = {
|
||||
documentId: number;
|
||||
recipientId: number;
|
||||
type: FieldType;
|
||||
pageNumber: number;
|
||||
pageX: number;
|
||||
pageY: number;
|
||||
pageWidth: number;
|
||||
pageHeight: number;
|
||||
};
|
||||
|
||||
export const createField = async ({
|
||||
documentId,
|
||||
recipientId,
|
||||
type,
|
||||
pageNumber,
|
||||
pageX,
|
||||
pageY,
|
||||
pageWidth,
|
||||
pageHeight,
|
||||
}: CreateFieldOptions) => {
|
||||
const field = await prisma.field.create({
|
||||
data: {
|
||||
documentId,
|
||||
recipientId,
|
||||
type,
|
||||
page: pageNumber,
|
||||
positionX: pageX,
|
||||
positionY: pageY,
|
||||
width: pageWidth,
|
||||
height: pageHeight,
|
||||
customText: '',
|
||||
inserted: false,
|
||||
},
|
||||
});
|
||||
|
||||
return field;
|
||||
};
|
||||
17
packages/lib/server-only/field/delete-field.ts
Normal file
17
packages/lib/server-only/field/delete-field.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
export type DeleteFieldOptions = {
|
||||
fieldId: number;
|
||||
documentId: number;
|
||||
};
|
||||
|
||||
export const deleteField = async ({ fieldId, documentId }: DeleteFieldOptions) => {
|
||||
const field = await prisma.field.delete({
|
||||
where: {
|
||||
id: fieldId,
|
||||
documentId,
|
||||
},
|
||||
});
|
||||
|
||||
return field;
|
||||
};
|
||||
17
packages/lib/server-only/field/get-field-by-id.ts
Normal file
17
packages/lib/server-only/field/get-field-by-id.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
export type GetFieldByIdOptions = {
|
||||
fieldId: number;
|
||||
documentId: number;
|
||||
};
|
||||
|
||||
export const getFieldById = async ({ fieldId, documentId }: GetFieldByIdOptions) => {
|
||||
const field = await prisma.field.findFirst({
|
||||
where: {
|
||||
id: fieldId,
|
||||
documentId,
|
||||
},
|
||||
});
|
||||
|
||||
return field;
|
||||
};
|
||||
44
packages/lib/server-only/field/update-field.ts
Normal file
44
packages/lib/server-only/field/update-field.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import type { FieldType } from '@documenso/prisma/client';
|
||||
|
||||
export type UpdateFieldOptions = {
|
||||
fieldId: number;
|
||||
documentId: number;
|
||||
recipientId?: number;
|
||||
type?: FieldType;
|
||||
pageNumber?: number;
|
||||
pageX?: number;
|
||||
pageY?: number;
|
||||
pageWidth?: number;
|
||||
pageHeight?: number;
|
||||
};
|
||||
|
||||
export const updateField = async ({
|
||||
fieldId,
|
||||
documentId,
|
||||
recipientId,
|
||||
type,
|
||||
pageNumber,
|
||||
pageX,
|
||||
pageY,
|
||||
pageWidth,
|
||||
pageHeight,
|
||||
}: UpdateFieldOptions) => {
|
||||
const field = await prisma.field.update({
|
||||
where: {
|
||||
id: fieldId,
|
||||
documentId,
|
||||
},
|
||||
data: {
|
||||
recipientId,
|
||||
type,
|
||||
page: pageNumber,
|
||||
positionX: pageX,
|
||||
positionY: pageY,
|
||||
width: pageWidth,
|
||||
height: pageHeight,
|
||||
},
|
||||
});
|
||||
|
||||
return field;
|
||||
};
|
||||
32
packages/lib/server-only/recipient/delete-recipient.ts
Normal file
32
packages/lib/server-only/recipient/delete-recipient.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { SendStatus } from '@documenso/prisma/client';
|
||||
|
||||
export type DeleteRecipientOptions = {
|
||||
documentId: number;
|
||||
recipientId: number;
|
||||
};
|
||||
|
||||
export const deleteRecipient = async ({ documentId, recipientId }: DeleteRecipientOptions) => {
|
||||
const recipient = await prisma.recipient.findFirst({
|
||||
where: {
|
||||
id: recipientId,
|
||||
documentId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!recipient) {
|
||||
throw new Error('Recipient not found');
|
||||
}
|
||||
|
||||
if (recipient.sendStatus !== SendStatus.NOT_SENT) {
|
||||
throw new Error('Can not delete a recipient that has already been sent a document');
|
||||
}
|
||||
|
||||
const deletedRecipient = await prisma.recipient.delete({
|
||||
where: {
|
||||
id: recipient.id,
|
||||
},
|
||||
});
|
||||
|
||||
return deletedRecipient;
|
||||
};
|
||||
21
packages/lib/server-only/recipient/get-recipient-by-email.ts
Normal file
21
packages/lib/server-only/recipient/get-recipient-by-email.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
export type GetRecipientByEmailOptions = {
|
||||
documentId: number;
|
||||
email: string;
|
||||
};
|
||||
|
||||
export const getRecipientByEmail = async ({ documentId, email }: GetRecipientByEmailOptions) => {
|
||||
const recipient = await prisma.recipient.findFirst({
|
||||
where: {
|
||||
documentId,
|
||||
email: email.toLowerCase(),
|
||||
},
|
||||
});
|
||||
|
||||
if (!recipient) {
|
||||
throw new Error('Recipient not found');
|
||||
}
|
||||
|
||||
return recipient;
|
||||
};
|
||||
21
packages/lib/server-only/recipient/get-recipient-by-id.ts
Normal file
21
packages/lib/server-only/recipient/get-recipient-by-id.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
export type GetRecipientByIdOptions = {
|
||||
id: number;
|
||||
documentId: number;
|
||||
};
|
||||
|
||||
export const getRecipientById = async ({ documentId, id }: GetRecipientByIdOptions) => {
|
||||
const recipient = await prisma.recipient.findFirst({
|
||||
where: {
|
||||
documentId,
|
||||
id,
|
||||
},
|
||||
});
|
||||
|
||||
if (!recipient) {
|
||||
throw new Error('Recipient not found');
|
||||
}
|
||||
|
||||
return recipient;
|
||||
};
|
||||
38
packages/lib/server-only/recipient/update-recipient.ts
Normal file
38
packages/lib/server-only/recipient/update-recipient.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
export type UpdateRecipientOptions = {
|
||||
documentId: number;
|
||||
recipientId: number;
|
||||
email?: string;
|
||||
name?: string;
|
||||
};
|
||||
|
||||
export const updateRecipient = async ({
|
||||
documentId,
|
||||
recipientId,
|
||||
email,
|
||||
name,
|
||||
}: UpdateRecipientOptions) => {
|
||||
const recipient = await prisma.recipient.findFirst({
|
||||
where: {
|
||||
id: recipientId,
|
||||
documentId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!recipient) {
|
||||
throw new Error('Recipient not found');
|
||||
}
|
||||
|
||||
const updatedRecipient = await prisma.recipient.update({
|
||||
where: {
|
||||
id: recipient.id,
|
||||
},
|
||||
data: {
|
||||
email: email?.toLowerCase() ?? recipient.email,
|
||||
name: name ?? recipient.name,
|
||||
},
|
||||
});
|
||||
|
||||
return updatedRecipient;
|
||||
};
|
||||
Reference in New Issue
Block a user