mirror of
https://github.com/documenso/documenso.git
synced 2026-07-25 17:35:05 +10:00
chore: merge main, resolve biome formatting conflicts
Merge origin/main into feat/document-file-conversion. Conflicts were format-only (Tailwind class ordering, single-line vs multi-line) plus two semantic merges: - files.helpers.ts: combine main's pending-PDF download path with the branch's original-source-file (DOCX/PNG/JPEG) download path - download-pdf.ts: combine main's versionToFilenameSuffix helper with the branch's server-provided Content-Disposition filename support
This commit is contained in:
@@ -1,3 +1,10 @@
|
||||
import { DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats';
|
||||
import { DEFAULT_DOCUMENT_TIME_ZONE } from '@documenso/lib/constants/time-zones';
|
||||
import { DOCUMENT_AUDIT_LOG_TYPE, RECIPIENT_DIFF_TYPE } from '@documenso/lib/types/document-audit-logs';
|
||||
import type { RequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
|
||||
import { fieldsContainUnsignedRequiredField } from '@documenso/lib/utils/advanced-fields-helpers';
|
||||
import { createDocumentAuditLogData } from '@documenso/lib/utils/document-audit-logs';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import {
|
||||
DocumentSigningOrder,
|
||||
DocumentStatus,
|
||||
@@ -10,25 +17,11 @@ import {
|
||||
} from '@prisma/client';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
import { DEFAULT_DOCUMENT_DATE_FORMAT } from '@documenso/lib/constants/date-formats';
|
||||
import { DEFAULT_DOCUMENT_TIME_ZONE } from '@documenso/lib/constants/time-zones';
|
||||
import {
|
||||
DOCUMENT_AUDIT_LOG_TYPE,
|
||||
RECIPIENT_DIFF_TYPE,
|
||||
} from '@documenso/lib/types/document-audit-logs';
|
||||
import type { RequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
|
||||
import { fieldsContainUnsignedRequiredField } from '@documenso/lib/utils/advanced-fields-helpers';
|
||||
import { createDocumentAuditLogData } from '@documenso/lib/utils/document-audit-logs';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
import { AppError, AppErrorCode } from '../../errors/app-error';
|
||||
import { jobs } from '../../jobs/client';
|
||||
import type { TRecipientAccessAuth } from '../../types/document-auth';
|
||||
import { DocumentAuth } from '../../types/document-auth';
|
||||
import {
|
||||
ZWebhookDocumentSchema,
|
||||
mapEnvelopeToWebhookDocumentPayload,
|
||||
} from '../../types/webhook-payload';
|
||||
import { mapEnvelopeToWebhookDocumentPayload, ZWebhookDocumentSchema } from '../../types/webhook-payload';
|
||||
import { extractDocumentAuthMethods } from '../../utils/document-auth';
|
||||
import type { EnvelopeIdOptions } from '../../utils/envelope';
|
||||
import { mapSecondaryIdToDocumentId, unsafeBuildEnvelopeIdQuery } from '../../utils/envelope';
|
||||
@@ -117,9 +110,7 @@ export const completeDocumentWithToken = async ({
|
||||
});
|
||||
|
||||
if (!isRecipientsTurn) {
|
||||
throw new Error(
|
||||
`Recipient ${recipient.id} attempted to complete the document before it was their turn`,
|
||||
);
|
||||
throw new Error(`Recipient ${recipient.id} attempted to complete the document before it was their turn`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,9 +180,7 @@ export const completeDocumentWithToken = async ({
|
||||
});
|
||||
|
||||
// This should be scoped to the current recipient.
|
||||
const uninsertedDateFields = fields.filter(
|
||||
(field) => field.type === FieldType.DATE && !field.inserted,
|
||||
);
|
||||
const uninsertedDateFields = fields.filter((field) => field.type === FieldType.DATE && !field.inserted);
|
||||
|
||||
let recipientName = recipient.name;
|
||||
let recipientEmail = recipient.email;
|
||||
|
||||
@@ -1,22 +1,17 @@
|
||||
import { createElement } from 'react';
|
||||
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import type { DocumentMeta, Envelope, Recipient, User } from '@prisma/client';
|
||||
import { DocumentStatus, EnvelopeType, SendStatus, WebhookTriggerEvents } from '@prisma/client';
|
||||
|
||||
import { mailer } from '@documenso/email/mailer';
|
||||
import DocumentCancelTemplate from '@documenso/email/templates/document-cancel';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import type { DocumentMeta, Envelope, Recipient, User } from '@prisma/client';
|
||||
import { DocumentStatus, EnvelopeType, SendStatus, WebhookTriggerEvents } from '@prisma/client';
|
||||
import { createElement } from 'react';
|
||||
|
||||
import { getI18nInstance } from '../../client-only/providers/i18n-server';
|
||||
import { NEXT_PUBLIC_WEBAPP_URL } from '../../constants/app';
|
||||
import { AppError, AppErrorCode } from '../../errors/app-error';
|
||||
import { DOCUMENT_AUDIT_LOG_TYPE } from '../../types/document-audit-logs';
|
||||
import { extractDerivedDocumentEmailSettings } from '../../types/document-email';
|
||||
import {
|
||||
ZWebhookDocumentSchema,
|
||||
mapEnvelopeToWebhookDocumentPayload,
|
||||
} from '../../types/webhook-payload';
|
||||
import { mapEnvelopeToWebhookDocumentPayload, ZWebhookDocumentSchema } from '../../types/webhook-payload';
|
||||
import type { ApiRequestMetadata } from '../../universal/extract-request-metadata';
|
||||
import { isDocumentCompleted } from '../../utils/document';
|
||||
import { createDocumentAuditLogData } from '../../utils/document-audit-logs';
|
||||
@@ -34,12 +29,7 @@ export type DeleteDocumentOptions = {
|
||||
requestMetadata: ApiRequestMetadata;
|
||||
};
|
||||
|
||||
export const deleteDocument = async ({
|
||||
id,
|
||||
userId,
|
||||
teamId,
|
||||
requestMetadata,
|
||||
}: DeleteDocumentOptions) => {
|
||||
export const deleteDocument = async ({ id, userId, teamId, requestMetadata }: DeleteDocumentOptions) => {
|
||||
const user = await prisma.user.findUnique({
|
||||
where: {
|
||||
id: userId,
|
||||
@@ -131,11 +121,7 @@ type HandleDocumentOwnerDeleteOptions = {
|
||||
requestMetadata: ApiRequestMetadata;
|
||||
};
|
||||
|
||||
const handleDocumentOwnerDelete = async ({
|
||||
envelope,
|
||||
user,
|
||||
requestMetadata,
|
||||
}: HandleDocumentOwnerDeleteOptions) => {
|
||||
const handleDocumentOwnerDelete = async ({ envelope, user, requestMetadata }: HandleDocumentOwnerDeleteOptions) => {
|
||||
if (envelope.deletedAt) {
|
||||
return;
|
||||
}
|
||||
@@ -199,9 +185,7 @@ const handleDocumentOwnerDelete = async ({
|
||||
});
|
||||
});
|
||||
|
||||
const isEnvelopeDeleteEmailEnabled = extractDerivedDocumentEmailSettings(
|
||||
envelope.documentMeta,
|
||||
).documentDeleted;
|
||||
const isEnvelopeDeleteEmailEnabled = extractDerivedDocumentEmailSettings(envelope.documentMeta).documentDeleted;
|
||||
|
||||
if (!isEnvelopeDeleteEmailEnabled) {
|
||||
return deletedEnvelope;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { type DocumentAuditLog, EnvelopeType, type Prisma } from '@prisma/client';
|
||||
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { type DocumentAuditLog, EnvelopeType, type Prisma } from '@prisma/client';
|
||||
|
||||
import { AppError, AppErrorCode } from '../../errors/app-error';
|
||||
import { DOCUMENT_AUDIT_LOG_TYPE } from '../../types/document-audit-logs';
|
||||
@@ -99,7 +98,7 @@ export const findDocumentAuditLogs = async ({
|
||||
}),
|
||||
]);
|
||||
|
||||
let nextCursor: string | undefined = undefined;
|
||||
let nextCursor: string | undefined;
|
||||
|
||||
const parsedData = data.map((auditLog) => parseDocumentAuditLogData(auditLog));
|
||||
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
import { kyselyPrisma, prisma, sql } from '@documenso/prisma';
|
||||
import type { DB } from '@documenso/prisma/generated/types';
|
||||
import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-document-status';
|
||||
import type { DocumentSource, Envelope, Team, TeamEmail } from '@prisma/client';
|
||||
import { DocumentVisibility } from '@prisma/client';
|
||||
import { DocumentStatus } from '@prisma/client';
|
||||
import { EnvelopeType, RecipientRole, SigningStatus, TeamMemberRole } from '@prisma/client';
|
||||
import {
|
||||
DocumentStatus,
|
||||
DocumentVisibility,
|
||||
EnvelopeType,
|
||||
RecipientRole,
|
||||
SigningStatus,
|
||||
TeamMemberRole,
|
||||
} from '@prisma/client';
|
||||
import type { Expression, ExpressionBuilder, SelectQueryBuilder, SqlBool } from 'kysely';
|
||||
import { DateTime } from 'luxon';
|
||||
import { match } from 'ts-pattern';
|
||||
|
||||
import { kyselyPrisma, prisma, sql } from '@documenso/prisma';
|
||||
import type { DB } from '@documenso/prisma/generated/types';
|
||||
import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-document-status';
|
||||
|
||||
import { type FindResultResponse } from '../../types/search-params';
|
||||
import type { FindResultResponse } from '../../types/search-params';
|
||||
import { maskRecipientTokensForDocument } from '../../utils/mask-recipient-tokens-for-document';
|
||||
import { getTeamById } from '../team/get-team';
|
||||
|
||||
@@ -137,18 +141,14 @@ export const findDocuments = async ({
|
||||
// folder, period, sender, source, template, and search.
|
||||
|
||||
const buildBaseQuery = () => {
|
||||
let qb = kyselyPrisma.$kysely
|
||||
.selectFrom('Envelope')
|
||||
.select(['Envelope.id', 'Envelope.createdAt']);
|
||||
let qb = kyselyPrisma.$kysely.selectFrom('Envelope').select(['Envelope.id', 'Envelope.createdAt']);
|
||||
|
||||
// Type must be DOCUMENT (enum cast requires raw sql — this is the one escape hatch)
|
||||
qb = qb.where('Envelope.type', '=', sql.lit(EnvelopeType.DOCUMENT));
|
||||
|
||||
// Folder filter
|
||||
qb =
|
||||
folderId !== undefined
|
||||
? qb.where('Envelope.folderId', '=', folderId)
|
||||
: qb.where('Envelope.folderId', 'is', null);
|
||||
folderId !== undefined ? qb.where('Envelope.folderId', '=', folderId) : qb.where('Envelope.folderId', 'is', null);
|
||||
|
||||
// Period filter
|
||||
if (period) {
|
||||
@@ -220,10 +220,7 @@ export const findDocuments = async ({
|
||||
eb.or([
|
||||
eb('Envelope.userId', '=', user.id),
|
||||
eb.and([
|
||||
eb('Envelope.status', 'in', [
|
||||
sql.lit(DocumentStatus.COMPLETED),
|
||||
sql.lit(DocumentStatus.PENDING),
|
||||
]),
|
||||
eb('Envelope.status', 'in', [sql.lit(DocumentStatus.COMPLETED), sql.lit(DocumentStatus.PENDING)]),
|
||||
recipientExists(eb, user.email),
|
||||
]),
|
||||
]),
|
||||
@@ -311,10 +308,7 @@ export const findDocuments = async ({
|
||||
DocumentVisibility.MANAGER_AND_ABOVE,
|
||||
DocumentVisibility.ADMIN,
|
||||
])
|
||||
.with(TeamMemberRole.MANAGER, () => [
|
||||
DocumentVisibility.EVERYONE,
|
||||
DocumentVisibility.MANAGER_AND_ABOVE,
|
||||
])
|
||||
.with(TeamMemberRole.MANAGER, () => [DocumentVisibility.EVERYONE, DocumentVisibility.MANAGER_AND_ABOVE])
|
||||
.otherwise(() => [DocumentVisibility.EVERYONE]);
|
||||
|
||||
// Visibility: meets role threshold OR directly involved
|
||||
@@ -331,15 +325,11 @@ export const findDocuments = async ({
|
||||
|
||||
// Deleted filter for team path
|
||||
const teamDeletedFilter = (eb: EnvelopeExpressionBuilder) => {
|
||||
const branches = [
|
||||
eb.and([eb('Envelope.teamId', '=', teamData.id), eb('Envelope.deletedAt', 'is', null)]),
|
||||
];
|
||||
const branches = [eb.and([eb('Envelope.teamId', '=', teamData.id), eb('Envelope.deletedAt', 'is', null)])];
|
||||
|
||||
if (teamEmail) {
|
||||
branches.push(eb.and([senderEmailIs(eb, teamEmail), eb('Envelope.deletedAt', 'is', null)]));
|
||||
branches.push(
|
||||
recipientExists(eb, teamEmail, (reb) => reb('Recipient.documentDeletedAt', 'is', null)),
|
||||
);
|
||||
branches.push(recipientExists(eb, teamEmail, (reb) => reb('Recipient.documentDeletedAt', 'is', null)));
|
||||
}
|
||||
|
||||
return eb.or(branches);
|
||||
@@ -353,10 +343,7 @@ export const findDocuments = async ({
|
||||
if (teamEmail) {
|
||||
accessBranches.push(senderEmailIs(eb, teamEmail));
|
||||
accessBranches.push(
|
||||
eb.and([
|
||||
eb('status', '!=', sql.lit(ExtendedDocumentStatus.DRAFT)),
|
||||
recipientExists(eb, teamEmail),
|
||||
]),
|
||||
eb.and([eb('status', '!=', sql.lit(ExtendedDocumentStatus.DRAFT)), recipientExists(eb, teamEmail)]),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -368,23 +355,21 @@ export const findDocuments = async ({
|
||||
return null;
|
||||
}
|
||||
|
||||
return qb
|
||||
.where('Envelope.status', '!=', sql.lit(ExtendedDocumentStatus.DRAFT))
|
||||
.where((eb) =>
|
||||
eb.and([
|
||||
visibilityFilter(eb),
|
||||
// Single EXISTS check: the team-email recipient must be NOT_SIGNED,
|
||||
// non-CC, and not soft-deleted. Replaces teamDeletedFilter + separate
|
||||
// recipientExists, eliminating a hashed SubPlan (~79k rows).
|
||||
recipientExists(eb, teamEmail, (reb) =>
|
||||
reb.and([
|
||||
reb('Recipient.documentDeletedAt', 'is', null),
|
||||
reb('Recipient.signingStatus', '=', sql.lit(SigningStatus.NOT_SIGNED)),
|
||||
reb('Recipient.role', '!=', sql.lit(RecipientRole.CC)),
|
||||
]),
|
||||
),
|
||||
]),
|
||||
);
|
||||
return qb.where('Envelope.status', '!=', sql.lit(ExtendedDocumentStatus.DRAFT)).where((eb) =>
|
||||
eb.and([
|
||||
visibilityFilter(eb),
|
||||
// Single EXISTS check: the team-email recipient must be NOT_SIGNED,
|
||||
// non-CC, and not soft-deleted. Replaces teamDeletedFilter + separate
|
||||
// recipientExists, eliminating a hashed SubPlan (~79k rows).
|
||||
recipientExists(eb, teamEmail, (reb) =>
|
||||
reb.and([
|
||||
reb('Recipient.documentDeletedAt', 'is', null),
|
||||
reb('Recipient.signingStatus', '=', sql.lit(SigningStatus.NOT_SIGNED)),
|
||||
reb('Recipient.role', '!=', sql.lit(RecipientRole.CC)),
|
||||
]),
|
||||
),
|
||||
]),
|
||||
);
|
||||
})
|
||||
.with(ExtendedDocumentStatus.DRAFT, () =>
|
||||
qb.where('Envelope.status', '=', sql.lit(ExtendedDocumentStatus.DRAFT)).where((eb) => {
|
||||
@@ -466,10 +451,7 @@ export const findDocuments = async ({
|
||||
const offset = Math.max(page - 1, 0) * perPage;
|
||||
|
||||
// Data query: paginated, executed directly via Kysely query builder
|
||||
const dataQuery = filteredQuery
|
||||
.orderBy(`Envelope.${orderByColumn}`, orderByDirection)
|
||||
.limit(perPage)
|
||||
.offset(offset);
|
||||
const dataQuery = filteredQuery.orderBy(`Envelope.${orderByColumn}`, orderByDirection).limit(perPage).offset(offset);
|
||||
|
||||
// Count query: either windowed (fast, capped) or full (exact, for API consumers).
|
||||
const baseCountQuery = filteredQuery.clearSelect().select('Envelope.id');
|
||||
@@ -482,10 +464,7 @@ export const findDocuments = async ({
|
||||
.selectFrom(baseCountQuery.as('filtered'))
|
||||
.select(({ fn }) => fn.count<number>('id').as('total'));
|
||||
|
||||
const [dataResult, countResult] = await Promise.all([
|
||||
dataQuery.execute(),
|
||||
countQuery.executeTakeFirstOrThrow(),
|
||||
]);
|
||||
const [dataResult, countResult] = await Promise.all([dataQuery.execute(), countQuery.executeTakeFirstOrThrow()]);
|
||||
|
||||
const ids = dataResult.map((row) => row.id);
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { DocumentStatus, EnvelopeType } from '@prisma/client';
|
||||
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { DocumentStatus, EnvelopeType } from '@prisma/client';
|
||||
|
||||
import { mapSecondaryIdToDocumentId } from '../../utils/envelope';
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { EnvelopeType } from '@prisma/client';
|
||||
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { EnvelopeType } from '@prisma/client';
|
||||
|
||||
import { AppError, AppErrorCode } from '../../errors/app-error';
|
||||
import type { TDocumentAuthMethods } from '../../types/document-auth';
|
||||
|
||||
@@ -7,9 +7,7 @@ export type GetDocumentCertificateAuditLogsOptions = {
|
||||
envelopeId: string;
|
||||
};
|
||||
|
||||
export const getDocumentCertificateAuditLogs = async ({
|
||||
envelopeId,
|
||||
}: GetDocumentCertificateAuditLogsOptions) => {
|
||||
export const getDocumentCertificateAuditLogs = async ({ envelopeId }: GetDocumentCertificateAuditLogsOptions) => {
|
||||
const rawAuditLogs = await prisma.documentAuditLog.findMany({
|
||||
where: {
|
||||
envelopeId,
|
||||
|
||||
@@ -9,11 +9,7 @@ export type GetDocumentWithDetailsByIdOptions = {
|
||||
teamId: number;
|
||||
};
|
||||
|
||||
export const getDocumentWithDetailsById = async ({
|
||||
id,
|
||||
userId,
|
||||
teamId,
|
||||
}: GetDocumentWithDetailsByIdOptions) => {
|
||||
export const getDocumentWithDetailsById = async ({ id, userId, teamId }: GetDocumentWithDetailsByIdOptions) => {
|
||||
const envelope = await getEnvelopeById({
|
||||
id,
|
||||
type: EnvelopeType.DOCUMENT,
|
||||
|
||||
@@ -4,9 +4,7 @@ export type GetRecipientOrSenderByShareLinkSlugOptions = {
|
||||
slug: string;
|
||||
};
|
||||
|
||||
export const getRecipientOrSenderByShareLinkSlug = async ({
|
||||
slug,
|
||||
}: GetRecipientOrSenderByShareLinkSlugOptions) => {
|
||||
export const getRecipientOrSenderByShareLinkSlug = async ({ slug }: GetRecipientOrSenderByShareLinkSlugOptions) => {
|
||||
const { envelopeId, email } = await prisma.documentShareLink.findFirstOrThrow({
|
||||
where: {
|
||||
slug,
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
import {
|
||||
DocumentStatus,
|
||||
EnvelopeType,
|
||||
RecipientRole,
|
||||
SigningStatus,
|
||||
TeamMemberRole,
|
||||
} from '@prisma/client';
|
||||
import type { Expression, ExpressionBuilder, SelectQueryBuilder, SqlBool } from 'kysely';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
import type { PeriodSelectorValue } from '@documenso/lib/server-only/document/find-documents';
|
||||
import { kyselyPrisma, prisma, sql } from '@documenso/prisma';
|
||||
import type { DB } from '@documenso/prisma/generated/types';
|
||||
import { ExtendedDocumentStatus } from '@documenso/prisma/types/extended-document-status';
|
||||
import { DocumentStatus, EnvelopeType, RecipientRole, SigningStatus, TeamMemberRole } from '@prisma/client';
|
||||
import type { Expression, ExpressionBuilder, SelectQueryBuilder, SqlBool } from 'kysely';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
import { STATS_COUNT_CAP } from '../../constants/document';
|
||||
import { TEAM_DOCUMENT_VISIBILITY_MAP } from '../../constants/teams';
|
||||
@@ -87,14 +80,7 @@ const cappedCount = async (qb: EnvelopeQueryBuilder): Promise<number> => {
|
||||
return Math.min(Number(result.total ?? 0), STATS_COUNT_CAP);
|
||||
};
|
||||
|
||||
export const getStats = async ({
|
||||
userId,
|
||||
teamId,
|
||||
period,
|
||||
search = '',
|
||||
folderId,
|
||||
senderIds,
|
||||
}: GetStatsInput) => {
|
||||
export const getStats = async ({ userId, teamId, period, search = '', folderId, senderIds }: GetStatsInput) => {
|
||||
const user = await prisma.user.findFirstOrThrow({
|
||||
where: { id: userId },
|
||||
select: { id: true, email: true },
|
||||
@@ -113,18 +99,14 @@ export const getStats = async ({
|
||||
// ─── Base query builder ──────────────────────────────────────────────
|
||||
|
||||
const buildBaseQuery = (): EnvelopeQueryBuilder => {
|
||||
let qb: EnvelopeQueryBuilder = kyselyPrisma.$kysely
|
||||
.selectFrom('Envelope')
|
||||
.select('Envelope.id');
|
||||
let qb: EnvelopeQueryBuilder = kyselyPrisma.$kysely.selectFrom('Envelope').select('Envelope.id');
|
||||
|
||||
// Type = DOCUMENT
|
||||
qb = qb.where('Envelope.type', '=', sql.lit(EnvelopeType.DOCUMENT));
|
||||
|
||||
// Folder filter
|
||||
qb =
|
||||
folderId !== undefined
|
||||
? qb.where('Envelope.folderId', '=', folderId)
|
||||
: qb.where('Envelope.folderId', 'is', null);
|
||||
folderId !== undefined ? qb.where('Envelope.folderId', '=', folderId) : qb.where('Envelope.folderId', 'is', null);
|
||||
|
||||
// Period filter
|
||||
if (period) {
|
||||
@@ -181,15 +163,11 @@ export const getStats = async ({
|
||||
]);
|
||||
|
||||
const teamDeletedFilter = (eb: EnvelopeExpressionBuilder) => {
|
||||
const branches = [
|
||||
eb.and([eb('Envelope.teamId', '=', team.id), eb('Envelope.deletedAt', 'is', null)]),
|
||||
];
|
||||
const branches = [eb.and([eb('Envelope.teamId', '=', team.id), eb('Envelope.deletedAt', 'is', null)])];
|
||||
|
||||
if (teamEmail) {
|
||||
branches.push(eb.and([senderEmailIs(eb, teamEmail), eb('Envelope.deletedAt', 'is', null)]));
|
||||
branches.push(
|
||||
recipientExists(eb, teamEmail, (reb) => reb('Recipient.documentDeletedAt', 'is', null)),
|
||||
);
|
||||
branches.push(recipientExists(eb, teamEmail, (reb) => reb('Recipient.documentDeletedAt', 'is', null)));
|
||||
}
|
||||
|
||||
return eb.or(branches);
|
||||
@@ -254,9 +232,7 @@ export const getStats = async ({
|
||||
if (teamEmail) {
|
||||
accessBranches.push(senderEmailIs(eb, teamEmail));
|
||||
accessBranches.push(
|
||||
recipientExists(eb, teamEmail, (reb) =>
|
||||
reb('Recipient.signingStatus', '=', sql.lit(SigningStatus.REJECTED)),
|
||||
),
|
||||
recipientExists(eb, teamEmail, (reb) => reb('Recipient.signingStatus', '=', sql.lit(SigningStatus.REJECTED))),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import type { Envelope, Recipient } from '@prisma/client';
|
||||
import { verifyAuthenticationResponse } from '@simplewebauthn/server';
|
||||
import { isoBase64URL } from '@simplewebauthn/server/helpers';
|
||||
import { match } from 'ts-pattern';
|
||||
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
import { validateTwoFactorTokenFromEmail } from '../2fa/email/validate-2fa-token-from-email';
|
||||
import { verifyTwoFactorAuthenticationToken } from '../2fa/verify-2fa-token';
|
||||
import { verifyPassword } from '../2fa/verify-password';
|
||||
import { AppError, AppErrorCode } from '../../errors/app-error';
|
||||
import type { TDocumentAuth, TDocumentAuthMethods } from '../../types/document-auth';
|
||||
import { DocumentAuth } from '../../types/document-auth';
|
||||
import type { TAuthenticationResponseJSONSchema } from '../../types/webauthn';
|
||||
import { getAuthenticatorOptions } from '../../utils/authenticator';
|
||||
import { extractDocumentAuthMethods } from '../../utils/document-auth';
|
||||
import { validateTwoFactorTokenFromEmail } from '../2fa/email/validate-2fa-token-from-email';
|
||||
import { verifyTwoFactorAuthenticationToken } from '../2fa/verify-2fa-token';
|
||||
import { verifyPassword } from '../2fa/verify-password';
|
||||
|
||||
type IsRecipientAuthorizedOptions = {
|
||||
// !: Probably find a better name than 'ACCESS_2FA' if requirements change.
|
||||
@@ -71,10 +69,7 @@ export const isRecipientAuthorized = async ({
|
||||
.exhaustive();
|
||||
|
||||
// Early true return when auth is not required.
|
||||
if (
|
||||
authMethods.length === 0 ||
|
||||
authMethods.some((method) => method === DocumentAuth.EXPLICIT_NONE)
|
||||
) {
|
||||
if (authMethods.length === 0 || authMethods.some((method) => method === DocumentAuth.EXPLICIT_NONE)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { DocumentStatus, EnvelopeType, SigningStatus } from '@prisma/client';
|
||||
|
||||
import { jobs } from '@documenso/lib/jobs/client';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { DocumentStatus, EnvelopeType, SigningStatus } from '@prisma/client';
|
||||
|
||||
import { AppError, AppErrorCode } from '../../errors/app-error';
|
||||
import { DOCUMENT_AUDIT_LOG_TYPE } from '../../types/document-audit-logs';
|
||||
@@ -18,12 +17,7 @@ export type RejectDocumentWithTokenOptions = {
|
||||
requestMetadata?: RequestMetadata;
|
||||
};
|
||||
|
||||
export async function rejectDocumentWithToken({
|
||||
token,
|
||||
id,
|
||||
reason,
|
||||
requestMetadata,
|
||||
}: RejectDocumentWithTokenOptions) {
|
||||
export async function rejectDocumentWithToken({ token, id, reason, requestMetadata }: RejectDocumentWithTokenOptions) {
|
||||
// Find the recipient and document in a single query
|
||||
const recipient = await prisma.recipient.findFirst({
|
||||
where: {
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import { createElement } from 'react';
|
||||
|
||||
import { mailer } from '@documenso/email/mailer';
|
||||
import { DocumentInviteEmailTemplate } from '@documenso/email/templates/document-invite';
|
||||
import { resolveExpiresAt } from '@documenso/lib/constants/envelope-expiration';
|
||||
import { RECIPIENT_ROLE_TO_EMAIL_TYPE, RECIPIENT_ROLES_DESCRIPTION } from '@documenso/lib/constants/recipient-roles';
|
||||
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 { renderCustomEmailTemplate } from '@documenso/lib/utils/render-custom-email-template';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import {
|
||||
DocumentStatus,
|
||||
@@ -9,27 +16,12 @@ import {
|
||||
SigningStatus,
|
||||
WebhookTriggerEvents,
|
||||
} from '@prisma/client';
|
||||
|
||||
import { mailer } from '@documenso/email/mailer';
|
||||
import { DocumentInviteEmailTemplate } from '@documenso/email/templates/document-invite';
|
||||
import { resolveExpiresAt } from '@documenso/lib/constants/envelope-expiration';
|
||||
import {
|
||||
RECIPIENT_ROLES_DESCRIPTION,
|
||||
RECIPIENT_ROLE_TO_EMAIL_TYPE,
|
||||
} from '@documenso/lib/constants/recipient-roles';
|
||||
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 { renderCustomEmailTemplate } from '@documenso/lib/utils/render-custom-email-template';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { createElement } from 'react';
|
||||
|
||||
import { getI18nInstance } from '../../client-only/providers/i18n-server';
|
||||
import { NEXT_PUBLIC_WEBAPP_URL } from '../../constants/app';
|
||||
import { extractDerivedDocumentEmailSettings } from '../../types/document-email';
|
||||
import {
|
||||
ZWebhookDocumentSchema,
|
||||
mapEnvelopeToWebhookDocumentPayload,
|
||||
} from '../../types/webhook-payload';
|
||||
import { mapEnvelopeToWebhookDocumentPayload, ZWebhookDocumentSchema } from '../../types/webhook-payload';
|
||||
import { isDocumentCompleted } from '../../utils/document';
|
||||
import type { EnvelopeIdOptions } from '../../utils/envelope';
|
||||
import { isRecipientEmailValidForSending } from '../../utils/recipients';
|
||||
@@ -46,13 +38,7 @@ export type ResendDocumentOptions = {
|
||||
requestMetadata: ApiRequestMetadata;
|
||||
};
|
||||
|
||||
export const resendDocument = async ({
|
||||
id,
|
||||
userId,
|
||||
recipients,
|
||||
teamId,
|
||||
requestMetadata,
|
||||
}: ResendDocumentOptions) => {
|
||||
export const resendDocument = async ({ id, userId, recipients, teamId, requestMetadata }: ResendDocumentOptions) => {
|
||||
const user = await prisma.user.findFirstOrThrow({
|
||||
where: {
|
||||
id: userId,
|
||||
@@ -134,15 +120,14 @@ export const resendDocument = async ({
|
||||
return envelope;
|
||||
}
|
||||
|
||||
const { branding, emailLanguage, organisationType, senderEmail, replyToEmail } =
|
||||
await getEmailContext({
|
||||
emailType: 'RECIPIENT',
|
||||
source: {
|
||||
type: 'team',
|
||||
teamId: envelope.teamId,
|
||||
},
|
||||
meta: envelope.documentMeta,
|
||||
});
|
||||
const { branding, emailLanguage, organisationType, senderEmail, replyToEmail } = await getEmailContext({
|
||||
emailType: 'RECIPIENT',
|
||||
source: {
|
||||
type: 'team',
|
||||
teamId: envelope.teamId,
|
||||
},
|
||||
meta: envelope.documentMeta,
|
||||
});
|
||||
|
||||
await Promise.all(
|
||||
recipientsToRemind.map(async (recipient) => {
|
||||
@@ -157,9 +142,7 @@ export const resendDocument = async ({
|
||||
const { email, name } = recipient;
|
||||
const selfSigner = email === user.email;
|
||||
|
||||
const recipientActionVerb = i18n
|
||||
._(RECIPIENT_ROLES_DESCRIPTION[recipient.role].actionVerb)
|
||||
.toLowerCase();
|
||||
const recipientActionVerb = i18n._(RECIPIENT_ROLES_DESCRIPTION[recipient.role].actionVerb).toLowerCase();
|
||||
|
||||
let emailMessage = envelope.documentMeta.message || '';
|
||||
let emailSubject = i18n._(msg`Reminder: Please ${recipientActionVerb} this document`);
|
||||
@@ -172,9 +155,7 @@ export const resendDocument = async ({
|
||||
}
|
||||
|
||||
if (organisationType === OrganisationType.ORGANISATION) {
|
||||
emailSubject = i18n._(
|
||||
msg`Reminder: ${envelope.team.name} invited you to ${recipientActionVerb} a document`,
|
||||
);
|
||||
emailSubject = i18n._(msg`Reminder: ${envelope.team.name} invited you to ${recipientActionVerb} a document`);
|
||||
emailMessage =
|
||||
envelope.documentMeta.message ||
|
||||
i18n._(
|
||||
@@ -229,10 +210,7 @@ export const resendDocument = async ({
|
||||
from: senderEmail,
|
||||
replyTo: replyToEmail,
|
||||
subject: envelope.documentMeta.subject
|
||||
? renderCustomEmailTemplate(
|
||||
i18n._(msg`Reminder: ${envelope.documentMeta.subject}`),
|
||||
customEmailTemplate,
|
||||
)
|
||||
? renderCustomEmailTemplate(i18n._(msg`Reminder: ${envelope.documentMeta.subject}`), customEmailTemplate)
|
||||
: emailSubject,
|
||||
html,
|
||||
text,
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { formatDocumentsPath, getHighestTeamRoleInGroup } from '@documenso/lib/utils/teams';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import type { Prisma } from '@prisma/client';
|
||||
import { DocumentStatus, DocumentVisibility, EnvelopeType, TeamMemberRole } from '@prisma/client';
|
||||
import { match } from 'ts-pattern';
|
||||
|
||||
import { formatDocumentsPath, getHighestTeamRoleInGroup } from '@documenso/lib/utils/teams';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
|
||||
import { mapSecondaryIdToDocumentId } from '../../utils/envelope';
|
||||
import { getUserTeamGroups } from '../team/get-user-team-groups';
|
||||
|
||||
@@ -14,11 +13,7 @@ export type SearchDocumentsWithKeywordOptions = {
|
||||
limit?: number;
|
||||
};
|
||||
|
||||
export const searchDocumentsWithKeyword = async ({
|
||||
query,
|
||||
userId,
|
||||
limit = 20,
|
||||
}: SearchDocumentsWithKeywordOptions) => {
|
||||
export const searchDocumentsWithKeyword = async ({ query, userId, limit = 20 }: SearchDocumentsWithKeywordOptions) => {
|
||||
if (!query.trim()) {
|
||||
return [];
|
||||
}
|
||||
@@ -135,10 +130,7 @@ export const searchDocumentsWithKeyword = async ({
|
||||
|
||||
let path: string;
|
||||
|
||||
if (
|
||||
envelope.userId === user.id ||
|
||||
(envelope.teamId && teamGroupsByTeamId.has(envelope.teamId))
|
||||
) {
|
||||
if (envelope.userId === user.id || (envelope.teamId && teamGroupsByTeamId.has(envelope.teamId))) {
|
||||
path = `${formatDocumentsPath(envelope.team.url)}/${legacyDocumentId}`;
|
||||
} else {
|
||||
const signingToken = envelope.recipients.find((r) => r.email === user.email)?.token;
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { createElement } from 'react';
|
||||
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { DocumentSource, EnvelopeType } from '@prisma/client';
|
||||
|
||||
import { mailer } from '@documenso/email/mailer';
|
||||
import { DocumentCompletedEmailTemplate } from '@documenso/email/templates/document-completed';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { DocumentSource, EnvelopeType } from '@prisma/client';
|
||||
import { createElement } from 'react';
|
||||
|
||||
import { getI18nInstance } from '../../client-only/providers/i18n-server';
|
||||
import { NEXT_PUBLIC_WEBAPP_URL } from '../../constants/app';
|
||||
@@ -86,8 +84,7 @@ export const sendCompletedEmail = async ({ id, requestMetadata }: SendDocumentOp
|
||||
const file = await getFileServerSide(envelopeItem.documentData);
|
||||
|
||||
// Use the envelope title for version 1, and the envelope item title for version 2.
|
||||
const fileNameToUse =
|
||||
envelope.internalVersion === 1 ? envelope.title : envelopeItem.title + '.pdf';
|
||||
const fileNameToUse = envelope.internalVersion === 1 ? envelope.title : envelopeItem.title + '.pdf';
|
||||
|
||||
return {
|
||||
filename: fileNameToUse.endsWith('.pdf') ? fileNameToUse : fileNameToUse + '.pdf',
|
||||
@@ -104,9 +101,7 @@ export const sendCompletedEmail = async ({ id, requestMetadata }: SendDocumentOp
|
||||
)}/${envelope.id}`;
|
||||
|
||||
if (envelope.team?.url) {
|
||||
documentOwnerDownloadLink = `${NEXT_PUBLIC_WEBAPP_URL()}/t/${envelope.team.url}/documents/${
|
||||
envelope.id
|
||||
}`;
|
||||
documentOwnerDownloadLink = `${NEXT_PUBLIC_WEBAPP_URL()}/t/${envelope.team.url}/documents/${envelope.id}`;
|
||||
}
|
||||
|
||||
const emailSettings = extractDerivedDocumentEmailSettings(envelope.documentMeta);
|
||||
@@ -120,8 +115,7 @@ export const sendCompletedEmail = async ({ id, requestMetadata }: SendDocumentOp
|
||||
// - Recipient emails are disabled
|
||||
if (
|
||||
isOwnerDocumentCompletedEmailEnabled &&
|
||||
(!envelope.recipients.find((recipient) => recipient.email === owner.email) ||
|
||||
!isDocumentCompletedEmailEnabled)
|
||||
(!envelope.recipients.find((recipient) => recipient.email === owner.email) || !isDocumentCompletedEmailEnabled)
|
||||
) {
|
||||
const template = createElement(DocumentCompletedEmailTemplate, {
|
||||
documentName: envelope.title,
|
||||
@@ -177,9 +171,7 @@ export const sendCompletedEmail = async ({ id, requestMetadata }: SendDocumentOp
|
||||
return;
|
||||
}
|
||||
|
||||
const recipientsToNotify = envelope.recipients.filter((recipient) =>
|
||||
isRecipientEmailValidForSending(recipient),
|
||||
);
|
||||
const recipientsToNotify = envelope.recipients.filter((recipient) => isRecipientEmailValidForSending(recipient));
|
||||
|
||||
await Promise.all(
|
||||
recipientsToNotify.map(async (recipient) => {
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { createElement } from 'react';
|
||||
|
||||
import { msg } from '@lingui/core/macro';
|
||||
|
||||
import { mailer } from '@documenso/email/mailer';
|
||||
import { DocumentSuperDeleteEmailTemplate } from '@documenso/email/templates/document-super-delete';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { createElement } from 'react';
|
||||
|
||||
import { getI18nInstance } from '../../client-only/providers/i18n-server';
|
||||
import { NEXT_PUBLIC_WEBAPP_URL } from '../../constants/app';
|
||||
@@ -42,9 +40,7 @@ export const sendDeleteEmail = async ({ envelopeId, reason }: SendDeleteEmailOpt
|
||||
});
|
||||
}
|
||||
|
||||
const isDocumentDeletedEmailEnabled = extractDerivedDocumentEmailSettings(
|
||||
envelope.documentMeta,
|
||||
).documentDeleted;
|
||||
const isDocumentDeletedEmailEnabled = extractDerivedDocumentEmailSettings(envelope.documentMeta).documentDeleted;
|
||||
|
||||
if (!isDocumentDeletedEmailEnabled) {
|
||||
return;
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
import { resolveExpiresAt } from '@documenso/lib/constants/envelope-expiration';
|
||||
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 { prisma } from '@documenso/prisma';
|
||||
import { checkboxValidationSigns } from '@documenso/ui/primitives/document-flow/field-items-advanced-settings/constants';
|
||||
import type { DocumentData, Envelope, EnvelopeItem, Field, Recipient } from '@prisma/client';
|
||||
import {
|
||||
DocumentSigningOrder,
|
||||
@@ -10,13 +16,6 @@ import {
|
||||
WebhookTriggerEvents,
|
||||
} from '@prisma/client';
|
||||
|
||||
import { resolveExpiresAt } from '@documenso/lib/constants/envelope-expiration';
|
||||
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 { prisma } from '@documenso/prisma';
|
||||
import { checkboxValidationSigns } from '@documenso/ui/primitives/document-flow/field-items-advanced-settings/constants';
|
||||
|
||||
import { validateCheckboxLength } from '../../advanced-fields-validation/validate-checkbox';
|
||||
import { DIRECT_TEMPLATE_RECIPIENT_EMAIL } from '../../constants/direct-templates';
|
||||
import { AppError, AppErrorCode } from '../../errors/app-error';
|
||||
@@ -30,20 +29,14 @@ import {
|
||||
ZRadioFieldMeta,
|
||||
ZTextFieldMeta,
|
||||
} from '../../types/field-meta';
|
||||
import {
|
||||
ZWebhookDocumentSchema,
|
||||
mapEnvelopeToWebhookDocumentPayload,
|
||||
} from '../../types/webhook-payload';
|
||||
import { mapEnvelopeToWebhookDocumentPayload, ZWebhookDocumentSchema } from '../../types/webhook-payload';
|
||||
import { getFileServerSide } from '../../universal/upload/get-file.server';
|
||||
import { putNormalizedPdfFileServerSide } from '../../universal/upload/put-file.server';
|
||||
import { isDocumentCompleted } from '../../utils/document';
|
||||
import { extractDocumentAuthMethods } from '../../utils/document-auth';
|
||||
import { type EnvelopeIdOptions, mapSecondaryIdToDocumentId } from '../../utils/envelope';
|
||||
import { toCheckboxCustomText, toRadioCustomText } from '../../utils/fields';
|
||||
import {
|
||||
getRecipientsWithMissingFields,
|
||||
isRecipientEmailValidForSending,
|
||||
} from '../../utils/recipients';
|
||||
import { getRecipientsWithMissingFields, isRecipientEmailValidForSending } from '../../utils/recipients';
|
||||
import { getEnvelopeWhereInput } from '../envelope/get-envelope-by-id';
|
||||
import { insertFormValuesInPdf } from '../pdf/insert-form-values-in-pdf';
|
||||
import { triggerWebhook } from '../webhooks/trigger/trigger-webhook';
|
||||
@@ -56,13 +49,7 @@ export type SendDocumentOptions = {
|
||||
requestMetadata: ApiRequestMetadata;
|
||||
};
|
||||
|
||||
export const sendDocument = async ({
|
||||
id,
|
||||
userId,
|
||||
teamId,
|
||||
sendEmail,
|
||||
requestMetadata,
|
||||
}: SendDocumentOptions) => {
|
||||
export const sendDocument = async ({ id, userId, teamId, sendEmail, requestMetadata }: SendDocumentOptions) => {
|
||||
const { envelopeWhereInput } = await getEnvelopeWhereInput({
|
||||
id,
|
||||
type: EnvelopeType.DOCUMENT,
|
||||
@@ -156,10 +143,7 @@ export const sendDocument = async ({
|
||||
});
|
||||
|
||||
// Validate that recipients who require fields (e.g., signers need signature fields) have them.
|
||||
const recipientsWithMissingFields = getRecipientsWithMissingFields(
|
||||
envelope.recipients,
|
||||
envelope.fields,
|
||||
);
|
||||
const recipientsWithMissingFields = getRecipientsWithMissingFields(envelope.recipients, envelope.fields);
|
||||
|
||||
if (recipientsWithMissingFields.length > 0) {
|
||||
const missingRecipientDescriptions = recipientsWithMissingFields
|
||||
@@ -172,8 +156,7 @@ export const sendDocument = async ({
|
||||
}
|
||||
|
||||
const allRecipientsHaveNoActionToTake = envelope.recipients.every(
|
||||
(recipient) =>
|
||||
recipient.role === RecipientRole.CC || recipient.signingStatus === SigningStatus.SIGNED,
|
||||
(recipient) => recipient.role === RecipientRole.CC || recipient.signingStatus === SigningStatus.SIGNED,
|
||||
);
|
||||
|
||||
if (allRecipientsHaveNoActionToTake) {
|
||||
@@ -456,11 +439,7 @@ export const extractFieldAutoInsertValues = (
|
||||
|
||||
// Auto insert checkbox fields with the pre-checked values.
|
||||
if (field.type === FieldType.CHECKBOX) {
|
||||
const {
|
||||
values = [],
|
||||
validationRule,
|
||||
validationLength,
|
||||
} = ZCheckboxFieldMeta.parse(field.fieldMeta);
|
||||
const { values = [], validationRule, validationLength } = ZCheckboxFieldMeta.parse(field.fieldMeta);
|
||||
|
||||
const checkedIndices: number[] = [];
|
||||
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { createElement } from 'react';
|
||||
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { EnvelopeType } from '@prisma/client';
|
||||
|
||||
import { mailer } from '@documenso/email/mailer';
|
||||
import { DocumentPendingEmailTemplate } from '@documenso/email/templates/document-pending';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { msg } from '@lingui/core/macro';
|
||||
import { EnvelopeType } from '@prisma/client';
|
||||
import { createElement } from 'react';
|
||||
|
||||
import { getI18nInstance } from '../../client-only/providers/i18n-server';
|
||||
import { NEXT_PUBLIC_WEBAPP_URL } from '../../constants/app';
|
||||
@@ -58,9 +56,7 @@ export const sendPendingEmail = async ({ id, recipientId }: SendPendingEmailOpti
|
||||
meta: envelope.documentMeta,
|
||||
});
|
||||
|
||||
const isDocumentPendingEmailEnabled = extractDerivedDocumentEmailSettings(
|
||||
envelope.documentMeta,
|
||||
).documentPending;
|
||||
const isDocumentPendingEmailEnabled = extractDerivedDocumentEmailSettings(envelope.documentMeta).documentPending;
|
||||
|
||||
if (!isDocumentPendingEmailEnabled) {
|
||||
return;
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import { EnvelopeType, ReadStatus, SendStatus, WebhookTriggerEvents } from '@prisma/client';
|
||||
|
||||
import { DOCUMENT_AUDIT_LOG_TYPE } from '@documenso/lib/types/document-audit-logs';
|
||||
import type { RequestMetadata } from '@documenso/lib/universal/extract-request-metadata';
|
||||
import { createDocumentAuditLogData } from '@documenso/lib/utils/document-audit-logs';
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { EnvelopeType, ReadStatus, SendStatus, WebhookTriggerEvents } from '@prisma/client';
|
||||
|
||||
import type { TDocumentAccessAuthTypes } from '../../types/document-auth';
|
||||
import {
|
||||
ZWebhookDocumentSchema,
|
||||
mapEnvelopeToWebhookDocumentPayload,
|
||||
} from '../../types/webhook-payload';
|
||||
import { mapEnvelopeToWebhookDocumentPayload, ZWebhookDocumentSchema } from '../../types/webhook-payload';
|
||||
import { triggerWebhook } from '../webhooks/trigger/trigger-webhook';
|
||||
|
||||
export type ViewedDocumentOptions = {
|
||||
@@ -18,11 +14,7 @@ export type ViewedDocumentOptions = {
|
||||
requestMetadata?: RequestMetadata;
|
||||
};
|
||||
|
||||
export const viewedDocument = async ({
|
||||
token,
|
||||
recipientAccessAuth,
|
||||
requestMetadata,
|
||||
}: ViewedDocumentOptions) => {
|
||||
export const viewedDocument = async ({ token, recipientAccessAuth, requestMetadata }: ViewedDocumentOptions) => {
|
||||
const recipient = await prisma.recipient.findFirst({
|
||||
where: {
|
||||
token,
|
||||
|
||||
Reference in New Issue
Block a user