2023-11-22 15:44:49 +02:00
|
|
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
|
|
|
|
|
2023-12-08 13:28:34 +00:00
|
|
|
import { upsertDocumentMeta } from '@documenso/lib/server-only/document-meta/upsert-document-meta';
|
2023-12-06 15:27:30 +00:00
|
|
|
import { deleteDocument } from '@documenso/lib/server-only/document/delete-document';
|
2023-12-08 13:28:34 +00:00
|
|
|
import { findDocuments } from '@documenso/lib/server-only/document/find-documents';
|
2023-11-23 10:02:22 +02:00
|
|
|
import { getDocumentById } from '@documenso/lib/server-only/document/get-document-by-id';
|
2023-12-08 13:28:34 +00:00
|
|
|
import { sendDocument } from '@documenso/lib/server-only/document/send-document';
|
|
|
|
|
import { setFieldsForDocument } from '@documenso/lib/server-only/field/set-fields-for-document';
|
2023-11-30 14:39:31 +02:00
|
|
|
import { checkUserFromToken } from '@documenso/lib/server-only/public-api/get-user-by-token';
|
2023-12-08 13:28:34 +00:00
|
|
|
import { setRecipientsForDocument } from '@documenso/lib/server-only/recipient/set-recipients-for-document';
|
|
|
|
|
import { getPresignPostUrl } from '@documenso/lib/universal/upload/server-actions';
|
2023-11-22 15:44:49 +02:00
|
|
|
import { contract } from '@documenso/trpc/api-contract/contract';
|
|
|
|
|
import { createNextRoute, createNextRouter } from '@documenso/trpc/server/public-api/ts-rest';
|
|
|
|
|
|
2023-11-30 14:39:31 +02:00
|
|
|
const validateUserToken = async (token: string) => {
|
|
|
|
|
try {
|
|
|
|
|
return await checkUserFromToken({ token });
|
|
|
|
|
} catch (e) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2023-11-22 15:44:49 +02:00
|
|
|
const router = createNextRoute(contract, {
|
|
|
|
|
getDocuments: async (args) => {
|
|
|
|
|
const page = Number(args.query.page) || 1;
|
|
|
|
|
const perPage = Number(args.query.perPage) || 10;
|
2023-11-30 14:39:31 +02:00
|
|
|
const { authorization } = args.headers;
|
|
|
|
|
|
|
|
|
|
const user = await validateUserToken(authorization);
|
2023-11-22 15:44:49 +02:00
|
|
|
|
2023-11-30 14:39:31 +02:00
|
|
|
if (!user) {
|
|
|
|
|
return {
|
|
|
|
|
status: 401,
|
|
|
|
|
body: {
|
|
|
|
|
message: 'Unauthorized',
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-08 13:28:34 +00:00
|
|
|
const { data: documents, totalPages } = await findDocuments({ page, perPage, userId: user.id });
|
2023-11-22 15:44:49 +02:00
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
status: 200,
|
|
|
|
|
body: {
|
|
|
|
|
documents,
|
|
|
|
|
totalPages,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
},
|
2023-11-23 10:02:22 +02:00
|
|
|
getDocument: async (args) => {
|
2023-11-30 14:39:31 +02:00
|
|
|
const { id: documentId } = args.params;
|
|
|
|
|
const { authorization } = args.headers;
|
2023-11-23 10:02:22 +02:00
|
|
|
|
2023-11-30 14:39:31 +02:00
|
|
|
const user = await validateUserToken(authorization);
|
|
|
|
|
|
|
|
|
|
if (!user) {
|
|
|
|
|
return {
|
|
|
|
|
status: 401,
|
|
|
|
|
body: {
|
|
|
|
|
message: 'Unauthorized',
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const document = await getDocumentById({ id: Number(documentId), userId: user.id });
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
status: 200,
|
|
|
|
|
body: document,
|
|
|
|
|
};
|
|
|
|
|
} catch (e) {
|
|
|
|
|
return {
|
|
|
|
|
status: 404,
|
|
|
|
|
body: {
|
|
|
|
|
message: 'Document not found',
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
deleteDocument: async (args) => {
|
|
|
|
|
const { id: documentId } = args.params;
|
|
|
|
|
const { authorization } = args.headers;
|
|
|
|
|
|
|
|
|
|
const user = await validateUserToken(authorization);
|
|
|
|
|
|
|
|
|
|
if (!user) {
|
|
|
|
|
return {
|
|
|
|
|
status: 401,
|
|
|
|
|
body: {
|
|
|
|
|
message: 'Unauthorized',
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
2023-12-06 15:27:30 +00:00
|
|
|
const document = await getDocumentById({ id: Number(documentId), userId: user.id });
|
|
|
|
|
|
|
|
|
|
const deletedDocument = await deleteDocument({
|
|
|
|
|
id: Number(documentId),
|
|
|
|
|
userId: user.id,
|
|
|
|
|
status: document.status,
|
|
|
|
|
});
|
2023-11-30 14:39:31 +02:00
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
status: 200,
|
2023-12-06 15:27:30 +00:00
|
|
|
body: deletedDocument,
|
2023-11-30 14:39:31 +02:00
|
|
|
};
|
|
|
|
|
} catch (e) {
|
|
|
|
|
return {
|
|
|
|
|
status: 404,
|
|
|
|
|
body: {
|
|
|
|
|
message: 'Document not found',
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
2023-11-23 10:02:22 +02:00
|
|
|
},
|
2023-12-06 15:27:30 +00:00
|
|
|
createDocument: async (args) => {
|
2023-12-08 13:28:34 +00:00
|
|
|
const { body } = args;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const { url, key } = await getPresignPostUrl(body.fileName, body.contentType);
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
status: 200,
|
|
|
|
|
body: {
|
|
|
|
|
url,
|
|
|
|
|
key,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
} catch (e) {
|
|
|
|
|
return {
|
|
|
|
|
status: 404,
|
|
|
|
|
body: {
|
|
|
|
|
message: 'An error has occured while uploading the file',
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
sendDocumentForSigning: async (args) => {
|
2023-12-06 15:27:30 +00:00
|
|
|
const { authorization } = args.headers;
|
2023-12-08 13:28:34 +00:00
|
|
|
const { id } = args.params;
|
2023-12-06 15:27:30 +00:00
|
|
|
const { body } = args;
|
|
|
|
|
|
|
|
|
|
const user = await validateUserToken(authorization);
|
|
|
|
|
|
|
|
|
|
if (!user) {
|
|
|
|
|
return {
|
|
|
|
|
status: 401,
|
|
|
|
|
body: {
|
|
|
|
|
message: 'Unauthorized',
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-08 13:28:34 +00:00
|
|
|
const document = await getDocumentById({ id: Number(id), userId: user.id });
|
2023-12-06 15:27:30 +00:00
|
|
|
|
2023-12-08 13:28:34 +00:00
|
|
|
if (!document) {
|
|
|
|
|
return {
|
|
|
|
|
status: 404,
|
|
|
|
|
body: {
|
|
|
|
|
message: 'Document not found',
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
2023-12-06 15:27:30 +00:00
|
|
|
|
2023-12-08 13:28:34 +00:00
|
|
|
if (document.status === 'PENDING') {
|
|
|
|
|
return {
|
|
|
|
|
status: 400,
|
|
|
|
|
body: {
|
|
|
|
|
message: 'Document is already waiting for signing',
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
2023-12-06 15:27:30 +00:00
|
|
|
|
2023-12-08 13:28:34 +00:00
|
|
|
try {
|
|
|
|
|
await setRecipientsForDocument({
|
|
|
|
|
userId: user.id,
|
|
|
|
|
documentId: Number(id),
|
|
|
|
|
recipients: [
|
|
|
|
|
{
|
|
|
|
|
email: body.signerEmail,
|
|
|
|
|
name: body.signerName ?? '',
|
|
|
|
|
},
|
|
|
|
|
],
|
2023-12-06 15:27:30 +00:00
|
|
|
});
|
|
|
|
|
|
2023-12-08 13:28:34 +00:00
|
|
|
await setFieldsForDocument({
|
|
|
|
|
documentId: Number(id),
|
|
|
|
|
userId: user.id,
|
|
|
|
|
fields: body.fields.map((field) => ({
|
|
|
|
|
signerEmail: body.signerEmail,
|
|
|
|
|
type: field.fieldType,
|
|
|
|
|
pageNumber: field.pageNumber,
|
|
|
|
|
pageX: field.pageX,
|
|
|
|
|
pageY: field.pageY,
|
|
|
|
|
pageWidth: field.pageWidth,
|
|
|
|
|
pageHeight: field.pageHeight,
|
|
|
|
|
})),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (body.emailBody || body.emailSubject) {
|
|
|
|
|
await upsertDocumentMeta({
|
|
|
|
|
documentId: Number(id),
|
|
|
|
|
subject: body.emailSubject ?? '',
|
|
|
|
|
message: body.emailBody ?? '',
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await sendDocument({
|
|
|
|
|
documentId: Number(id),
|
2023-12-06 15:27:30 +00:00
|
|
|
userId: user.id,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
status: 200,
|
|
|
|
|
body: {
|
2023-12-08 13:28:34 +00:00
|
|
|
message: 'Document sent for signing successfully',
|
2023-12-06 15:27:30 +00:00
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
} catch (e) {
|
|
|
|
|
return {
|
|
|
|
|
status: 500,
|
|
|
|
|
body: {
|
|
|
|
|
message: 'An error occurred while uploading your document.',
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
},
|
2023-11-22 15:44:49 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const nextRouter = createNextRouter(contract, router);
|
|
|
|
|
|
|
|
|
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|
|
|
|
await nextRouter(req, res);
|
|
|
|
|
}
|