mirror of
https://github.com/documenso/documenso.git
synced 2026-07-27 02:15:05 +10:00
fix: move document complete email to a job (#2835)
This commit is contained in:
@@ -2,6 +2,7 @@ import { JobClient } from './client/client';
|
|||||||
import { SEND_ADMIN_USER_CREATED_EMAIL_JOB_DEFINITION } from './definitions/emails/send-admin-user-created-email';
|
import { SEND_ADMIN_USER_CREATED_EMAIL_JOB_DEFINITION } from './definitions/emails/send-admin-user-created-email';
|
||||||
import { SEND_CONFIRMATION_EMAIL_JOB_DEFINITION } from './definitions/emails/send-confirmation-email';
|
import { SEND_CONFIRMATION_EMAIL_JOB_DEFINITION } from './definitions/emails/send-confirmation-email';
|
||||||
import { SEND_DOCUMENT_CANCELLED_EMAILS_JOB_DEFINITION } from './definitions/emails/send-document-cancelled-emails';
|
import { SEND_DOCUMENT_CANCELLED_EMAILS_JOB_DEFINITION } from './definitions/emails/send-document-cancelled-emails';
|
||||||
|
import { SEND_DOCUMENT_COMPLETED_EMAILS_JOB_DEFINITION } from './definitions/emails/send-document-completed-emails';
|
||||||
import { SEND_DOCUMENT_CREATED_FROM_DIRECT_TEMPLATE_EMAIL_JOB_DEFINITION } from './definitions/emails/send-document-created-from-direct-template-email';
|
import { SEND_DOCUMENT_CREATED_FROM_DIRECT_TEMPLATE_EMAIL_JOB_DEFINITION } from './definitions/emails/send-document-created-from-direct-template-email';
|
||||||
import { SEND_ORGANISATION_MEMBER_JOINED_EMAIL_JOB_DEFINITION } from './definitions/emails/send-organisation-member-joined-email';
|
import { SEND_ORGANISATION_MEMBER_JOINED_EMAIL_JOB_DEFINITION } from './definitions/emails/send-organisation-member-joined-email';
|
||||||
import { SEND_ORGANISATION_MEMBER_LEFT_EMAIL_JOB_DEFINITION } from './definitions/emails/send-organisation-member-left-email';
|
import { SEND_ORGANISATION_MEMBER_LEFT_EMAIL_JOB_DEFINITION } from './definitions/emails/send-organisation-member-left-email';
|
||||||
@@ -41,6 +42,7 @@ export const jobsClient = new JobClient([
|
|||||||
SEND_PASSWORD_RESET_SUCCESS_EMAIL_JOB_DEFINITION,
|
SEND_PASSWORD_RESET_SUCCESS_EMAIL_JOB_DEFINITION,
|
||||||
SEND_SIGNING_REJECTION_EMAILS_JOB_DEFINITION,
|
SEND_SIGNING_REJECTION_EMAILS_JOB_DEFINITION,
|
||||||
SEND_RECIPIENT_SIGNED_EMAIL_JOB_DEFINITION,
|
SEND_RECIPIENT_SIGNED_EMAIL_JOB_DEFINITION,
|
||||||
|
SEND_DOCUMENT_COMPLETED_EMAILS_JOB_DEFINITION,
|
||||||
SEND_DOCUMENT_CANCELLED_EMAILS_JOB_DEFINITION,
|
SEND_DOCUMENT_CANCELLED_EMAILS_JOB_DEFINITION,
|
||||||
SEND_DOCUMENT_CREATED_FROM_DIRECT_TEMPLATE_EMAIL_JOB_DEFINITION,
|
SEND_DOCUMENT_CREATED_FROM_DIRECT_TEMPLATE_EMAIL_JOB_DEFINITION,
|
||||||
SEND_OWNER_RECIPIENT_EXPIRED_EMAIL_JOB_DEFINITION,
|
SEND_OWNER_RECIPIENT_EXPIRED_EMAIL_JOB_DEFINITION,
|
||||||
|
|||||||
+17
-20
@@ -5,29 +5,26 @@ import { msg } from '@lingui/core/macro';
|
|||||||
import { DocumentSource, EnvelopeType } from '@prisma/client';
|
import { DocumentSource, EnvelopeType } from '@prisma/client';
|
||||||
import { createElement } from 'react';
|
import { createElement } from 'react';
|
||||||
|
|
||||||
import { getI18nInstance } from '../../client-only/providers/i18n-server';
|
import { getI18nInstance } from '../../../client-only/providers/i18n-server';
|
||||||
import { NEXT_PUBLIC_WEBAPP_URL } from '../../constants/app';
|
import { NEXT_PUBLIC_WEBAPP_URL } from '../../../constants/app';
|
||||||
import { DOCUMENT_AUDIT_LOG_TYPE } from '../../types/document-audit-logs';
|
import { getEmailContext } from '../../../server-only/email/get-email-context';
|
||||||
import { extractDerivedDocumentEmailSettings } from '../../types/document-email';
|
import { DOCUMENT_AUDIT_LOG_TYPE } from '../../../types/document-audit-logs';
|
||||||
import type { RequestMetadata } from '../../universal/extract-request-metadata';
|
import { extractDerivedDocumentEmailSettings } from '../../../types/document-email';
|
||||||
import { getFileServerSide } from '../../universal/upload/get-file.server';
|
import { getFileServerSide } from '../../../universal/upload/get-file.server';
|
||||||
import { createDocumentAuditLogData } from '../../utils/document-audit-logs';
|
import { createDocumentAuditLogData } from '../../../utils/document-audit-logs';
|
||||||
import type { EnvelopeIdOptions } from '../../utils/envelope';
|
import { unsafeBuildEnvelopeIdQuery } from '../../../utils/envelope';
|
||||||
import { unsafeBuildEnvelopeIdQuery } from '../../utils/envelope';
|
import { isRecipientEmailValidForSending } from '../../../utils/recipients';
|
||||||
import { isRecipientEmailValidForSending } from '../../utils/recipients';
|
import { renderCustomEmailTemplate } from '../../../utils/render-custom-email-template';
|
||||||
import { renderCustomEmailTemplate } from '../../utils/render-custom-email-template';
|
import { renderEmailWithI18N } from '../../../utils/render-email-with-i18n';
|
||||||
import { renderEmailWithI18N } from '../../utils/render-email-with-i18n';
|
import { formatDocumentsPath } from '../../../utils/teams';
|
||||||
import { formatDocumentsPath } from '../../utils/teams';
|
import type { JobRunIO } from '../../client/_internal/job';
|
||||||
import { getEmailContext } from '../email/get-email-context';
|
import type { TSendDocumentCompletedEmailsJobDefinition } from './send-document-completed-emails';
|
||||||
|
|
||||||
export interface SendDocumentOptions {
|
export const run = async ({ payload, io }: { payload: TSendDocumentCompletedEmailsJobDefinition; io: JobRunIO }) => {
|
||||||
id: EnvelopeIdOptions;
|
const { envelopeId, requestMetadata } = payload;
|
||||||
requestMetadata?: RequestMetadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const sendCompletedEmail = async ({ id, requestMetadata }: SendDocumentOptions) => {
|
|
||||||
const envelope = await prisma.envelope.findUnique({
|
const envelope = await prisma.envelope.findUnique({
|
||||||
where: unsafeBuildEnvelopeIdQuery(id, EnvelopeType.DOCUMENT),
|
where: unsafeBuildEnvelopeIdQuery({ type: 'envelopeId', id: envelopeId }, EnvelopeType.DOCUMENT),
|
||||||
include: {
|
include: {
|
||||||
envelopeItems: {
|
envelopeItems: {
|
||||||
include: {
|
include: {
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
import { ZRequestMetadataSchema } from '../../../universal/extract-request-metadata';
|
||||||
|
import type { JobDefinition } from '../../client/_internal/job';
|
||||||
|
|
||||||
|
const SEND_DOCUMENT_COMPLETED_EMAILS_JOB_DEFINITION_ID = 'send.document.completed.emails';
|
||||||
|
|
||||||
|
const SEND_DOCUMENT_COMPLETED_EMAILS_JOB_DEFINITION_SCHEMA = z.object({
|
||||||
|
envelopeId: z.string(),
|
||||||
|
requestMetadata: ZRequestMetadataSchema.optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TSendDocumentCompletedEmailsJobDefinition = z.infer<
|
||||||
|
typeof SEND_DOCUMENT_COMPLETED_EMAILS_JOB_DEFINITION_SCHEMA
|
||||||
|
>;
|
||||||
|
|
||||||
|
export const SEND_DOCUMENT_COMPLETED_EMAILS_JOB_DEFINITION = {
|
||||||
|
id: SEND_DOCUMENT_COMPLETED_EMAILS_JOB_DEFINITION_ID,
|
||||||
|
name: 'Send Document Completed Emails',
|
||||||
|
version: '1.0.0',
|
||||||
|
trigger: {
|
||||||
|
name: SEND_DOCUMENT_COMPLETED_EMAILS_JOB_DEFINITION_ID,
|
||||||
|
schema: SEND_DOCUMENT_COMPLETED_EMAILS_JOB_DEFINITION_SCHEMA,
|
||||||
|
},
|
||||||
|
handler: async ({ payload, io }) => {
|
||||||
|
const handler = await import('./send-document-completed-emails.handler');
|
||||||
|
|
||||||
|
await handler.run({ payload, io });
|
||||||
|
},
|
||||||
|
} as const satisfies JobDefinition<
|
||||||
|
typeof SEND_DOCUMENT_COMPLETED_EMAILS_JOB_DEFINITION_ID,
|
||||||
|
TSendDocumentCompletedEmailsJobDefinition
|
||||||
|
>;
|
||||||
@@ -14,7 +14,6 @@ import { groupBy } from 'remeda';
|
|||||||
|
|
||||||
import { NEXT_PRIVATE_USE_PLAYWRIGHT_PDF } from '../../../constants/app';
|
import { NEXT_PRIVATE_USE_PLAYWRIGHT_PDF } from '../../../constants/app';
|
||||||
import { AppError, AppErrorCode } from '../../../errors/app-error';
|
import { AppError, AppErrorCode } from '../../../errors/app-error';
|
||||||
import { sendCompletedEmail } from '../../../server-only/document/send-completed-email';
|
|
||||||
import { getAuditLogsPdf } from '../../../server-only/htmltopdf/get-audit-logs-pdf';
|
import { getAuditLogsPdf } from '../../../server-only/htmltopdf/get-audit-logs-pdf';
|
||||||
import { getCertificatePdf } from '../../../server-only/htmltopdf/get-certificate-pdf';
|
import { getCertificatePdf } from '../../../server-only/htmltopdf/get-certificate-pdf';
|
||||||
import { insertFieldInPDFV1 } from '../../../server-only/pdf/insert-field-in-pdf-v1';
|
import { insertFieldInPDFV1 } from '../../../server-only/pdf/insert-field-in-pdf-v1';
|
||||||
@@ -31,6 +30,7 @@ import { fieldsContainUnsignedRequiredField } from '../../../utils/advanced-fiel
|
|||||||
import { isDocumentCompleted } from '../../../utils/document';
|
import { isDocumentCompleted } from '../../../utils/document';
|
||||||
import { createDocumentAuditLogData } from '../../../utils/document-audit-logs';
|
import { createDocumentAuditLogData } from '../../../utils/document-audit-logs';
|
||||||
import { mapDocumentIdToSecondaryId } from '../../../utils/envelope';
|
import { mapDocumentIdToSecondaryId } from '../../../utils/envelope';
|
||||||
|
import { jobs } from '../../client';
|
||||||
import type { JobRunIO } from '../../client/_internal/job';
|
import type { JobRunIO } from '../../client/_internal/job';
|
||||||
import type { TSealDocumentJobDefinition } from './seal-document';
|
import type { TSealDocumentJobDefinition } from './seal-document';
|
||||||
|
|
||||||
@@ -294,21 +294,6 @@ export const run = async ({ payload, io }: { payload: TSealDocumentJobDefinition
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
await io.runTask('send-completed-email', async () => {
|
|
||||||
let shouldSendCompletedEmail = sendEmail && !isResealing && !isRejected;
|
|
||||||
|
|
||||||
if (isResealing && !isDocumentCompleted(envelopeStatus)) {
|
|
||||||
shouldSendCompletedEmail = sendEmail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldSendCompletedEmail) {
|
|
||||||
await sendCompletedEmail({
|
|
||||||
id: { type: 'envelopeId', id: envelopeId },
|
|
||||||
requestMetadata,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const updatedEnvelope = await prisma.envelope.findFirstOrThrow({
|
const updatedEnvelope = await prisma.envelope.findFirstOrThrow({
|
||||||
where: {
|
where: {
|
||||||
id: envelopeId,
|
id: envelopeId,
|
||||||
@@ -325,6 +310,22 @@ export const run = async ({ payload, io }: { payload: TSealDocumentJobDefinition
|
|||||||
userId: updatedEnvelope.userId,
|
userId: updatedEnvelope.userId,
|
||||||
teamId: updatedEnvelope.teamId ?? undefined,
|
teamId: updatedEnvelope.teamId ?? undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let shouldSendCompletedEmail = sendEmail && !isResealing && !isRejected;
|
||||||
|
|
||||||
|
if (isResealing && !isDocumentCompleted(envelopeStatus)) {
|
||||||
|
shouldSendCompletedEmail = sendEmail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldSendCompletedEmail) {
|
||||||
|
await jobs.triggerJob({
|
||||||
|
name: 'send.document.completed.emails',
|
||||||
|
payload: {
|
||||||
|
envelopeId,
|
||||||
|
requestMetadata,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
type DecorateAndSignPdfOptions = {
|
type DecorateAndSignPdfOptions = {
|
||||||
|
|||||||
Reference in New Issue
Block a user