feat: expiry links

This commit is contained in:
Ephraim Atta-Duncan
2025-08-18 14:22:43 +00:00
parent ea7a2c2712
commit e24d00e23e
32 changed files with 935 additions and 6 deletions

View File

@ -24,6 +24,7 @@ import { sendDocument } from '@documenso/lib/server-only/document/send-document'
import { getTeamById } from '@documenso/lib/server-only/team/get-team';
import { getPresignPostUrl } from '@documenso/lib/universal/upload/server-actions';
import { isDocumentCompleted } from '@documenso/lib/utils/document';
import { isValidExpirySettings } from '@documenso/lib/utils/expiry';
import { authenticatedProcedure, procedure, router } from '../trpc';
import { downloadDocumentRoute } from './download-document';
@ -284,8 +285,16 @@ export const documentRouter = router({
globalActionAuth,
recipients,
meta,
expiryAmount,
expiryUnit,
} = input;
if ((expiryAmount || expiryUnit) && !isValidExpirySettings(expiryAmount, expiryUnit)) {
throw new AppError(AppErrorCode.INVALID_REQUEST, {
message: 'Invalid expiry settings. Please check your expiry configuration.',
});
}
const { remaining } = await getServerLimits({ userId: user.id, teamId });
if (remaining.documents <= 0) {
@ -316,6 +325,8 @@ export const documentRouter = router({
globalAccessAuth,
globalActionAuth,
recipients,
expiryAmount,
expiryUnit,
},
meta,
requestMetadata: ctx.metadata,
@ -345,7 +356,14 @@ export const documentRouter = router({
.input(ZCreateDocumentRequestSchema)
.mutation(async ({ input, ctx }) => {
const { user, teamId } = ctx;
const { title, documentDataId, timezone, folderId } = input;
const { title, documentDataId, timezone, folderId, expiryAmount, expiryUnit } = input;
// Validate expiry settings
if ((expiryAmount || expiryUnit) && !isValidExpirySettings(expiryAmount, expiryUnit)) {
throw new AppError(AppErrorCode.INVALID_REQUEST, {
message: 'Invalid expiry settings. Please check your expiry configuration.',
});
}
ctx.logger.info({
input: {
@ -371,6 +389,8 @@ export const documentRouter = router({
userTimezone: timezone,
requestMetadata: ctx.metadata,
folderId,
expiryAmount,
expiryUnit,
});
}),

View File

@ -117,6 +117,16 @@ export const ZDocumentMetaUploadSignatureEnabledSchema = z
.boolean()
.describe('Whether to allow recipients to sign using an uploaded signature.');
export const ZDocumentExpiryAmountSchema = z
.number()
.int()
.min(1)
.describe('The amount for expiry duration (e.g., 3 for "3 days").');
export const ZDocumentExpiryUnitSchema = z
.enum(['minutes', 'hours', 'days', 'weeks', 'months'])
.describe('The unit for expiry duration (e.g., "days" for "3 days").');
export const ZFindDocumentsRequestSchema = ZFindSearchParamsSchema.extend({
templateId: z
.number()
@ -200,6 +210,8 @@ export const ZCreateDocumentRequestSchema = z.object({
documentDataId: z.string().min(1),
timezone: ZDocumentMetaTimezoneSchema.optional(),
folderId: z.string().describe('The ID of the folder to create the document in').optional(),
expiryAmount: ZDocumentExpiryAmountSchema.optional(),
expiryUnit: ZDocumentExpiryUnitSchema.optional(),
});
export const ZCreateDocumentV2RequestSchema = z.object({
@ -209,6 +221,8 @@ export const ZCreateDocumentV2RequestSchema = z.object({
globalAccessAuth: z.array(ZDocumentAccessAuthTypesSchema).optional(),
globalActionAuth: z.array(ZDocumentActionAuthTypesSchema).optional(),
formValues: ZDocumentFormValuesSchema.optional(),
expiryAmount: ZDocumentExpiryAmountSchema.optional(),
expiryUnit: ZDocumentExpiryUnitSchema.optional(),
recipients: z
.array(
ZCreateRecipientSchema.extend({

View File

@ -1,5 +1,7 @@
import { AppError, AppErrorCode } from '@documenso/lib/errors/app-error';
import { upsertDocumentMeta } from '@documenso/lib/server-only/document-meta/upsert-document-meta';
import { updateDocument } from '@documenso/lib/server-only/document/update-document';
import { isValidExpirySettings } from '@documenso/lib/utils/expiry';
import { authenticatedProcedure } from '../trpc';
import {
@ -27,6 +29,15 @@ export const updateDocumentRoute = authenticatedProcedure
const userId = ctx.user.id;
if (
(meta.expiryAmount || meta.expiryUnit) &&
!isValidExpirySettings(meta.expiryAmount, meta.expiryUnit)
) {
throw new AppError(AppErrorCode.INVALID_REQUEST, {
message: 'Invalid expiry settings. Please check your expiry configuration.',
});
}
if (Object.values(meta).length > 0) {
await upsertDocumentMeta({
userId: ctx.user.id,
@ -47,6 +58,8 @@ export const updateDocumentRoute = authenticatedProcedure
emailId: meta.emailId,
emailReplyTo: meta.emailReplyTo,
emailSettings: meta.emailSettings,
expiryAmount: meta.expiryAmount,
expiryUnit: meta.expiryUnit,
requestMetadata: ctx.metadata,
});
}

View File

@ -11,6 +11,8 @@ import { ZDocumentEmailSettingsSchema } from '@documenso/lib/types/document-emai
import type { TrpcRouteMeta } from '../trpc';
import {
ZDocumentExpiryAmountSchema,
ZDocumentExpiryUnitSchema,
ZDocumentExternalIdSchema,
ZDocumentMetaDateFormatSchema,
ZDocumentMetaDistributionMethodSchema,
@ -64,6 +66,8 @@ export const ZUpdateDocumentRequestSchema = z.object({
emailId: z.string().nullish(),
emailReplyTo: z.string().email().nullish(),
emailSettings: ZDocumentEmailSettingsSchema.optional(),
expiryAmount: ZDocumentExpiryAmountSchema.optional(),
expiryUnit: ZDocumentExpiryUnitSchema.optional(),
})
.optional(),
});