chore: Move getRemindersFromRemovedTeams and deleteAllWorkflowReminders to workflow repo (#16861)

* wip

* move deleteAllWorkflowReminders to repo
This commit is contained in:
sean-brydon authored and GitHub committed 2024-09-27 10:42:09 -04:00
1 parent 4d9777af8b
commit 20729b3a4e
10 files changed
+148 -161

No files matched your search

@@ -21,6 +21,7 @@ import { HttpError } from "@calcom/lib/http-error";
import logger from "@calcom/lib/logger";
import { safeStringify } from "@calcom/lib/safeStringify";
import { getTranslation } from "@calcom/lib/server/i18n";
import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat";
import prisma, { bookingMinimalSelect } from "@calcom/prisma";
import type { WebhookTriggerEvents } from "@calcom/prisma/enums";
@@ -32,10 +33,7 @@ import {
schemaBookingCancelParams,
} from "@calcom/prisma/zod-utils";
import type { EventTypeMetadata } from "@calcom/prisma/zod-utils";
import {
deleteAllWorkflowReminders,
getAllWorkflowsFromEventType,
} from "@calcom/trpc/server/routers/viewer/workflows/util";
import { getAllWorkflowsFromEventType } from "@calcom/trpc/server/routers/viewer/workflows/util";
import type { CalendarEvent } from "@calcom/types/Calendar";
import { getAllCredentials } from "./getAllCredentialsForUsersOnEvent/getAllCredentials";
@@ -520,7 +518,7 @@ async function handler(req: CustomRequest) {
webhookTriggerPromises.push(deleteWebhookScheduledTriggers({ booking }));
//Workflows - cancel all reminders for cancelled bookings
workflowReminderPromises.push(deleteAllWorkflowReminders(booking.workflowReminders));
workflowReminderPromises.push(WorkflowRepository.deleteAllWorkflowReminders(booking.workflowReminders));
}
await Promise.all([...webhookTriggerPromises, ...workflowReminderPromises]).catch((error) => {
@@ -62,6 +62,7 @@ import { getPiiFreeCalendarEvent, getPiiFreeEventType, getPiiFreeUser } from "@c
import { safeStringify } from "@calcom/lib/safeStringify";
import { checkBookingLimits, checkDurationLimits, getLuckyUser } from "@calcom/lib/server";
import { getTranslation } from "@calcom/lib/server/i18n";
import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
import { slugify } from "@calcom/lib/slugify";
import { updateWebUser as syncServicesUpdateWebUser } from "@calcom/lib/sync/SyncServiceManager";
import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat";
@@ -71,10 +72,7 @@ import { BookingStatus, SchedulingType, WebhookTriggerEvents } from "@calcom/pri
import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";
import type { bookingCreateSchemaLegacyPropsForApi } from "@calcom/prisma/zod-utils";
import { userMetadata as userMetadataSchema } from "@calcom/prisma/zod-utils";
import {
deleteAllWorkflowReminders,
getAllWorkflowsFromEventType,
} from "@calcom/trpc/server/routers/viewer/workflows/util";
import { getAllWorkflowsFromEventType } from "@calcom/trpc/server/routers/viewer/workflows/util";
import type {
AdditionalInformation,
AppsStatus,
@@ -1173,7 +1171,7 @@ async function handler(
if (!eventType.seatsPerTimeSlot && originalRescheduledBooking?.uid) {
log.silly("Rescheduling booking", originalRescheduledBooking.uid);
// cancel workflow reminders from previous rescheduled booking
await deleteAllWorkflowReminders(originalRescheduledBooking.workflowReminders);
await WorkflowRepository.deleteAllWorkflowReminders(originalRescheduledBooking.workflowReminders);
evt = addVideoCallDataToEvent(originalRescheduledBooking.references, evt);
@@ -7,12 +7,12 @@ import { HttpError } from "@calcom/lib/http-error";
import logger from "@calcom/lib/logger";
import { safeStringify } from "@calcom/lib/safeStringify";
import { getTranslation } from "@calcom/lib/server/i18n";
import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
import prisma from "@calcom/prisma";
import { WebhookTriggerEvents } from "@calcom/prisma/enums";
import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";
import { schemaBookingCancelParams } from "@calcom/prisma/zod-utils";
import type { EventTypeMetadata } from "@calcom/prisma/zod-utils";
import { deleteAllWorkflowReminders } from "@calcom/trpc/server/routers/viewer/workflows/util";
import type { CalendarEvent } from "@calcom/types/Calendar";
import type { CustomRequest } from "../../handleCancelBooking";
@@ -156,7 +156,7 @@ async function cancelAttendeeSeat(
bookingToDelete?.workflowReminders.filter((reminder) => reminder.seatReferenceId === seatReferenceUid) ??
null;
await deleteAllWorkflowReminders(workflowRemindersForAttendee);
await WorkflowRepository.deleteAllWorkflowReminders(workflowRemindersForAttendee);
return { success: true };
}
@@ -1,5 +1,5 @@
import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
import prisma from "@calcom/prisma";
import { deleteAllWorkflowReminders } from "@calcom/trpc/server/routers/viewer/workflows/util";
// cancel/delete all workflowReminders of the removed member that come from that team (org teams only)
export async function deleteWorkfowRemindersOfRemovedMember(
@@ -31,8 +31,7 @@ export async function deleteWorkfowRemindersOfRemovedMember(
method: true,
},
});
deleteAllWorkflowReminders(workflowRemindersToDelete);
await WorkflowRepository.deleteAllWorkflowReminders(workflowRemindersToDelete);
} else {
if (!team.parentId) return;
@@ -90,6 +89,6 @@ export async function deleteWorkfowRemindersOfRemovedMember(
method: true,
},
});
deleteAllWorkflowReminders(workflowRemindersToDelete);
await WorkflowRepository.deleteAllWorkflowReminders(workflowRemindersToDelete);
}
}
+119
View File
@@ -1,14 +1,21 @@
import { z } from "zod";
import type { WorkflowType } from "@calcom/ee/workflows/components/WorkflowListPage";
import { deleteScheduledEmailReminder } from "@calcom/ee/workflows/lib/reminders/emailReminderManager";
import { deleteScheduledSMSReminder } from "@calcom/ee/workflows/lib/reminders/smsReminderManager";
import { deleteScheduledWhatsappReminder } from "@calcom/ee/workflows/lib/reminders/whatsappReminderManager";
import type { WorkflowStep } from "@calcom/ee/workflows/lib/types";
import { hasFilter } from "@calcom/features/filters/lib/hasFilter";
import prisma from "@calcom/prisma";
import { MembershipRole } from "@calcom/prisma/client";
import { Prisma } from "@calcom/prisma/client";
import { WorkflowMethods } from "@calcom/prisma/enums";
import type { TFilteredListInputSchema } from "@calcom/trpc/server/routers/viewer/workflows/filteredList.schema";
import type { TGetVerifiedEmailsInputSchema } from "@calcom/trpc/server/routers/viewer/workflows/getVerifiedEmails.schema";
import type { TGetVerifiedNumbersInputSchema } from "@calcom/trpc/server/routers/viewer/workflows/getVerifiedNumbers.schema";
import logger from "../../logger";
export const ZGetInputSchema = z.object({
id: z.number(),
});
@@ -58,6 +65,8 @@ const { include: includedFields } = Prisma.validator<Prisma.WorkflowDefaultArgs>
});
export class WorkflowRepository {
private static log = logger.getSubLogger({ prefix: ["workflow"] });
static async getById({ id }: TGetInputSchema) {
return await prisma.workflow.findFirst({
where: {
@@ -276,4 +285,114 @@ export class WorkflowRepository {
};
}
}
static async getRemindersFromRemovedTeams(
removedTeams: number[],
workflowSteps: WorkflowStep[],
activeOn?: number[]
) {
const remindersToDeletePromise: Prisma.PrismaPromise<
{
id: number;
referenceId: string | null;
method: string;
}[]
>[] = [];
removedTeams.forEach((teamId) => {
const reminderToDelete = prisma.workflowReminder.findMany({
where: {
OR: [
{
//team event types + children managed event types
booking: {
eventType: {
OR: [{ teamId }, { teamId: null, parent: { teamId } }],
},
},
},
{
// user bookings
booking: {
user: {
AND: [
// user is part of team that got removed
{
teams: {
some: {
teamId: teamId,
},
},
},
// and user is not part of any team were the workflow is still active on
{
teams: {
none: {
teamId: {
in: activeOn,
},
},
},
},
],
},
eventType: {
teamId: null,
parentId: null, // children managed event types are handled above with team event types
},
},
},
],
workflowStepId: {
in: workflowSteps.map((step) => {
return step.id;
}),
},
},
select: {
id: true,
referenceId: true,
method: true,
},
});
remindersToDeletePromise.push(reminderToDelete);
});
const remindersToDelete = (await Promise.all(remindersToDeletePromise)).flat();
return remindersToDelete;
}
static async deleteAllWorkflowReminders(
remindersToDelete:
| {
id: number;
referenceId: string | null;
method: string;
}[]
| null
) {
const reminderMethods: {
[x: string]: (id: number, referenceId: string | null) => void;
} = {
[WorkflowMethods.EMAIL]: (id, referenceId) => deleteScheduledEmailReminder(id, referenceId),
[WorkflowMethods.SMS]: (id, referenceId) => deleteScheduledSMSReminder(id, referenceId),
[WorkflowMethods.WHATSAPP]: (id, referenceId) => deleteScheduledWhatsappReminder(id, referenceId),
};
if (!remindersToDelete) return Promise.resolve();
const results = await Promise.allSettled(
remindersToDelete.map((reminder) => {
return reminderMethods[reminder.method](reminder.id, reminder.referenceId);
})
);
results.forEach((result, index) => {
if (result.status !== "fulfilled") {
this.log.error(
`An error occurred when deleting reminder ${remindersToDelete[index].id}, method: ${remindersToDelete[index].method}`,
result.reason
);
}
});
}
}
@@ -19,6 +19,7 @@ import logger from "@calcom/lib/logger";
import { safeStringify } from "@calcom/lib/safeStringify";
import { getTranslation } from "@calcom/lib/server";
import { getUsersCredentials } from "@calcom/lib/server/getUsersCredentials";
import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
import { prisma } from "@calcom/prisma";
import type { WebhookTriggerEvents } from "@calcom/prisma/enums";
import { BookingStatus } from "@calcom/prisma/enums";
@@ -28,7 +29,6 @@ import type { CalendarEvent, Person } from "@calcom/types/Calendar";
import { TRPCError } from "@trpc/server";
import type { TrpcSessionUser } from "../../../trpc";
import { deleteAllWorkflowReminders } from "../workflows/util";
import type { TRequestRescheduleInputSchema } from "./requestReschedule.schema";
import type { PersonAttendeeCommonFields } from "./types";
@@ -159,7 +159,7 @@ export const requestRescheduleHandler = async ({ ctx, input }: RequestReschedule
});
//cancel workflow reminders of previous booking
await deleteAllWorkflowReminders(bookingToReschedule.workflowReminders);
await WorkflowRepository.deleteAllWorkflowReminders(bookingToReschedule.workflowReminders);
const [mainAttendee] = bookingToReschedule.attendees;
// @NOTE: Should we assume attendees language?
@@ -1,6 +1,7 @@
import { scheduleEmailReminder } from "@calcom/features/ee/workflows/lib/reminders/emailReminderManager";
import { scheduleSMSReminder } from "@calcom/features/ee/workflows/lib/reminders/smsReminderManager";
import { scheduleWhatsappReminder } from "@calcom/features/ee/workflows/lib/reminders/whatsappReminderManager";
import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat";
import { prisma } from "@calcom/prisma";
import { BookingStatus } from "@calcom/prisma/client";
@@ -11,11 +12,7 @@ import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
import { TRPCError } from "@trpc/server";
import type { TActivateEventTypeInputSchema } from "./activateEventType.schema";
import {
deleteAllWorkflowReminders,
removeSmsReminderFieldForEventTypes,
upsertSmsReminderFieldForEventTypes,
} from "./util";
import { removeSmsReminderFieldForEventTypes, upsertSmsReminderFieldForEventTypes } from "./util";
type ActivateEventTypeOptions = {
ctx: {
@@ -120,7 +117,7 @@ export const activateEventTypeHandler = async ({ ctx, input }: ActivateEventType
},
});
await deleteAllWorkflowReminders(remindersToDelete);
await WorkflowRepository.deleteAllWorkflowReminders(remindersToDelete);
await prisma.workflowsOnEventTypes.deleteMany({
where: {
@@ -1,10 +1,11 @@
import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
import { prisma } from "@calcom/prisma";
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
import { TRPCError } from "@trpc/server";
import type { TDeleteInputSchema } from "./delete.schema";
import { deleteAllWorkflowReminders, isAuthorized, removeSmsReminderFieldForEventTypes } from "./util";
import { isAuthorized, removeSmsReminderFieldForEventTypes } from "./util";
type DeleteOptions = {
ctx: {
@@ -50,7 +51,7 @@ export const deleteHandler = async ({ ctx, input }: DeleteOptions) => {
});
//cancel workflow reminders of deleted workflow
await deleteAllWorkflowReminders(scheduledReminders);
await WorkflowRepository.deleteAllWorkflowReminders(scheduledReminders);
const isOrg = workflowToDelete.team?.isOrganization ?? false;
@@ -1,6 +1,7 @@
import { isSMSOrWhatsappAction } from "@calcom/features/ee/workflows/lib/actionHelperFunctions";
import { IS_SELF_HOSTED } from "@calcom/lib/constants";
import hasKeyInMetadata from "@calcom/lib/hasKeyInMetadata";
import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
import type { PrismaClient } from "@calcom/prisma";
import { WorkflowActions } from "@calcom/prisma/enums";
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
@@ -15,7 +16,6 @@ import {
upsertSmsReminderFieldForEventTypes,
deleteRemindersOfActiveOnIds,
isAuthorizedToAddActiveOnIds,
deleteAllWorkflowReminders,
scheduleWorkflowNotifications,
verifyEmailSender,
removeSmsReminderFieldForEventTypes,
@@ -324,7 +324,7 @@ export const updateHandler = async ({ ctx, input }: UpdateOptions) => {
//step was deleted
if (!newStep) {
// cancel all workflow reminders from deleted steps
await deleteAllWorkflowReminders(remindersFromStep);
await WorkflowRepository.deleteAllWorkflowReminders(remindersFromStep);
await ctx.prisma.workflowStep.delete({
where: {
@@ -367,7 +367,7 @@ export const updateHandler = async ({ ctx, input }: UpdateOptions) => {
});
// cancel all notifications of edited step
await deleteAllWorkflowReminders(remindersFromStep);
await WorkflowRepository.deleteAllWorkflowReminders(remindersFromStep);
// schedule notifications for edited steps
await scheduleWorkflowNotifications(
@@ -3,18 +3,9 @@ import type { z } from "zod";
import { isSMSOrWhatsappAction } from "@calcom/ee/workflows/lib/actionHelperFunctions";
import { getAllWorkflows } from "@calcom/ee/workflows/lib/getAllWorkflows";
import {
deleteScheduledEmailReminder,
scheduleEmailReminder,
} from "@calcom/ee/workflows/lib/reminders/emailReminderManager";
import {
deleteScheduledSMSReminder,
scheduleSMSReminder,
} from "@calcom/ee/workflows/lib/reminders/smsReminderManager";
import {
deleteScheduledWhatsappReminder,
scheduleWhatsappReminder,
} from "@calcom/ee/workflows/lib/reminders/whatsappReminderManager";
import { scheduleEmailReminder } from "@calcom/ee/workflows/lib/reminders/emailReminderManager";
import { scheduleSMSReminder } from "@calcom/ee/workflows/lib/reminders/smsReminderManager";
import { scheduleWhatsappReminder } from "@calcom/ee/workflows/lib/reminders/whatsappReminderManager";
import type { Workflow as WorkflowType } from "@calcom/ee/workflows/lib/types";
import { SMS_REMINDER_NUMBER_FIELD } from "@calcom/features/bookings/lib/SystemField";
import {
@@ -27,18 +18,13 @@ import getOrgIdFromMemberOrTeamId from "@calcom/lib/getOrgIdFromMemberOrTeamId";
import { getTeamIdFromEventType } from "@calcom/lib/getTeamIdFromEventType";
import logger from "@calcom/lib/logger";
import { EventTypeRepository } from "@calcom/lib/server/repository/eventType";
import { WorkflowRepository } from "@calcom/lib/server/repository/workflow";
import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat";
import prisma from "@calcom/prisma";
import type { Prisma, WorkflowStep } from "@calcom/prisma/client";
import type { TimeUnit } from "@calcom/prisma/enums";
import { SchedulingType } from "@calcom/prisma/enums";
import {
BookingStatus,
MembershipRole,
WorkflowActions,
WorkflowMethods,
WorkflowTriggerEvents,
} from "@calcom/prisma/enums";
import { BookingStatus, MembershipRole, WorkflowActions, WorkflowTriggerEvents } from "@calcom/prisma/enums";
import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
import { TRPCError } from "@trpc/server";
@@ -424,41 +410,6 @@ export async function isAuthorizedToAddActiveOnIds(
return true;
}
const reminderMethods: {
[x: string]: (id: number, referenceId: string | null) => void;
} = {
[WorkflowMethods.EMAIL]: (id, referenceId) => deleteScheduledEmailReminder(id, referenceId),
[WorkflowMethods.SMS]: (id, referenceId) => deleteScheduledSMSReminder(id, referenceId),
[WorkflowMethods.WHATSAPP]: (id, referenceId) => deleteScheduledWhatsappReminder(id, referenceId),
};
export async function deleteAllWorkflowReminders(
remindersToDelete:
| {
id: number;
referenceId: string | null;
method: string;
}[]
| null
) {
if (!remindersToDelete) return Promise.resolve();
const results = await Promise.allSettled(
remindersToDelete.map((reminder) => {
return reminderMethods[reminder.method](reminder.id, reminder.referenceId);
})
);
results.forEach((result, index) => {
if (result.status !== "fulfilled") {
log.error(
`An error occurred when deleting reminder ${remindersToDelete[index].id}, method: ${remindersToDelete[index].method}`,
result.reason
);
}
});
}
export async function deleteRemindersOfActiveOnIds({
removedActiveOnIds,
workflowSteps,
@@ -472,84 +423,8 @@ export async function deleteRemindersOfActiveOnIds({
}) {
const remindersToDelete = !isOrg
? await getRemindersFromRemovedEventTypes(removedActiveOnIds, workflowSteps)
: await getRemindersFromRemovedTeams(removedActiveOnIds, workflowSteps, activeOnIds);
await deleteAllWorkflowReminders(remindersToDelete);
}
async function getRemindersFromRemovedTeams(
removedTeams: number[],
workflowSteps: WorkflowStep[],
activeOn?: number[]
) {
const remindersToDeletePromise: Prisma.PrismaPromise<
{
id: number;
referenceId: string | null;
method: string;
}[]
>[] = [];
removedTeams.forEach((teamId) => {
const reminderToDelete = prisma.workflowReminder.findMany({
where: {
OR: [
{
//team event types + children managed event types
booking: {
eventType: {
OR: [{ teamId }, { teamId: null, parent: { teamId } }],
},
},
},
{
// user bookings
booking: {
user: {
AND: [
// user is part of team that got removed
{
teams: {
some: {
teamId: teamId,
},
},
},
// and user is not part of any team were the workflow is still active on
{
teams: {
none: {
teamId: {
in: activeOn,
},
},
},
},
],
},
eventType: {
teamId: null,
parentId: null, // children managed event types are handled above with team event types
},
},
},
],
workflowStepId: {
in: workflowSteps.map((step) => {
return step.id;
}),
},
},
select: {
id: true,
referenceId: true,
method: true,
},
});
remindersToDeletePromise.push(reminderToDelete);
});
const remindersToDelete = (await Promise.all(remindersToDeletePromise)).flat();
return remindersToDelete;
: await WorkflowRepository.getRemindersFromRemovedTeams(removedActiveOnIds, workflowSteps, activeOnIds);
await WorkflowRepository.deleteAllWorkflowReminders(remindersToDelete);
}
async function getRemindersFromRemovedEventTypes(removedEventTypes: number[], workflowSteps: WorkflowStep[]) {