mirror of
https://github.com/documenso/documenso.git
synced 2026-07-14 23:07:13 +10:00
fix: wip
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||
import { verifyEmbeddingPresignToken } from '@documenso/lib/server-only/embedding-presign/verify-embedding-presign-token';
|
||||
|
||||
import { createEnvelopeRouteCaller } from '../envelope-router/create-envelope';
|
||||
import { procedure } from '../trpc';
|
||||
import {
|
||||
ZCreateEmbeddingEnvelopeRequestSchema,
|
||||
ZCreateEmbeddingEnvelopeResponseSchema,
|
||||
} from './create-embedding-envelope.types';
|
||||
|
||||
export const createEmbeddingEnvelopeRoute = procedure
|
||||
.input(ZCreateEmbeddingEnvelopeRequestSchema)
|
||||
.output(ZCreateEmbeddingEnvelopeResponseSchema)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const { req } = ctx;
|
||||
|
||||
const authorizationHeader = req.headers.get('authorization');
|
||||
|
||||
const [presignToken] = (authorizationHeader || '').split('Bearer ').filter((s) => s.length > 0);
|
||||
|
||||
if (!presignToken) {
|
||||
throw new AppError(AppErrorCode.UNAUTHORIZED, {
|
||||
message: 'No presign token provided',
|
||||
});
|
||||
}
|
||||
|
||||
const apiToken = await verifyEmbeddingPresignToken({ token: presignToken });
|
||||
|
||||
const { userId, teamId } = apiToken;
|
||||
|
||||
return await createEnvelopeRouteCaller({
|
||||
userId,
|
||||
teamId,
|
||||
input,
|
||||
requestMetadata: ctx.metadata,
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
import {
|
||||
ZCreateEnvelopeRequestSchema,
|
||||
ZCreateEnvelopeResponseSchema,
|
||||
} from '../envelope-router/create-envelope.types';
|
||||
|
||||
export const ZCreateEmbeddingEnvelopeRequestSchema = ZCreateEnvelopeRequestSchema;
|
||||
|
||||
export const ZCreateEmbeddingEnvelopeResponseSchema = ZCreateEnvelopeResponseSchema;
|
||||
@@ -24,7 +24,9 @@ export const ZCreateEmbeddingPresignTokenRequestSchema = z.object({
|
||||
scope: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe('Resource restriction. Example: documentId:1, templateId:2'),
|
||||
.describe(
|
||||
'Resource restriction. V1 embeds only support documentId:1, templateId:2. V2 embeds only support envelope:envelope_123',
|
||||
),
|
||||
});
|
||||
|
||||
export const ZCreateEmbeddingPresignTokenResponseSchema = z.object({
|
||||
|
||||
@@ -5,10 +5,12 @@ import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
|
||||
import { createEnvelope } from '@documenso/lib/server-only/envelope/create-envelope';
|
||||
import { extractPdfPlaceholders } from '@documenso/lib/server-only/pdf/auto-place-fields';
|
||||
import { normalizePdf } from '@documenso/lib/server-only/pdf/normalize-pdf';
|
||||
import type { ApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
|
||||
import { putPdfFileServerSide } from '@documenso/lib/universal/upload/put-file.server';
|
||||
|
||||
import { insertFormValuesInPdf } from '../../../lib/server-only/pdf/insert-form-values-in-pdf';
|
||||
import { authenticatedProcedure } from '../trpc';
|
||||
import type { TCreateEnvelopeRequest } from './create-envelope.types';
|
||||
import {
|
||||
ZCreateEnvelopeRequestSchema,
|
||||
ZCreateEnvelopeResponseSchema,
|
||||
@@ -20,150 +22,176 @@ export const createEnvelopeRoute = authenticatedProcedure
|
||||
.input(ZCreateEnvelopeRequestSchema)
|
||||
.output(ZCreateEnvelopeResponseSchema)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
const { user, teamId } = ctx;
|
||||
ctx.logger.info({
|
||||
input: {
|
||||
folderId: input.payload.folderId,
|
||||
},
|
||||
});
|
||||
|
||||
const { payload, files } = input;
|
||||
return await createEnvelopeRouteCaller({
|
||||
userId: ctx.user.id,
|
||||
teamId: ctx.teamId,
|
||||
input,
|
||||
requestMetadata: ctx.metadata,
|
||||
});
|
||||
});
|
||||
|
||||
const {
|
||||
title,
|
||||
type CreateEnvelopeRouteOptions = {
|
||||
/**
|
||||
* Verified user ID.
|
||||
*/
|
||||
userId: number;
|
||||
|
||||
/**
|
||||
* Unverified team ID.
|
||||
*/
|
||||
teamId: number;
|
||||
input: TCreateEnvelopeRequest;
|
||||
requestMetadata: ApiRequestMetadata;
|
||||
};
|
||||
|
||||
export const createEnvelopeRouteCaller = async ({
|
||||
userId,
|
||||
teamId,
|
||||
input,
|
||||
requestMetadata,
|
||||
}: CreateEnvelopeRouteOptions) => {
|
||||
const { payload, files } = input;
|
||||
|
||||
const {
|
||||
title,
|
||||
type,
|
||||
externalId,
|
||||
visibility,
|
||||
globalAccessAuth,
|
||||
globalActionAuth,
|
||||
formValues,
|
||||
recipients,
|
||||
folderId,
|
||||
meta,
|
||||
attachments,
|
||||
delegatedDocumentOwner,
|
||||
} = payload;
|
||||
|
||||
const { remaining, maximumEnvelopeItemCount } = await getServerLimits({
|
||||
userId,
|
||||
teamId,
|
||||
});
|
||||
|
||||
if (remaining.documents <= 0) {
|
||||
throw new AppError(AppErrorCode.LIMIT_EXCEEDED, {
|
||||
message: 'You have reached your document limit for this month. Please upgrade your plan.',
|
||||
statusCode: 400,
|
||||
});
|
||||
}
|
||||
|
||||
if (files.length > maximumEnvelopeItemCount) {
|
||||
throw new AppError('ENVELOPE_ITEM_LIMIT_EXCEEDED', {
|
||||
message: `You cannot upload more than ${maximumEnvelopeItemCount} envelope items per envelope`,
|
||||
statusCode: 400,
|
||||
});
|
||||
}
|
||||
|
||||
if (files.some((file) => !file.type.startsWith('application/pdf'))) {
|
||||
throw new AppError('INVALID_DOCUMENT_FILE', {
|
||||
message: 'You cannot upload non-PDF files',
|
||||
statusCode: 400,
|
||||
});
|
||||
}
|
||||
|
||||
// For each file: normalize, extract & clean placeholders, then upload.
|
||||
const envelopeItems = await Promise.all(
|
||||
files.map(async (file) => {
|
||||
let pdf = Buffer.from(await file.arrayBuffer());
|
||||
|
||||
if (formValues) {
|
||||
// eslint-disable-next-line require-atomic-updates
|
||||
pdf = await insertFormValuesInPdf({
|
||||
pdf,
|
||||
formValues,
|
||||
});
|
||||
}
|
||||
|
||||
const normalized = await normalizePdf(pdf, {
|
||||
flattenForm: type !== EnvelopeType.TEMPLATE,
|
||||
});
|
||||
|
||||
const { cleanedPdf, placeholders } = await extractPdfPlaceholders(normalized);
|
||||
|
||||
const { id: documentDataId } = await putPdfFileServerSide({
|
||||
name: file.name,
|
||||
type: 'application/pdf',
|
||||
arrayBuffer: async () => Promise.resolve(cleanedPdf),
|
||||
});
|
||||
|
||||
return {
|
||||
title: file.name,
|
||||
documentDataId,
|
||||
placeholders,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
const recipientsToCreate = recipients?.map((recipient) => ({
|
||||
email: recipient.email,
|
||||
name: recipient.name,
|
||||
role: recipient.role,
|
||||
signingOrder: recipient.signingOrder,
|
||||
accessAuth: recipient.accessAuth,
|
||||
actionAuth: recipient.actionAuth,
|
||||
fields: recipient.fields?.map((field) => {
|
||||
let documentDataId: string | undefined = undefined;
|
||||
|
||||
if (typeof field.identifier === 'string') {
|
||||
documentDataId = envelopeItems.find(
|
||||
(item) => item.title === field.identifier,
|
||||
)?.documentDataId;
|
||||
}
|
||||
|
||||
if (typeof field.identifier === 'number') {
|
||||
documentDataId = envelopeItems.at(field.identifier)?.documentDataId;
|
||||
}
|
||||
|
||||
if (field.identifier === undefined) {
|
||||
documentDataId = envelopeItems.at(0)?.documentDataId;
|
||||
}
|
||||
|
||||
if (!documentDataId) {
|
||||
throw new AppError(AppErrorCode.NOT_FOUND, {
|
||||
message: 'Document data not found',
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
...field,
|
||||
documentDataId,
|
||||
};
|
||||
}),
|
||||
}));
|
||||
|
||||
const envelope = await createEnvelope({
|
||||
userId,
|
||||
teamId,
|
||||
internalVersion: 2,
|
||||
data: {
|
||||
type,
|
||||
title,
|
||||
externalId,
|
||||
formValues,
|
||||
visibility,
|
||||
globalAccessAuth,
|
||||
globalActionAuth,
|
||||
formValues,
|
||||
recipients,
|
||||
recipients: recipientsToCreate,
|
||||
folderId,
|
||||
meta,
|
||||
attachments,
|
||||
envelopeItems,
|
||||
delegatedDocumentOwner,
|
||||
} = payload;
|
||||
|
||||
ctx.logger.info({
|
||||
input: {
|
||||
folderId,
|
||||
},
|
||||
});
|
||||
|
||||
const { remaining, maximumEnvelopeItemCount } = await getServerLimits({
|
||||
userId: user.id,
|
||||
teamId,
|
||||
});
|
||||
|
||||
if (remaining.documents <= 0) {
|
||||
throw new AppError(AppErrorCode.LIMIT_EXCEEDED, {
|
||||
message: 'You have reached your document limit for this month. Please upgrade your plan.',
|
||||
statusCode: 400,
|
||||
});
|
||||
}
|
||||
|
||||
if (files.length > maximumEnvelopeItemCount) {
|
||||
throw new AppError('ENVELOPE_ITEM_LIMIT_EXCEEDED', {
|
||||
message: `You cannot upload more than ${maximumEnvelopeItemCount} envelope items per envelope`,
|
||||
statusCode: 400,
|
||||
});
|
||||
}
|
||||
|
||||
if (files.some((file) => !file.type.startsWith('application/pdf'))) {
|
||||
throw new AppError('INVALID_DOCUMENT_FILE', {
|
||||
message: 'You cannot upload non-PDF files',
|
||||
statusCode: 400,
|
||||
});
|
||||
}
|
||||
|
||||
// For each file: normalize, extract & clean placeholders, then upload.
|
||||
const envelopeItems = await Promise.all(
|
||||
files.map(async (file) => {
|
||||
let pdf = Buffer.from(await file.arrayBuffer());
|
||||
|
||||
if (formValues) {
|
||||
// eslint-disable-next-line require-atomic-updates
|
||||
pdf = await insertFormValuesInPdf({
|
||||
pdf,
|
||||
formValues,
|
||||
});
|
||||
}
|
||||
|
||||
const normalized = await normalizePdf(pdf, {
|
||||
flattenForm: type !== EnvelopeType.TEMPLATE,
|
||||
});
|
||||
|
||||
const { cleanedPdf, placeholders } = await extractPdfPlaceholders(normalized);
|
||||
|
||||
const { id: documentDataId } = await putPdfFileServerSide({
|
||||
name: file.name,
|
||||
type: 'application/pdf',
|
||||
arrayBuffer: async () => Promise.resolve(cleanedPdf),
|
||||
});
|
||||
|
||||
return {
|
||||
title: file.name,
|
||||
documentDataId,
|
||||
placeholders,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
const recipientsToCreate = recipients?.map((recipient) => ({
|
||||
email: recipient.email,
|
||||
name: recipient.name,
|
||||
role: recipient.role,
|
||||
signingOrder: recipient.signingOrder,
|
||||
accessAuth: recipient.accessAuth,
|
||||
actionAuth: recipient.actionAuth,
|
||||
fields: recipient.fields?.map((field) => {
|
||||
let documentDataId: string | undefined = undefined;
|
||||
|
||||
if (typeof field.identifier === 'string') {
|
||||
documentDataId = envelopeItems.find(
|
||||
(item) => item.title === field.identifier,
|
||||
)?.documentDataId;
|
||||
}
|
||||
|
||||
if (typeof field.identifier === 'number') {
|
||||
documentDataId = envelopeItems.at(field.identifier)?.documentDataId;
|
||||
}
|
||||
|
||||
if (field.identifier === undefined) {
|
||||
documentDataId = envelopeItems.at(0)?.documentDataId;
|
||||
}
|
||||
|
||||
if (!documentDataId) {
|
||||
throw new AppError(AppErrorCode.NOT_FOUND, {
|
||||
message: 'Document data not found',
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
...field,
|
||||
documentDataId,
|
||||
};
|
||||
}),
|
||||
}));
|
||||
|
||||
const envelope = await createEnvelope({
|
||||
userId: user.id,
|
||||
teamId,
|
||||
internalVersion: 2,
|
||||
data: {
|
||||
type,
|
||||
title,
|
||||
externalId,
|
||||
formValues,
|
||||
visibility,
|
||||
globalAccessAuth,
|
||||
globalActionAuth,
|
||||
recipients: recipientsToCreate,
|
||||
folderId,
|
||||
envelopeItems,
|
||||
delegatedDocumentOwner,
|
||||
},
|
||||
attachments,
|
||||
meta,
|
||||
requestMetadata: ctx.metadata,
|
||||
});
|
||||
|
||||
return {
|
||||
id: envelope.id,
|
||||
};
|
||||
},
|
||||
attachments,
|
||||
meta,
|
||||
requestMetadata,
|
||||
});
|
||||
|
||||
return {
|
||||
id: envelope.id,
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user