chore: Remove SendGrid related code from emailReminderManager (#23591)
* chore: Remove SendGrid related code from emailReminderManager * Small type fixes in consumers * Remove redundant userId/teamId from activateEventType.handler * Remove sendSengridMail as dep * Remove teamId param --------- Co-authored-by: Keith Williams <keithwillcode@gmail.com>
This commit is contained in:
1 parent
e02108d535
commit
6f05142447
7 files changed
+19
-208
No files matched your search
@@ -502,8 +502,6 @@ export async function handleWorkflowsUpdate({
|
||||
includeCalendarEvent: workflowStep.includeCalendarEvent,
|
||||
workflowStepId: workflowStep.id,
|
||||
verifiedAt: workflowStep.verifiedAt,
|
||||
userId: workflow.userId,
|
||||
teamId: workflow.teamId,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import generateIcsString from "@calcom/emails/lib/generateIcsString";
|
||||
import { FeaturesRepository } from "@calcom/features/flags/features.repository";
|
||||
import { preprocessNameFieldDataWithVariant } from "@calcom/features/form-builder/utils";
|
||||
import tasker from "@calcom/features/tasker";
|
||||
import { SENDER_NAME, WEBSITE_URL } from "@calcom/lib/constants";
|
||||
@@ -19,10 +18,8 @@ import {
|
||||
} from "@calcom/prisma/enums";
|
||||
import { bookingMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
import { IMMEDIATE_WORKFLOW_TRIGGER_EVENTS } from "../constants";
|
||||
import { getWorkflowRecipientEmail } from "../getWorkflowReminders";
|
||||
import { sendOrScheduleWorkflowEmails } from "./providers/emailProvider";
|
||||
import { getBatchId, sendSendgridMail } from "./providers/sendgridProvider";
|
||||
import type { AttendeeInBookingInfo, BookingInfo, timeUnitLowerCase } from "./smsReminderManager";
|
||||
import type { VariablesType } from "./templates/customTemplate";
|
||||
import customTemplate from "./templates/customTemplate";
|
||||
@@ -53,13 +50,10 @@ interface scheduleEmailReminderArgs extends ScheduleReminderArgs {
|
||||
evt: BookingInfo;
|
||||
sendTo: string[];
|
||||
action: ScheduleEmailReminderAction;
|
||||
userId?: number | null;
|
||||
teamId?: number | null;
|
||||
emailSubject?: string;
|
||||
emailBody?: string;
|
||||
hideBranding?: boolean;
|
||||
includeCalendarEvent?: boolean;
|
||||
isMandatoryReminder?: boolean;
|
||||
verifiedAt: Date | null;
|
||||
}
|
||||
|
||||
@@ -77,11 +71,8 @@ export const scheduleEmailReminder = async (args: scheduleEmailReminderArgs) =>
|
||||
emailBody = "",
|
||||
hideBranding,
|
||||
includeCalendarEvent,
|
||||
isMandatoryReminder,
|
||||
action,
|
||||
verifiedAt,
|
||||
userId,
|
||||
teamId,
|
||||
} = args;
|
||||
|
||||
if (!verifiedAt) {
|
||||
@@ -91,7 +82,6 @@ export const scheduleEmailReminder = async (args: scheduleEmailReminderArgs) =>
|
||||
|
||||
const { startTime, endTime } = evt;
|
||||
const uid = evt.uid as string;
|
||||
const currentDate = dayjs();
|
||||
const timeUnit: timeUnitLowerCase | undefined = timeSpan.timeUnit?.toLocaleLowerCase() as timeUnitLowerCase;
|
||||
|
||||
let scheduledDate = null;
|
||||
@@ -286,130 +276,26 @@ export const scheduleEmailReminder = async (args: scheduleEmailReminderArgs) =>
|
||||
|
||||
const mailData = await prepareEmailData();
|
||||
|
||||
const isSendgridEnabled = !!(process.env.SENDGRID_API_KEY && process.env.SENDGRID_EMAIL);
|
||||
|
||||
const featureRepo = new FeaturesRepository(prisma);
|
||||
|
||||
const isWorkflowSmtpEmailsEnabled = teamId
|
||||
? await featureRepo.checkIfTeamHasFeature(teamId, "workflow-smtp-emails")
|
||||
: userId
|
||||
? await featureRepo.checkIfUserHasFeature(userId, "workflow-smtp-emails")
|
||||
: false;
|
||||
|
||||
if (isWorkflowSmtpEmailsEnabled || !isSendgridEnabled) {
|
||||
let reminderUid;
|
||||
if (scheduledDate) {
|
||||
const reminder = await prisma.workflowReminder.create({
|
||||
data: {
|
||||
bookingUid: uid,
|
||||
workflowStepId,
|
||||
method: WorkflowMethods.EMAIL,
|
||||
scheduledDate: scheduledDate.toDate(),
|
||||
scheduled: true,
|
||||
},
|
||||
});
|
||||
reminderUid = reminder.uuid;
|
||||
}
|
||||
|
||||
await sendOrScheduleWorkflowEmails({
|
||||
...mailData,
|
||||
to: sendTo,
|
||||
sendAt: scheduledDate?.toDate(),
|
||||
referenceUid: reminderUid ?? undefined,
|
||||
let reminderUid = undefined;
|
||||
if (scheduledDate) {
|
||||
const reminder = await prisma.workflowReminder.create({
|
||||
data: {
|
||||
bookingUid: uid,
|
||||
workflowStepId,
|
||||
method: WorkflowMethods.EMAIL,
|
||||
scheduledDate: scheduledDate.toDate(),
|
||||
scheduled: true,
|
||||
},
|
||||
});
|
||||
|
||||
return;
|
||||
reminderUid = reminder.uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated only needed for SendGrid, use SMTP with tasker instead
|
||||
*/
|
||||
if (IMMEDIATE_WORKFLOW_TRIGGER_EVENTS.includes(triggerEvent)) {
|
||||
try {
|
||||
const promises = sendTo.map((email) => sendSendgridMail({ ...mailData, to: email }));
|
||||
// TODO: Maybe don't await for this?
|
||||
await Promise.all(promises);
|
||||
} catch (error) {
|
||||
log.error("Error sending Email");
|
||||
}
|
||||
} else if (
|
||||
(triggerEvent === WorkflowTriggerEvents.BEFORE_EVENT ||
|
||||
triggerEvent === WorkflowTriggerEvents.AFTER_EVENT) &&
|
||||
scheduledDate
|
||||
) {
|
||||
// Sendgrid to schedule emails
|
||||
// Can only schedule at least 60 minutes and at most 72 hours in advance
|
||||
// To limit the amount of canceled sends we schedule at most 2 hours in advance
|
||||
if (
|
||||
currentDate.isBefore(scheduledDate.subtract(1, "hour")) &&
|
||||
!scheduledDate.isAfter(currentDate.add(2, "hour"))
|
||||
) {
|
||||
try {
|
||||
const sendgridBatchId = await getBatchId();
|
||||
|
||||
// If sendEmail failed then workflowReminer will not be created, failing E2E tests
|
||||
await sendSendgridMail({
|
||||
...mailData,
|
||||
to: sendTo,
|
||||
sendAt: scheduledDate.unix(),
|
||||
batchId: sendgridBatchId,
|
||||
});
|
||||
|
||||
if (!isMandatoryReminder) {
|
||||
await prisma.workflowReminder.create({
|
||||
data: {
|
||||
bookingUid: uid,
|
||||
workflowStepId: workflowStepId,
|
||||
method: WorkflowMethods.EMAIL,
|
||||
scheduledDate: scheduledDate.toDate(),
|
||||
scheduled: true,
|
||||
referenceId: sendgridBatchId,
|
||||
seatReferenceId: seatReferenceUid,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await prisma.workflowReminder.create({
|
||||
data: {
|
||||
bookingUid: uid,
|
||||
method: WorkflowMethods.EMAIL,
|
||||
scheduledDate: scheduledDate.toDate(),
|
||||
scheduled: true,
|
||||
referenceId: sendgridBatchId,
|
||||
seatReferenceId: seatReferenceUid,
|
||||
isMandatoryReminder: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
log.error(`Error scheduling email with error ${error}`);
|
||||
}
|
||||
} else if (scheduledDate.isAfter(currentDate.add(2, "hour"))) {
|
||||
// Write to DB and send to CRON if scheduled reminder date is past 2 hours
|
||||
if (!isMandatoryReminder) {
|
||||
await prisma.workflowReminder.create({
|
||||
data: {
|
||||
bookingUid: uid,
|
||||
workflowStepId: workflowStepId,
|
||||
method: WorkflowMethods.EMAIL,
|
||||
scheduledDate: scheduledDate.toDate(),
|
||||
scheduled: false,
|
||||
seatReferenceId: seatReferenceUid,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await prisma.workflowReminder.create({
|
||||
data: {
|
||||
bookingUid: uid,
|
||||
method: WorkflowMethods.EMAIL,
|
||||
scheduledDate: scheduledDate.toDate(),
|
||||
scheduled: false,
|
||||
seatReferenceId: seatReferenceUid,
|
||||
isMandatoryReminder: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
await sendOrScheduleWorkflowEmails({
|
||||
...mailData,
|
||||
to: sendTo,
|
||||
sendAt: scheduledDate?.toDate(),
|
||||
referenceUid: reminderUid ?? undefined,
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteScheduledEmailReminder = async (reminderId: number) => {
|
||||
|
||||
@@ -156,8 +156,6 @@ const processWorkflowStep = async (
|
||||
seatReferenceUid,
|
||||
includeCalendarEvent: step.includeCalendarEvent,
|
||||
verifiedAt: step.verifiedAt,
|
||||
userId: workflow.userId,
|
||||
teamId: workflow.teamId,
|
||||
});
|
||||
} else if (isWhatsappAction(step.action)) {
|
||||
const sendTo = step.action === WorkflowActions.WHATSAPP_ATTENDEE ? smsReminderNumber : step.sendTo;
|
||||
|
||||
@@ -63,10 +63,8 @@ async function _scheduleMandatoryReminder({
|
||||
hideBranding,
|
||||
seatReferenceUid,
|
||||
includeCalendarEvent: false,
|
||||
isMandatoryReminder: true,
|
||||
// Template is fixed so we don't have to verify
|
||||
verifiedAt: new Date(),
|
||||
userId: evt.organizer.id,
|
||||
});
|
||||
} catch (error) {
|
||||
log.error("Error while scheduling mandatory reminders", JSON.stringify({ error }));
|
||||
|
||||
@@ -36,7 +36,6 @@ import { FeaturesRepository } from "../../../../flags/features.repository";
|
||||
import { deleteWorkfowRemindersOfRemovedMember } from "../../../teams/lib/deleteWorkflowRemindersOfRemovedMember";
|
||||
import { scheduleEmailReminder } from "../reminders/emailReminderManager";
|
||||
import * as emailProvider from "../reminders/providers/emailProvider";
|
||||
import * as sendgridProvider from "../reminders/providers/sendgridProvider";
|
||||
|
||||
const workflowSelect = {
|
||||
id: true,
|
||||
@@ -709,7 +708,6 @@ describe("scheduleBookingReminders", () => {
|
||||
},
|
||||
});
|
||||
|
||||
const allVerified = await prismock.verifiedNumber.findMany();
|
||||
await scheduleBookingReminders(
|
||||
bookings,
|
||||
workflow.steps,
|
||||
@@ -1061,7 +1059,6 @@ describe("deleteWorkfowRemindersOfRemovedMember", () => {
|
||||
});
|
||||
|
||||
describe("Workflow SMTP Emails Feature Flag", () => {
|
||||
vi.spyOn(sendgridProvider, "sendSendgridMail");
|
||||
vi.spyOn(emailProvider, "sendOrScheduleWorkflowEmails");
|
||||
|
||||
const mockEvt = {
|
||||
@@ -1097,72 +1094,10 @@ describe("Workflow SMTP Emails Feature Flag", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
// Mock SendGrid environment variables
|
||||
process.env.SENDGRID_API_KEY = "test-key";
|
||||
process.env.SENDGRID_EMAIL = "test@example.com";
|
||||
});
|
||||
|
||||
test("should use SMTP when team has workflow-smtp-emails feature", async () => {
|
||||
vi.spyOn(FeaturesRepository.prototype, "checkIfTeamHasFeature").mockResolvedValue(true);
|
||||
|
||||
await scheduleEmailReminder({
|
||||
...baseArgs,
|
||||
teamId: 123,
|
||||
});
|
||||
expect(sendgridProvider.sendSendgridMail).not.toHaveBeenCalled();
|
||||
expect(emailProvider.sendOrScheduleWorkflowEmails).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("should use SMTP when user has workflow-smtp-emails feature", async () => {
|
||||
vi.spyOn(FeaturesRepository.prototype, "checkIfUserHasFeature").mockResolvedValue(true);
|
||||
|
||||
await scheduleEmailReminder({
|
||||
...baseArgs,
|
||||
userId: 123,
|
||||
});
|
||||
expect(sendgridProvider.sendSendgridMail).not.toHaveBeenCalled();
|
||||
expect(emailProvider.sendOrScheduleWorkflowEmails).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("should use SendGrid when workflow-smtp-emails feature is not enabled for team", async () => {
|
||||
vi.spyOn(FeaturesRepository.prototype, "checkIfTeamHasFeature").mockResolvedValue(false);
|
||||
|
||||
await scheduleEmailReminder({
|
||||
...baseArgs,
|
||||
teamId: 123,
|
||||
});
|
||||
|
||||
expect(sendgridProvider.sendSendgridMail).toHaveBeenCalled();
|
||||
expect(emailProvider.sendOrScheduleWorkflowEmails).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("should use SendGrid when workflow-smtp-emails feature is not enabled for user", async () => {
|
||||
vi.spyOn(FeaturesRepository.prototype, "checkIfUserHasFeature").mockResolvedValue(false);
|
||||
|
||||
await scheduleEmailReminder({
|
||||
...baseArgs,
|
||||
userId: 123,
|
||||
});
|
||||
|
||||
expect(sendgridProvider.sendSendgridMail).toHaveBeenCalled();
|
||||
expect(emailProvider.sendOrScheduleWorkflowEmails).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test("should use SMTP when SendGrid is not configured", async () => {
|
||||
vi.spyOn(FeaturesRepository.prototype, "checkIfTeamHasFeature").mockResolvedValue(false);
|
||||
|
||||
vi.spyOn(FeaturesRepository.prototype, "checkIfUserHasFeature").mockResolvedValue(false);
|
||||
|
||||
delete process.env.SENDGRID_API_KEY;
|
||||
delete process.env.SENDGRID_EMAIL;
|
||||
|
||||
await scheduleEmailReminder({
|
||||
...baseArgs,
|
||||
teamId: 123,
|
||||
userId: 456,
|
||||
});
|
||||
|
||||
expect(sendgridProvider.sendSendgridMail).not.toHaveBeenCalled();
|
||||
test("should use SMTP", async () => {
|
||||
await scheduleEmailReminder(baseArgs);
|
||||
expect(emailProvider.sendOrScheduleWorkflowEmails).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -388,8 +388,6 @@ export const activateEventTypeHandler = async ({ ctx, input }: ActivateEventType
|
||||
sender: step.sender,
|
||||
workflowStepId: step.id,
|
||||
verifiedAt: step.verifiedAt,
|
||||
userId: eventTypeWorkflow.userId,
|
||||
teamId: eventTypeWorkflow.teamId,
|
||||
});
|
||||
} else if (step.action === WorkflowActions.SMS_NUMBER && step.sendTo) {
|
||||
await scheduleSMSReminder({
|
||||
|
||||
@@ -794,8 +794,6 @@ export async function scheduleBookingReminders(
|
||||
sender: step.sender,
|
||||
workflowStepId: step.id,
|
||||
verifiedAt: step?.verifiedAt ?? null,
|
||||
userId,
|
||||
teamId,
|
||||
});
|
||||
} else if (step.action === WorkflowActions.SMS_NUMBER && step.sendTo) {
|
||||
await scheduleSMSReminder({
|
||||
|
||||
Reference in new issue
Block a user