fix: Workflow action 'email to host' only sends to one host of team e… (#14767)
* fix: Workflow action 'email to host' only sends to one host of team event * add in missing files * fix host logic * uncomment working test * code refactor * use connected calendar email * add changes to util file * fix: extend eventType info in sendCancelledReminders --------- Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
This commit is contained in:
co-authored by
Udit Takkar
parent
30c31d3585
commit
66cb2bcc13
@@ -107,6 +107,7 @@ async function getBookingToDelete(id: number | undefined, uid: string | undefine
|
||||
bookingFields: true,
|
||||
seatsShowAttendees: true,
|
||||
metadata: true,
|
||||
schedulingType: true,
|
||||
hosts: {
|
||||
select: {
|
||||
user: true,
|
||||
@@ -357,7 +358,13 @@ async function handler(req: CustomRequest) {
|
||||
smsReminderNumber: bookingToDelete.smsReminderNumber,
|
||||
evt: {
|
||||
...evt,
|
||||
...{ eventType: { slug: bookingToDelete.eventType?.slug } },
|
||||
...{
|
||||
eventType: {
|
||||
slug: bookingToDelete.eventType?.slug,
|
||||
schedulingType: bookingToDelete.eventType?.schedulingType,
|
||||
hosts: bookingToDelete.eventType?.hosts,
|
||||
},
|
||||
},
|
||||
},
|
||||
hideBranding: !!bookingToDelete.eventType?.owner?.hideBranding,
|
||||
});
|
||||
|
||||
@@ -20,6 +20,7 @@ import { getTeamIdFromEventType } from "@calcom/lib/getTeamIdFromEventType";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { safeStringify } from "@calcom/lib/safeStringify";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import type { SchedulingType } from "@calcom/prisma/enums";
|
||||
import { BookingStatus, WebhookTriggerEvents } from "@calcom/prisma/enums";
|
||||
import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
import { getAllWorkflowsFromEventType } from "@calcom/trpc/server/routers/viewer/workflows/util";
|
||||
@@ -135,6 +136,15 @@ export async function handleConfirmation(args: {
|
||||
eventType: {
|
||||
bookingFields: Prisma.JsonValue | null;
|
||||
slug: string;
|
||||
schedulingType: SchedulingType | null;
|
||||
hosts: {
|
||||
user: {
|
||||
email: string;
|
||||
destinationCalendar?: {
|
||||
primaryEmail: string | null;
|
||||
} | null;
|
||||
};
|
||||
}[];
|
||||
owner: {
|
||||
hideBranding?: boolean | null;
|
||||
} | null;
|
||||
@@ -175,6 +185,21 @@ export async function handleConfirmation(args: {
|
||||
select: {
|
||||
slug: true,
|
||||
bookingFields: true,
|
||||
schedulingType: true,
|
||||
hosts: {
|
||||
select: {
|
||||
user: {
|
||||
select: {
|
||||
email: true,
|
||||
destinationCalendar: {
|
||||
select: {
|
||||
primaryEmail: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
owner: {
|
||||
select: {
|
||||
hideBranding: true,
|
||||
@@ -220,11 +245,26 @@ export async function handleConfirmation(args: {
|
||||
select: {
|
||||
slug: true,
|
||||
bookingFields: true,
|
||||
schedulingType: true,
|
||||
owner: {
|
||||
select: {
|
||||
hideBranding: true,
|
||||
},
|
||||
},
|
||||
hosts: {
|
||||
select: {
|
||||
user: {
|
||||
select: {
|
||||
email: true,
|
||||
destinationCalendar: {
|
||||
select: {
|
||||
primaryEmail: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
uid: true,
|
||||
@@ -249,7 +289,11 @@ export async function handleConfirmation(args: {
|
||||
const evtOfBooking = {
|
||||
...evt,
|
||||
metadata: { videoCallUrl: meetingUrl },
|
||||
eventType: { slug: eventTypeSlug },
|
||||
eventType: {
|
||||
slug: eventTypeSlug,
|
||||
schedulingType: updatedBookings[index].eventType?.schedulingType,
|
||||
hosts: updatedBookings[index].eventType?.hosts,
|
||||
},
|
||||
};
|
||||
evtOfBooking.startTime = updatedBookings[index].startTime.toISOString();
|
||||
evtOfBooking.endTime = updatedBookings[index].endTime.toISOString();
|
||||
|
||||
@@ -1741,7 +1741,11 @@ async function handler(
|
||||
loggerWithEventDetails.error("Error while creating booking references", JSON.stringify({ error }));
|
||||
}
|
||||
|
||||
const evtWithMetadata = { ...evt, metadata, eventType: { slug: eventType.slug } };
|
||||
const evtWithMetadata = {
|
||||
...evt,
|
||||
metadata,
|
||||
eventType: { slug: eventType.slug, schedulingType: eventType.schedulingType, hosts: eventType.hosts },
|
||||
};
|
||||
|
||||
if (!eventType.metadata?.disableStandardEmails?.all?.attendee) {
|
||||
await scheduleMandatoryReminder(
|
||||
|
||||
@@ -392,8 +392,7 @@ describe("handleNewBooking", () => {
|
||||
});
|
||||
|
||||
expectWorkflowToBeTriggered({
|
||||
// emailsToReceive: [organizer.email].concat(otherTeamMembers.map(member => member.email)),
|
||||
emailsToReceive: [organizer.email],
|
||||
emailsToReceive: [organizer.email].concat(otherTeamMembers.map((member) => member.email)),
|
||||
emails,
|
||||
});
|
||||
},
|
||||
|
||||
@@ -104,7 +104,17 @@ const handleSeats = async (newSeatedBookingObject: NewSeatedBookingObject) => {
|
||||
await scheduleWorkflowReminders({
|
||||
workflows,
|
||||
smsReminderNumber: smsReminderNumber || null,
|
||||
calendarEvent: { ...evt, ...{ metadata, eventType: { slug: eventType.slug } } },
|
||||
calendarEvent: {
|
||||
...evt,
|
||||
...{
|
||||
metadata,
|
||||
eventType: {
|
||||
slug: eventType.slug,
|
||||
schedulingType: eventType.schedulingType,
|
||||
hosts: eventType.hosts,
|
||||
},
|
||||
},
|
||||
},
|
||||
isNotConfirmed: evt.requiresConfirmation || false,
|
||||
isRescheduleEvent: !!rescheduleUid,
|
||||
emailAttendeeSendToOverride: bookerEmail,
|
||||
|
||||
@@ -9,7 +9,7 @@ import logger from "@calcom/lib/logger";
|
||||
import { defaultHandler } from "@calcom/lib/server";
|
||||
import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat";
|
||||
import prisma from "@calcom/prisma";
|
||||
import { WorkflowActions, WorkflowMethods, WorkflowTemplates } from "@calcom/prisma/enums";
|
||||
import { SchedulingType, WorkflowActions, WorkflowMethods, WorkflowTemplates } from "@calcom/prisma/enums";
|
||||
import { bookingMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
import type { PartialWorkflowReminder } from "../lib/getWorkflowReminders";
|
||||
@@ -119,6 +119,19 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
switch (reminder.workflowStep.action) {
|
||||
case WorkflowActions.EMAIL_HOST:
|
||||
sendTo = reminder.booking?.userPrimaryEmail ?? reminder.booking.user?.email;
|
||||
const hosts = reminder?.booking?.eventType?.hosts
|
||||
?.filter((host) =>
|
||||
reminder.booking?.attendees.some((attendee) => attendee.email === host.user.email)
|
||||
)
|
||||
.map(({ user }) => user.destinationCalendar?.primaryEmail ?? user.email);
|
||||
const schedulingType = reminder.booking.eventType?.schedulingType;
|
||||
|
||||
if (
|
||||
hosts &&
|
||||
(schedulingType === SchedulingType.COLLECTIVE || schedulingType === SchedulingType.ROUND_ROBIN)
|
||||
) {
|
||||
sendTo = sendTo ? [sendTo, ...hosts] : hosts;
|
||||
}
|
||||
break;
|
||||
case WorkflowActions.EMAIL_ATTENDEE:
|
||||
sendTo = reminder.booking.attendees[0].email;
|
||||
|
||||
@@ -27,7 +27,14 @@ type PartialBooking =
|
||||
| "attendees"
|
||||
| "userPrimaryEmail"
|
||||
| "smsReminderNumber"
|
||||
> & { eventType: (Partial<EventType> & { team: { parentId?: number } }) | null } & {
|
||||
> & {
|
||||
eventType:
|
||||
| (Partial<EventType> & {
|
||||
team: { parentId?: number };
|
||||
hosts: { user: { email: string; destinationCalendar?: { primaryEmail: string } } }[] | undefined;
|
||||
})
|
||||
| null;
|
||||
} & {
|
||||
user: Partial<User> | null;
|
||||
})
|
||||
| null;
|
||||
@@ -159,6 +166,20 @@ export const select: Prisma.WorkflowReminderSelect = {
|
||||
bookingFields: true,
|
||||
title: true,
|
||||
slug: true,
|
||||
hosts: {
|
||||
select: {
|
||||
user: {
|
||||
select: {
|
||||
email: true,
|
||||
destinationCalendar: {
|
||||
select: {
|
||||
primaryEmail: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
recurringEvent: true,
|
||||
team: {
|
||||
select: {
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
import type { Workflow, WorkflowStep } from "@calcom/features/ee/workflows/lib/types";
|
||||
import { checkSMSRateLimit } from "@calcom/lib/checkRateLimitAndThrowError";
|
||||
import { SENDER_NAME } from "@calcom/lib/constants";
|
||||
import { WorkflowActions, WorkflowTriggerEvents } from "@calcom/prisma/enums";
|
||||
import { SchedulingType, WorkflowActions, WorkflowTriggerEvents } from "@calcom/prisma/enums";
|
||||
import type { CalendarEvent } from "@calcom/types/Calendar";
|
||||
|
||||
import { scheduleEmailReminder } from "./emailReminderManager";
|
||||
@@ -16,7 +16,11 @@ import { scheduleWhatsappReminder } from "./whatsappReminderManager";
|
||||
|
||||
export type ExtendedCalendarEvent = CalendarEvent & {
|
||||
metadata?: { videoCallUrl: string | undefined };
|
||||
eventType: { slug?: string };
|
||||
eventType: {
|
||||
slug?: string;
|
||||
schedulingType?: SchedulingType | null;
|
||||
hosts?: { user: { email: string; destinationCalendar?: { primaryEmail: string | null } | null } }[];
|
||||
};
|
||||
};
|
||||
|
||||
type ProcessWorkflowStepParams = {
|
||||
@@ -85,6 +89,13 @@ const processWorkflowStep = async (
|
||||
break;
|
||||
case WorkflowActions.EMAIL_HOST:
|
||||
sendTo = [evt.organizer?.email || ""];
|
||||
|
||||
const schedulingType = evt.eventType.schedulingType;
|
||||
const isTeamEvent =
|
||||
schedulingType === SchedulingType.ROUND_ROBIN || schedulingType === SchedulingType.COLLECTIVE;
|
||||
if (isTeamEvent && evt.team?.members) {
|
||||
sendTo = sendTo.concat(evt.team.members.map((member) => member.email));
|
||||
}
|
||||
break;
|
||||
case WorkflowActions.EMAIL_ATTENDEE:
|
||||
const attendees = !!emailAttendeeSendToOverride
|
||||
|
||||
@@ -4,7 +4,7 @@ import { scheduleWhatsappReminder } from "@calcom/features/ee/workflows/lib/remi
|
||||
import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat";
|
||||
import { prisma } from "@calcom/prisma";
|
||||
import { BookingStatus } from "@calcom/prisma/client";
|
||||
import { MembershipRole, WorkflowActions } from "@calcom/prisma/enums";
|
||||
import { MembershipRole, SchedulingType, WorkflowActions } from "@calcom/prisma/enums";
|
||||
import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
|
||||
|
||||
@@ -200,7 +200,26 @@ export const activateEventTypeHandler = async ({ ctx, input }: ActivateEventType
|
||||
},
|
||||
include: {
|
||||
attendees: true,
|
||||
eventType: true,
|
||||
eventType: {
|
||||
select: {
|
||||
schedulingType: true,
|
||||
slug: true,
|
||||
hosts: {
|
||||
select: {
|
||||
user: {
|
||||
select: {
|
||||
email: true,
|
||||
destinationCalendar: {
|
||||
select: {
|
||||
primaryEmail: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
user: true,
|
||||
},
|
||||
});
|
||||
@@ -232,6 +251,8 @@ export const activateEventTypeHandler = async ({ ctx, input }: ActivateEventType
|
||||
language: { locale: booking?.user?.locale || defaultLocale },
|
||||
eventType: {
|
||||
slug: booking.eventType?.slug,
|
||||
schedulingType: booking.eventType?.schedulingType,
|
||||
hosts: booking.eventType?.hosts,
|
||||
},
|
||||
};
|
||||
for (const step of eventTypeWorkflow.steps) {
|
||||
@@ -245,6 +266,19 @@ export const activateEventTypeHandler = async ({ ctx, input }: ActivateEventType
|
||||
switch (step.action) {
|
||||
case WorkflowActions.EMAIL_HOST:
|
||||
sendTo = [bookingInfo.organizer?.email];
|
||||
const schedulingType = bookingInfo.eventType?.schedulingType;
|
||||
const hosts = bookingInfo.eventType.hosts
|
||||
?.filter((host) =>
|
||||
bookingInfo.attendees.some((attendee) => host.user.email === attendee.email)
|
||||
)
|
||||
.map(({ user }) => user.destinationCalendar?.primaryEmail ?? user.email);
|
||||
if (
|
||||
(schedulingType === SchedulingType.ROUND_ROBIN ||
|
||||
schedulingType === SchedulingType.COLLECTIVE) &&
|
||||
hosts
|
||||
) {
|
||||
sendTo = sendTo.concat(hosts);
|
||||
}
|
||||
break;
|
||||
case WorkflowActions.EMAIL_ATTENDEE:
|
||||
sendTo = bookingInfo.attendees.map((attendee) => attendee.email);
|
||||
|
||||
@@ -31,6 +31,7 @@ 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,
|
||||
@@ -64,6 +65,21 @@ export const bookingSelect = {
|
||||
select: {
|
||||
slug: true,
|
||||
id: true,
|
||||
schedulingType: true,
|
||||
hosts: {
|
||||
select: {
|
||||
user: {
|
||||
select: {
|
||||
email: true,
|
||||
destinationCalendar: {
|
||||
select: {
|
||||
primaryEmail: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
user: {
|
||||
@@ -732,6 +748,8 @@ export async function scheduleBookingReminders(
|
||||
language: { locale: booking?.user?.locale || defaultLocale },
|
||||
eventType: {
|
||||
slug: booking.eventType?.slug,
|
||||
schedulingType: booking.eventType?.schedulingType,
|
||||
hosts: booking.eventType?.hosts,
|
||||
},
|
||||
};
|
||||
if (
|
||||
@@ -744,6 +762,16 @@ export async function scheduleBookingReminders(
|
||||
switch (step.action) {
|
||||
case WorkflowActions.EMAIL_HOST:
|
||||
sendTo = [bookingInfo.organizer?.email];
|
||||
const schedulingType = bookingInfo.eventType.schedulingType;
|
||||
const hosts = bookingInfo.eventType.hosts
|
||||
?.filter((host) => bookingInfo.attendees.some((attendee) => attendee.email === host.user.email))
|
||||
.map(({ user }) => user.destinationCalendar?.primaryEmail ?? user.email);
|
||||
if (
|
||||
hosts &&
|
||||
(schedulingType === SchedulingType.ROUND_ROBIN || schedulingType === SchedulingType.COLLECTIVE)
|
||||
) {
|
||||
sendTo = sendTo.concat(hosts);
|
||||
}
|
||||
break;
|
||||
case WorkflowActions.EMAIL_ATTENDEE:
|
||||
sendTo = bookingInfo.attendees.map((attendee) => attendee.email);
|
||||
@@ -751,6 +779,7 @@ export async function scheduleBookingReminders(
|
||||
case WorkflowActions.EMAIL_ADDRESS:
|
||||
await verifyEmailSender(step.sendTo || "", userId, teamId);
|
||||
sendTo = [step.sendTo || ""];
|
||||
break;
|
||||
}
|
||||
await scheduleEmailReminder({
|
||||
evt: bookingInfo,
|
||||
|
||||
Reference in New Issue
Block a user