feat: audit logging for reminder emails

This commit is contained in:
Ephraim Atta-Duncan
2025-04-15 11:24:18 +00:00
parent 0ff304fca7
commit 6a3adbfd7e
3 changed files with 23 additions and 11 deletions

View File

@ -3,7 +3,6 @@ import { SEND_CONFIRMATION_EMAIL_JOB_DEFINITION } from './definitions/emails/sen
import { SEND_DAILY_REMINDER_EMAIL_JOB } from './definitions/emails/send-daily-reminder-email'; import { SEND_DAILY_REMINDER_EMAIL_JOB } from './definitions/emails/send-daily-reminder-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_HOURLY_REMINDER_EMAIL_JOB } from './definitions/emails/send-hourly-reminder-email'; import { SEND_HOURLY_REMINDER_EMAIL_JOB } from './definitions/emails/send-hourly-reminder-email';
import { SEND_MONTHLY_REMINDER_EMAIL_JOB } from './definitions/emails/send-monthly-reminder-email';
import { SEND_PASSWORD_RESET_SUCCESS_EMAIL_JOB_DEFINITION } from './definitions/emails/send-password-reset-success-email'; import { SEND_PASSWORD_RESET_SUCCESS_EMAIL_JOB_DEFINITION } from './definitions/emails/send-password-reset-success-email';
import { SEND_RECIPIENT_SIGNED_EMAIL_JOB_DEFINITION } from './definitions/emails/send-recipient-signed-email'; import { SEND_RECIPIENT_SIGNED_EMAIL_JOB_DEFINITION } from './definitions/emails/send-recipient-signed-email';
import { SEND_SIGNING_REJECTION_EMAILS_JOB_DEFINITION } from './definitions/emails/send-rejection-emails'; import { SEND_SIGNING_REJECTION_EMAILS_JOB_DEFINITION } from './definitions/emails/send-rejection-emails';
@ -11,7 +10,6 @@ import { SEND_SIGNING_EMAIL_JOB_DEFINITION } from './definitions/emails/send-sig
import { SEND_TEAM_DELETED_EMAIL_JOB_DEFINITION } from './definitions/emails/send-team-deleted-email'; import { SEND_TEAM_DELETED_EMAIL_JOB_DEFINITION } from './definitions/emails/send-team-deleted-email';
import { SEND_TEAM_MEMBER_JOINED_EMAIL_JOB_DEFINITION } from './definitions/emails/send-team-member-joined-email'; import { SEND_TEAM_MEMBER_JOINED_EMAIL_JOB_DEFINITION } from './definitions/emails/send-team-member-joined-email';
import { SEND_TEAM_MEMBER_LEFT_EMAIL_JOB_DEFINITION } from './definitions/emails/send-team-member-left-email'; import { SEND_TEAM_MEMBER_LEFT_EMAIL_JOB_DEFINITION } from './definitions/emails/send-team-member-left-email';
import { SEND_WEEKLY_REMINDER_EMAIL_JOB } from './definitions/emails/send-weekly-reminder-email';
import { BULK_SEND_TEMPLATE_JOB_DEFINITION } from './definitions/internal/bulk-send-template'; import { BULK_SEND_TEMPLATE_JOB_DEFINITION } from './definitions/internal/bulk-send-template';
import { SEAL_DOCUMENT_JOB_DEFINITION } from './definitions/internal/seal-document'; import { SEAL_DOCUMENT_JOB_DEFINITION } from './definitions/internal/seal-document';
@ -33,8 +31,6 @@ export const jobsClient = new JobClient([
BULK_SEND_TEMPLATE_JOB_DEFINITION, BULK_SEND_TEMPLATE_JOB_DEFINITION,
SEND_HOURLY_REMINDER_EMAIL_JOB, SEND_HOURLY_REMINDER_EMAIL_JOB,
SEND_DAILY_REMINDER_EMAIL_JOB, SEND_DAILY_REMINDER_EMAIL_JOB,
SEND_WEEKLY_REMINDER_EMAIL_JOB,
SEND_MONTHLY_REMINDER_EMAIL_JOB,
] as const); ] as const);
export const jobs = jobsClient; export const jobs = jobsClient;

View File

@ -12,13 +12,12 @@ 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 { FROM_ADDRESS, FROM_NAME } from '../../../constants/email'; import { FROM_ADDRESS, FROM_NAME } from '../../../constants/email';
import { RECIPIENT_ROLES_DESCRIPTION } from '../../../constants/recipient-roles'; import { RECIPIENT_ROLES_DESCRIPTION } from '../../../constants/recipient-roles';
import { DOCUMENT_AUDIT_LOG_TYPE, DOCUMENT_EMAIL_TYPE } from '../../../types/document-audit-logs';
import { extractDerivedDocumentEmailSettings } from '../../../types/document-email'; import { extractDerivedDocumentEmailSettings } from '../../../types/document-email';
import { renderEmailWithI18N } from '../../../utils/render-email-with-i18n'; import { renderEmailWithI18N } from '../../../utils/render-email-with-i18n';
import { shouldSendReminder } from '../../../utils/should-send-reminder'; import { shouldSendReminder } from '../../../utils/should-send-reminder';
import type { JobRunIO } from '../../client/_internal/job'; import type { JobRunIO } from '../../client/_internal/job';
// TODO: Add Audit Log import and usage
export type SendReminderHandlerOptions = { export type SendReminderHandlerOptions = {
io: JobRunIO; io: JobRunIO;
intervals: DocumentReminderInterval[]; intervals: DocumentReminderInterval[];
@ -150,17 +149,33 @@ export async function run({ io, intervals }: SendReminderHandlerOptions) {
text, text,
}); });
// Update recipient status (might be redundant if only tracking lastReminderSentAt on DocumentMeta)
await prisma.recipient.update({ await prisma.recipient.update({
where: { id: recipient.id }, where: { id: recipient.id },
data: { sendStatus: SendStatus.SENT }, data: { sendStatus: SendStatus.SENT },
}); });
}); });
// TODO: Duncan == Audit log await io.runTask(`log-reminder-${recipient.id}`, async () => {
// await io.runTask(`log-reminder-${recipient.id}`, async () => { await prisma.documentAuditLog.create({
// await prisma.documentAuditLog.create(...); data: {
// }); type: DOCUMENT_AUDIT_LOG_TYPE.EMAIL_SENT,
documentId: document.id,
userId: document.userId,
data: {
type: DOCUMENT_AUDIT_LOG_TYPE.EMAIL_SENT,
data: {
recipientEmail: recipient.email,
recipientName: recipient.name,
recipientId: recipient.id,
recipientRole: recipient.role,
emailType: DOCUMENT_EMAIL_TYPE.REMINDER,
isResending: false,
},
},
ipAddress: undefined,
},
});
});
} catch (error) { } catch (error) {
io.logger.error(`Error processing reminder for recipient ${recipient.id}`, error); io.logger.error(`Error processing reminder for recipient ${recipient.id}`, error);
} }

View File

@ -48,6 +48,7 @@ export const ZDocumentAuditLogEmailTypeSchema = z.enum([
'ASSISTING_REQUEST', 'ASSISTING_REQUEST',
'CC', 'CC',
'DOCUMENT_COMPLETED', 'DOCUMENT_COMPLETED',
'REMINDER',
]); ]);
export const ZDocumentMetaDiffTypeSchema = z.enum([ export const ZDocumentMetaDiffTypeSchema = z.enum([