This commit is contained in:
David Nguyen
2026-02-17 13:45:09 +11:00
parent 2a53104644
commit 3acc029fef
10 changed files with 582 additions and 85 deletions
@@ -32,6 +32,10 @@ export const createEmbeddingEnvelopeRoute = procedure
userId,
teamId,
input,
requestMetadata: ctx.metadata,
options: {
// Default recipients should be added on the frontend automatically for embeds.
bypassDefaultRecipients: true,
},
apiRequestMetadata: ctx.metadata,
});
});
@@ -32,7 +32,7 @@ export const createEnvelopeRoute = authenticatedProcedure
userId: ctx.user.id,
teamId: ctx.teamId,
input,
requestMetadata: ctx.metadata,
apiRequestMetadata: ctx.metadata,
});
});
@@ -47,14 +47,19 @@ type CreateEnvelopeRouteOptions = {
*/
teamId: number;
input: TCreateEnvelopeRequest;
requestMetadata: ApiRequestMetadata;
apiRequestMetadata: ApiRequestMetadata;
options?: {
bypassDefaultRecipients?: boolean;
};
};
export const createEnvelopeRouteCaller = async ({
userId,
teamId,
input,
requestMetadata,
apiRequestMetadata,
options = {},
}: CreateEnvelopeRouteOptions) => {
const { payload, files } = input;
@@ -116,6 +121,7 @@ export const createEnvelopeRouteCaller = async ({
flattenForm: type !== EnvelopeType.TEMPLATE,
});
// Todo: Embeds - Does this need to be done on the frontend?
const { cleanedPdf, placeholders } = await extractPdfPlaceholders(normalized);
const { id: documentDataId } = await putPdfFileServerSide({
@@ -188,7 +194,8 @@ export const createEnvelopeRouteCaller = async ({
},
attachments,
meta,
requestMetadata,
requestMetadata: apiRequestMetadata,
bypassDefaultRecipients: options.bypassDefaultRecipients,
});
return {
@@ -1,6 +1,7 @@
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
import { getEnvelopeWhereInput } from '@documenso/lib/server-only/envelope/get-envelope-by-id';
import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs';
import type { ApiRequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
import { createDocumentAuditLogData } from '@documenso/lib/utils/document-audit-logs';
import { canEnvelopeItemsBeModified } from '@documenso/lib/utils/envelope';
import { prisma } from '@documenso/prisma';
@@ -57,50 +58,75 @@ export const deleteEnvelopeItemRoute = authenticatedProcedure
});
}
const result = await prisma.$transaction(async (tx) => {
const deletedEnvelopeItem = await tx.envelopeItem.delete({
where: {
id: envelopeItemId,
envelopeId: envelope.id,
},
select: {
id: true,
title: true,
documentData: {
select: {
id: true,
},
},
},
});
await tx.documentAuditLog.create({
data: createDocumentAuditLogData({
type: DOCUMENT_AUDIT_LOG_TYPE.ENVELOPE_ITEM_DELETED,
envelopeId: envelope.id,
data: {
envelopeItemId: deletedEnvelopeItem.id,
envelopeItemTitle: deletedEnvelopeItem.title,
},
user: {
name: user.name,
email: user.email,
},
requestMetadata: metadata.requestMetadata,
}),
});
return deletedEnvelopeItem;
});
await prisma.documentData.delete({
where: {
id: result.documentData.id,
envelopeItem: {
is: null,
},
},
await UNSAFE_deleteEnvelopeItem({
envelopeId,
envelopeItemId,
user,
apiRequestMetadata: metadata,
});
return ZGenericSuccessResponse;
});
type UnsafeDeleteEnvelopeItemOptions = {
envelopeId: string;
envelopeItemId: string;
user: {
id: number;
name: string | null;
email: string;
};
apiRequestMetadata: ApiRequestMetadata;
};
export const UNSAFE_deleteEnvelopeItem = async ({
envelopeId,
envelopeItemId,
user,
apiRequestMetadata,
}: UnsafeDeleteEnvelopeItemOptions) => {
const result = await prisma.$transaction(async (tx) => {
const deletedEnvelopeItem = await tx.envelopeItem.delete({
where: {
id: envelopeItemId,
envelopeId,
},
select: {
id: true,
title: true,
documentData: {
select: {
id: true,
},
},
},
});
await tx.documentAuditLog.create({
data: createDocumentAuditLogData({
type: DOCUMENT_AUDIT_LOG_TYPE.ENVELOPE_ITEM_DELETED,
envelopeId,
data: {
envelopeItemId: deletedEnvelopeItem.id,
envelopeItemTitle: deletedEnvelopeItem.title,
},
user: {
name: user.name,
email: user.email,
},
requestMetadata: apiRequestMetadata.requestMetadata,
}),
});
return deletedEnvelopeItem;
});
await prisma.documentData.delete({
where: {
id: result.documentData.id,
envelopeItem: {
is: null,
},
},
});
};
@@ -54,6 +54,9 @@ export const updateEnvelopeItemsRoute = authenticatedProcedure
});
}
// Note: This logic is duplicated in many places. If we plan to allow changing title/order
// even after the envelope has been sent, make sure to update it everywhere including
// embedding routes.
if (!canEnvelopeItemsBeModified(envelope, envelope.recipients)) {
throw new AppError(AppErrorCode.INVALID_REQUEST, {
message: 'Envelope item is not editable',
@@ -71,30 +74,51 @@ export const updateEnvelopeItemsRoute = authenticatedProcedure
});
}
const updatedEnvelopeItems = await Promise.all(
data.map(async ({ envelopeItemId, order, title }) =>
prisma.envelopeItem.update({
where: {
envelopeId: envelope.id,
id: envelopeItemId,
},
data: {
order,
title,
},
select: {
id: true,
order: true,
title: true,
envelopeId: true,
},
}),
),
);
// Todo: Envelope [AUDIT_LOGS]
const updatedEnvelopeItems = await UNSAFE_updateEnvelopeItems({
envelopeId,
data,
});
return {
data: updatedEnvelopeItems,
};
});
type UnsafeUpdateEnvelopeItemsOptions = {
envelopeId: string;
data: {
envelopeItemId: string;
order?: number;
title?: string;
}[];
};
export const UNSAFE_updateEnvelopeItems = async ({
envelopeId,
data,
}: UnsafeUpdateEnvelopeItemsOptions) => {
// Todo: Envelope [AUDIT_LOGS]
const updatedEnvelopeItems = await Promise.all(
data.map(async ({ envelopeItemId, order, title }) =>
prisma.envelopeItem.update({
where: {
envelopeId,
id: envelopeItemId,
},
data: {
order,
title,
},
select: {
id: true,
order: true,
title: true,
envelopeId: true,
},
}),
),
);
return updatedEnvelopeItems;
};