mirror of
https://github.com/documenso/documenso.git
synced 2026-07-25 17:35:05 +10:00
fix: add email reporting (#2918)
This commit is contained in:
@@ -211,6 +211,8 @@ export const run = async ({ payload, io }: { payload: TSendDocumentCompletedEmai
|
||||
};
|
||||
|
||||
const downloadLink = `${NEXT_PUBLIC_WEBAPP_URL()}/sign/${recipient.token}/complete`;
|
||||
const reportUrl =
|
||||
recipient.role === RecipientRole.CC ? `${NEXT_PUBLIC_WEBAPP_URL()}/report/${recipient.token}` : undefined;
|
||||
|
||||
const template = createElement(DocumentCompletedEmailTemplate, {
|
||||
documentName: envelope.title,
|
||||
@@ -220,6 +222,7 @@ export const run = async ({ payload, io }: { payload: TSendDocumentCompletedEmai
|
||||
isDirectTemplate && envelope.documentMeta?.message
|
||||
? renderCustomEmailTemplate(envelope.documentMeta.message, customEmailTemplate)
|
||||
: undefined,
|
||||
reportUrl,
|
||||
});
|
||||
|
||||
const [html, text] = await Promise.all([
|
||||
|
||||
@@ -165,6 +165,7 @@ export const run = async ({ payload, io }: { payload: TSendSigningEmailJobDefini
|
||||
|
||||
const assetBaseUrl = NEXT_PUBLIC_WEBAPP_URL() || 'http://localhost:3000';
|
||||
const signDocumentLink = `${NEXT_PUBLIC_WEBAPP_URL()}/sign/${recipient.token}`;
|
||||
const reportUrl = `${NEXT_PUBLIC_WEBAPP_URL()}/report/${recipient.token}`;
|
||||
|
||||
const template = createElement(DocumentInviteEmailTemplate, {
|
||||
documentName: envelope.title,
|
||||
@@ -180,6 +181,7 @@ export const run = async ({ payload, io }: { payload: TSendSigningEmailJobDefini
|
||||
teamName: team?.name,
|
||||
teamEmail: team?.teamEmail?.email,
|
||||
includeSenderDetails: settings.includeSenderDetails,
|
||||
reportUrl,
|
||||
});
|
||||
|
||||
if (isRecipientEmailValidForSending(recipient)) {
|
||||
|
||||
@@ -154,6 +154,7 @@ export const run = async ({ payload, io }: { payload: TProcessSigningReminderJob
|
||||
|
||||
const assetBaseUrl = NEXT_PUBLIC_WEBAPP_URL() || 'http://localhost:3000';
|
||||
const signDocumentLink = `${NEXT_PUBLIC_WEBAPP_URL()}/sign/${recipient.token}`;
|
||||
const reportUrl = `${NEXT_PUBLIC_WEBAPP_URL()}/report/${recipient.token}`;
|
||||
|
||||
// Meter reminder emails against the organisation email quota/stats. Reminders
|
||||
// are unsolicited (the recipient didn't opt in to them) and can recur, so they
|
||||
@@ -188,6 +189,7 @@ export const run = async ({ payload, io }: { payload: TProcessSigningReminderJob
|
||||
signDocumentLink,
|
||||
customBody: emailMessage,
|
||||
role: recipient.role,
|
||||
reportUrl,
|
||||
});
|
||||
|
||||
const [html, text] = await Promise.all([
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { prisma } from '@documenso/prisma';
|
||||
import { EnvelopeType, type Prisma } from '@prisma/client';
|
||||
import { z } from 'zod';
|
||||
|
||||
import type { FindResultResponse } from '../../types/search-params';
|
||||
|
||||
@@ -9,6 +10,16 @@ export interface AdminFindDocumentsOptions {
|
||||
perPage?: number;
|
||||
}
|
||||
|
||||
const ZPositiveIntegerSchema = z.coerce.number().int().positive();
|
||||
|
||||
const emptyResponse = {
|
||||
data: [],
|
||||
count: 0,
|
||||
currentPage: 1,
|
||||
perPage: 10,
|
||||
totalPages: 0,
|
||||
};
|
||||
|
||||
export const adminFindDocuments = async ({ query, page = 1, perPage = 10 }: AdminFindDocumentsOptions) => {
|
||||
let termFilters: Prisma.EnvelopeWhereInput | undefined = !query
|
||||
? undefined
|
||||
@@ -19,7 +30,35 @@ export const adminFindDocuments = async ({ query, page = 1, perPage = 10 }: Admi
|
||||
},
|
||||
};
|
||||
|
||||
if (query && query.startsWith('envelope_')) {
|
||||
if (query?.startsWith('user:')) {
|
||||
const parsedUserId = ZPositiveIntegerSchema.safeParse(query.slice('user:'.length));
|
||||
|
||||
if (parsedUserId.success) {
|
||||
termFilters = {
|
||||
userId: {
|
||||
equals: parsedUserId.data,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
return emptyResponse;
|
||||
}
|
||||
}
|
||||
|
||||
if (query?.startsWith('team:')) {
|
||||
const parsedTeamId = ZPositiveIntegerSchema.safeParse(query.slice('team:'.length));
|
||||
|
||||
if (parsedTeamId.success) {
|
||||
termFilters = {
|
||||
teamId: {
|
||||
equals: parsedTeamId.data,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
return emptyResponse;
|
||||
}
|
||||
}
|
||||
|
||||
if (query && query?.startsWith('envelope_')) {
|
||||
termFilters = {
|
||||
id: {
|
||||
equals: query,
|
||||
@@ -27,7 +66,7 @@ export const adminFindDocuments = async ({ query, page = 1, perPage = 10 }: Admi
|
||||
};
|
||||
}
|
||||
|
||||
if (query && query.startsWith('document_')) {
|
||||
if (query && query?.startsWith('document_')) {
|
||||
termFilters = {
|
||||
secondaryId: {
|
||||
equals: query,
|
||||
|
||||
@@ -210,6 +210,7 @@ export const resendDocument = async ({ id, userId, recipients, teamId, requestMe
|
||||
|
||||
const assetBaseUrl = NEXT_PUBLIC_WEBAPP_URL() || 'http://localhost:3000';
|
||||
const signDocumentLink = `${NEXT_PUBLIC_WEBAPP_URL()}/sign/${recipient.token}`;
|
||||
const reportUrl = `${NEXT_PUBLIC_WEBAPP_URL()}/report/${recipient.token}`;
|
||||
|
||||
const template = createElement(DocumentInviteEmailTemplate, {
|
||||
documentName: envelope.title,
|
||||
@@ -225,6 +226,7 @@ export const resendDocument = async ({ id, userId, recipients, teamId, requestMe
|
||||
selfSigner,
|
||||
organisationType,
|
||||
teamName: envelope.team?.name,
|
||||
reportUrl,
|
||||
});
|
||||
|
||||
const [html, text] = await Promise.all([
|
||||
|
||||
@@ -66,6 +66,12 @@ export const linkOrgAccountRateLimit = createRateLimit({
|
||||
window: '1h',
|
||||
});
|
||||
|
||||
export const reportSenderRateLimit = createRateLimit({
|
||||
action: 'recipient.report-sender',
|
||||
max: 1,
|
||||
window: '7d',
|
||||
});
|
||||
|
||||
// ---- API (Tier 4 - Standard) ----
|
||||
|
||||
export const apiV1RateLimit = createRateLimit({
|
||||
|
||||
Reference in New Issue
Block a user