Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ export const handleRescheduleEventManager = async ({
prefix: ["handleRescheduleEventManager", `${bookingId}`],
});

const skipDeleteEventsAndMeetings = changedOrganizer;

const allCredentials = await getAllCredentialsIncludeServiceAccountKey(
initParams.user,
initParams?.eventType
Expand All @@ -68,7 +70,9 @@ export const handleRescheduleEventManager = async ({
rescheduleUid,
newBookingId,
changedOrganizer,
previousHostDestinationCalendar
previousHostDestinationCalendar,
undefined,
skipDeleteEventsAndMeetings
);

const results = updateManager.results ?? [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,16 @@ describe("roundRobinReassignment test", () => {

await roundRobinReassignment({
bookingId: 123,
reassignedById: 101,
orgId: null,
});

// Verify that calendar deletion occurred (may be called multiple times due to duplicate references)
expect(calendarMock.deleteEventCalls.length).toBeGreaterThanOrEqual(1);
const deleteCall = calendarMock.deleteEventCalls[0];
expect(deleteCall.args.uid).toBe("ORIGINAL_EVENT_ID");
expect(deleteCall.args.externalCalendarId).toBe("MOCK_EXTERNAL_CALENDAR_ID");
expect(deleteCall.args.event.organizer.email).toBe(newHost.email); // Current implementation uses new host credentials
expect(deleteCall.args.event.organizer.email).toBe(originalHost.email);
expect(deleteCall.args.event.uid).toBe(bookingToReassignUid);

// Verify that creation occurred with new host credentials
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,9 @@ const expectEventManagerCalledWith = (
expectedParams.uid,
undefined,
expectedParams.changedOrganizer,
expectedParams.destinationCalendars ?? expect.any(Array)
expectedParams.destinationCalendars ?? expect.any(Array),
undefined,
expectedParams.changedOrganizer
);
};

Expand Down
38 changes: 38 additions & 0 deletions packages/features/ee/round-robin/roundRobinManualReassignment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
sendRoundRobinScheduledEmailsAndSMS,
sendRoundRobinUpdatedEmailsAndSMS,
} from "@calcom/emails";
import { getAllCredentialsIncludeServiceAccountKey } from "@calcom/features/bookings/lib/getAllCredentialsForUsersOnEvent/getAllCredentials";
import getBookingResponsesSchema from "@calcom/features/bookings/lib/getBookingResponsesSchema";
import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses";
import { getEventTypesFromDB } from "@calcom/features/bookings/lib/handleNewBooking/getEventTypesFromDB";
Expand All @@ -21,6 +22,7 @@ import {
import { scheduleWorkflowReminders } from "@calcom/features/ee/workflows/lib/reminders/reminderScheduler";
import { getEventName } from "@calcom/features/eventtypes/lib/eventNaming";
import { getVideoCallUrlFromCalEvent } from "@calcom/lib/CalEventParser";
import EventManager from "@calcom/lib/EventManager";
import { SENDER_NAME } from "@calcom/lib/constants";
import { enrichUserWithDelegationCredentialsIncludeServiceAccountKey } from "@calcom/lib/delegationCredential/server";
import { getBookerBaseUrl } from "@calcom/lib/getBookerUrl/server";
Expand All @@ -32,6 +34,7 @@ import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat";
import { prisma } from "@calcom/prisma";
import { WorkflowActions, WorkflowMethods, WorkflowTriggerEvents } from "@calcom/prisma/enums";
import type { EventTypeMetadata, PlatformClientParams } from "@calcom/prisma/zod-utils";
import { eventTypeAppMetadataOptionalSchema } from "@calcom/prisma/zod-utils";
import type { CalendarEvent } from "@calcom/types/Calendar";

import { handleRescheduleEventManager } from "./handleRescheduleEventManager";
Expand Down Expand Up @@ -324,6 +327,41 @@ export const roundRobinManualReassignment = async ({
})
: null;

const apps = eventTypeAppMetadataOptionalSchema.parse(eventType?.metadata?.apps);

// remove the event and meeting using the old host's credentials
if (hasOrganizerChanged && originalOrganizer.id !== newUser.id) {
const previousHostCredentials = await getAllCredentialsIncludeServiceAccountKey(
originalOrganizer,
eventType
);

const originalHostEventManager = new EventManager(
{ ...originalOrganizer, credentials: previousHostCredentials },
apps
);

const deletionEvent: CalendarEvent = {
...evt,
organizer: {
id: originalOrganizer.id,
name: originalOrganizer.name || "",
email: originalOrganizer.email,
username: originalOrganizer.username || undefined,
timeZone: originalOrganizer.timeZone,
language: { translate: originalOrganizerT, locale: originalOrganizer.locale ?? "en" },
timeFormat: getTimeFormatStringFromUserTimeFormat(originalOrganizer.timeFormat),
},
destinationCalendar: previousHostDestinationCalendar ? [previousHostDestinationCalendar] : [],
title: booking.title,
};

await originalHostEventManager.deleteEventsAndMeetings({
event: deletionEvent,
bookingReferences: booking.references,
});
}

const { evtWithAdditionalInfo } = await handleRescheduleEventManager({
evt,
rescheduleUid: booking.uid,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,9 @@ describe("roundRobinReassignment test", () => {
bookingToReassignUid,
undefined,
true,
expect.arrayContaining([expect.objectContaining(testDestinationCalendar)])
expect.arrayContaining([expect.objectContaining(testDestinationCalendar)]),
undefined,
true
);

// Use equal fairness rr algorithm
Expand Down Expand Up @@ -279,7 +281,9 @@ describe("roundRobinReassignment test", () => {
bookingToReassignUid,
undefined,
false,
[]
[],
undefined,
false
);

// Ensure organizer stays the same
Expand Down
39 changes: 39 additions & 0 deletions packages/features/ee/round-robin/roundRobinReassignment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
sendRoundRobinScheduledEmailsAndSMS,
sendRoundRobinUpdatedEmailsAndSMS,
} from "@calcom/emails";
import { getAllCredentialsIncludeServiceAccountKey } from "@calcom/features/bookings/lib/getAllCredentialsForUsersOnEvent/getAllCredentials";
import getBookingResponsesSchema from "@calcom/features/bookings/lib/getBookingResponsesSchema";
import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses";
import { ensureAvailableUsers } from "@calcom/features/bookings/lib/handleNewBooking/ensureAvailableUsers";
Expand All @@ -17,6 +18,7 @@ import AssignmentReasonRecorder, {
RRReassignmentType,
} from "@calcom/features/ee/round-robin/assignmentReason/AssignmentReasonRecorder";
import { getEventName } from "@calcom/features/eventtypes/lib/eventNaming";
import EventManager from "@calcom/lib/EventManager";
import {
enrichHostsWithDelegationCredentials,
enrichUserWithDelegationCredentialsIncludeServiceAccountKey,
Expand All @@ -31,6 +33,7 @@ import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat";
import { prisma } from "@calcom/prisma";
import { userMetadata as userMetadataSchema } from "@calcom/prisma/zod-utils";
import type { EventTypeMetadata, PlatformClientParams } from "@calcom/prisma/zod-utils";
import { eventTypeAppMetadataOptionalSchema } from "@calcom/prisma/zod-utils";
import type { CalendarEvent } from "@calcom/types/Calendar";

import { handleRescheduleEventManager } from "./handleRescheduleEventManager";
Expand Down Expand Up @@ -355,6 +358,42 @@ export const roundRobinReassignment = async ({
user: { ...organizer, credentials },
});

const apps = eventTypeAppMetadataOptionalSchema.parse(eventType?.metadata?.apps);

// remove the event and meeting using the old host's credentials
if (hasOrganizerChanged && originalOrganizer.id !== reassignedRRHost.id) {
const previousHostCredentials = await getAllCredentialsIncludeServiceAccountKey(
originalOrganizer,
eventType
);
const originalHostEventManager = new EventManager(
{ ...originalOrganizer, credentials: previousHostCredentials },
apps
);

const originalOrganizerT = await getTranslation(originalOrganizer.locale || "en", "common");

const deletionEvent: CalendarEvent = {
...evt,
organizer: {
id: originalOrganizer.id,
name: originalOrganizer.name || "",
email: originalOrganizer.email,
username: originalOrganizer.username || undefined,
timeZone: originalOrganizer.timeZone,
language: { translate: originalOrganizerT, locale: originalOrganizer.locale ?? "en" },
timeFormat: getTimeFormatStringFromUserTimeFormat(originalOrganizer.timeFormat),
},
destinationCalendar: previousHostDestinationCalendar ? [previousHostDestinationCalendar] : [],
title: booking.title,
};

await originalHostEventManager.deleteEventsAndMeetings({
event: deletionEvent,
bookingReferences: booking.references,
});
}

const { evtWithAdditionalInfo } = await handleRescheduleEventManager({
evt,
rescheduleUid: booking.uid,
Expand Down
13 changes: 12 additions & 1 deletion packages/features/ee/round-robin/utils/bookingSelect.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Prisma } from "@calcom/prisma/client";
import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";

export const bookingSelect = {
uid: true,
Expand All @@ -13,8 +14,18 @@ export const bookingSelect = {
eventTypeId: true,
destinationCalendar: true,
user: {
include: {
select: {
id: true,
name: true,
username: true,
email: true,
locale: true,
timeZone: true,
timeFormat: true,
destinationCalendar: true,
credentials: {
select: credentialForCalendarServiceSelect,
},
},
},
attendees: true,
Expand Down
Loading