When rescheduling update specific calendar (#3375)
Co-authored-by: Omar López <zomars@me.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>pull/3420/head
parent
a9ad9a6a39
commit
6fc3e17b47
|
@ -376,6 +376,7 @@ async function handler(req: NextApiRequest) {
|
|||
select: {
|
||||
id: true,
|
||||
attendees: true,
|
||||
userId: true,
|
||||
references: {
|
||||
select: {
|
||||
type: true,
|
||||
|
|
|
@ -500,12 +500,13 @@ const loggedInViewerRouter = createProtectedRouter()
|
|||
There are connected calendars, but no destination calendar
|
||||
So create a default destination calendar with the first primary connected calendar
|
||||
*/
|
||||
const { integration = "", externalId = "" } = connectedCalendars[0].primary ?? {};
|
||||
const { integration = "", externalId = "", credentialId } = connectedCalendars[0].primary ?? {};
|
||||
user.destinationCalendar = await ctx.prisma.destinationCalendar.create({
|
||||
data: {
|
||||
userId: user.id,
|
||||
integration,
|
||||
externalId,
|
||||
credentialId,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
|
@ -546,7 +547,7 @@ const loggedInViewerRouter = createProtectedRouter()
|
|||
}),
|
||||
async resolve({ ctx, input }) {
|
||||
const { user } = ctx;
|
||||
const { integration, externalId, eventTypeId, bookingId } = input;
|
||||
const { integration, externalId, eventTypeId } = input;
|
||||
const calendarCredentials = getCalendarCredentials(user.credentials, user.id);
|
||||
const connectedCalendars = await getConnectedCalendars(calendarCredentials, user.selectedCalendars);
|
||||
const allCals = connectedCalendars.map((cal) => cal.calendars ?? []).flat();
|
||||
|
@ -562,7 +563,6 @@ const loggedInViewerRouter = createProtectedRouter()
|
|||
let where;
|
||||
|
||||
if (eventTypeId) where = { eventTypeId };
|
||||
else if (bookingId) where = { bookingId };
|
||||
else where = { userId: user.id };
|
||||
|
||||
await ctx.prisma.destinationCalendar.upsert({
|
||||
|
|
|
@ -8,7 +8,12 @@ import getApps from "@calcom/app-store/utils";
|
|||
import prisma from "@calcom/prisma";
|
||||
import type { AdditionalInformation, CalendarEvent, NewCalendarEventType } from "@calcom/types/Calendar";
|
||||
import type { Event } from "@calcom/types/Event";
|
||||
import type { CreateUpdateResult, EventResult, PartialBooking } from "@calcom/types/EventManager";
|
||||
import type {
|
||||
CreateUpdateResult,
|
||||
EventResult,
|
||||
PartialBooking,
|
||||
PartialReference,
|
||||
} from "@calcom/types/EventManager";
|
||||
|
||||
import { createEvent, updateEvent } from "./CalendarManager";
|
||||
import { LocationType } from "./location";
|
||||
|
@ -141,6 +146,7 @@ export default class EventManager {
|
|||
meetingPassword: result.createdEvent?.password,
|
||||
meetingUrl: result.createdEvent?.url,
|
||||
externalCalendarId: evt.destinationCalendar?.externalId,
|
||||
credentialId: evt.destinationCalendar?.credentialId,
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -175,6 +181,7 @@ export default class EventManager {
|
|||
},
|
||||
select: {
|
||||
id: true,
|
||||
userId: true,
|
||||
references: {
|
||||
// NOTE: id field removed from select as we don't require for deletingMany
|
||||
// but was giving error on recreate for reschedule, probably because promise.all() didn't finished
|
||||
|
@ -185,6 +192,7 @@ export default class EventManager {
|
|||
meetingPassword: true,
|
||||
meetingUrl: true,
|
||||
externalCalendarId: true,
|
||||
credentialId: true,
|
||||
},
|
||||
},
|
||||
destinationCalendar: true,
|
||||
|
@ -381,36 +389,47 @@ export default class EventManager {
|
|||
event: CalendarEvent,
|
||||
booking: PartialBooking
|
||||
): Promise<Array<EventResult<NewCalendarEventType>>> {
|
||||
return async.mapLimit(this.calendarCredentials, 5, async (credential: Credential) => {
|
||||
try {
|
||||
// HACK:
|
||||
// Right now if two calendars are connected and a booking is created it has two bookingReferences, one is having uid null and the other is having valid uid.
|
||||
// I don't know why yet - But we should work on fixing that. But even after the fix as there can be multiple references in an existing booking the following ref.uid check would still be required
|
||||
// We should ignore the one with uid null, the other one is valid.
|
||||
// Also, we should store(if not already) that which is the calendarCredential for the valid bookingReference, instead of going through all credentials one by one
|
||||
const [bookingRef] = booking.references
|
||||
? booking.references.filter((ref) => ref.type === credential.type && !!ref.uid)
|
||||
: [];
|
||||
let calendarReference: PartialReference | undefined = undefined,
|
||||
credential;
|
||||
try {
|
||||
// Bookings should only have one calendar reference
|
||||
calendarReference = booking.references.filter((reference) => reference.type.includes("_calendar"))[0];
|
||||
|
||||
if (!bookingRef) throw new Error("bookingRef");
|
||||
if (!calendarReference) throw new Error("bookingRef");
|
||||
|
||||
const { uid: bookingRefUid, externalCalendarId: bookingExternalCalendarId } = bookingRef;
|
||||
const { uid: bookingRefUid, externalCalendarId: bookingExternalCalendarId } = calendarReference;
|
||||
|
||||
if (!bookingExternalCalendarId) throw new Error("externalCalendarId");
|
||||
if (!bookingExternalCalendarId) throw new Error("externalCalendarId");
|
||||
|
||||
return updateEvent(credential, event, bookingRefUid, bookingExternalCalendarId);
|
||||
} catch (error) {
|
||||
let message = `Tried to 'updateAllCalendarEvents' but there was no '{thing}' for '${credential.type}', userId: '${credential.userId}', bookingId: '${booking.id}'`;
|
||||
if (error instanceof Error) message = message.replace("{thing}", error.message);
|
||||
console.error(message);
|
||||
return Promise.resolve({
|
||||
type: credential.type,
|
||||
const result = [];
|
||||
if (calendarReference.credentialId) {
|
||||
credential = this.calendarCredentials.filter(
|
||||
(credential) => credential.id === calendarReference?.credentialId
|
||||
)[0];
|
||||
result.push(updateEvent(credential, event, bookingRefUid, bookingExternalCalendarId));
|
||||
} else {
|
||||
const credentials = this.calendarCredentials.filter(
|
||||
(credential) => credential.type === calendarReference?.type
|
||||
);
|
||||
for (const credential of credentials) {
|
||||
result.push(updateEvent(credential, event, bookingRefUid, bookingExternalCalendarId));
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(result);
|
||||
} catch (error) {
|
||||
let message = `Tried to 'updateAllCalendarEvents' but there was no '{thing}' for '${credential?.type}', userId: '${credential?.userId}', bookingId: '${booking?.id}'`;
|
||||
if (error instanceof Error) message = message.replace("{thing}", error.message);
|
||||
console.error(message);
|
||||
return Promise.resolve([
|
||||
{
|
||||
type: calendarReference?.type || "calendar",
|
||||
success: false,
|
||||
uid: "",
|
||||
originalEvent: event,
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `bookingId` on the `DestinationCalendar` table. All the data in the column will be lost.
|
||||
|
||||
*/
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "DestinationCalendar" DROP CONSTRAINT "DestinationCalendar_bookingId_fkey";
|
||||
|
||||
-- DropIndex
|
||||
DROP INDEX "DestinationCalendar_bookingId_key";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Booking" ADD COLUMN "destinationCalendarId" INTEGER;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "BookingReference" ADD COLUMN "credentialId" INTEGER;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "DestinationCalendar" DROP COLUMN "bookingId";
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Booking" ADD CONSTRAINT "Booking_destinationCalendarId_fkey" FOREIGN KEY ("destinationCalendarId") REFERENCES "DestinationCalendar"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
|
@ -111,8 +111,7 @@ model DestinationCalendar {
|
|||
externalId String
|
||||
user User? @relation(fields: [userId], references: [id])
|
||||
userId Int? @unique
|
||||
booking Booking? @relation(fields: [bookingId], references: [id])
|
||||
bookingId Int? @unique
|
||||
booking Booking[]
|
||||
eventType EventType? @relation(fields: [eventTypeId], references: [id])
|
||||
eventTypeId Int? @unique
|
||||
credentialId Int?
|
||||
|
@ -238,6 +237,7 @@ model BookingReference {
|
|||
bookingId Int?
|
||||
externalCalendarId String?
|
||||
deleted Boolean?
|
||||
credentialId Int?
|
||||
}
|
||||
|
||||
model Attendee {
|
||||
|
@ -266,36 +266,37 @@ model DailyEventReference {
|
|||
}
|
||||
|
||||
model Booking {
|
||||
id Int @id @default(autoincrement())
|
||||
uid String @unique
|
||||
user User? @relation(fields: [userId], references: [id])
|
||||
userId Int?
|
||||
references BookingReference[]
|
||||
eventType EventType? @relation(fields: [eventTypeId], references: [id])
|
||||
eventTypeId Int?
|
||||
title String
|
||||
description String?
|
||||
customInputs Json?
|
||||
startTime DateTime
|
||||
endTime DateTime
|
||||
attendees Attendee[]
|
||||
location String?
|
||||
dailyRef DailyEventReference?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime?
|
||||
status BookingStatus @default(ACCEPTED)
|
||||
paid Boolean @default(false)
|
||||
payment Payment[]
|
||||
destinationCalendar DestinationCalendar?
|
||||
cancellationReason String?
|
||||
rejectionReason String?
|
||||
dynamicEventSlugRef String?
|
||||
dynamicGroupSlugRef String?
|
||||
rescheduled Boolean?
|
||||
fromReschedule String?
|
||||
recurringEventId String?
|
||||
smsReminderNumber String?
|
||||
workflowReminders WorkflowReminder[]
|
||||
id Int @id @default(autoincrement())
|
||||
uid String @unique
|
||||
user User? @relation(fields: [userId], references: [id])
|
||||
userId Int?
|
||||
references BookingReference[]
|
||||
eventType EventType? @relation(fields: [eventTypeId], references: [id])
|
||||
eventTypeId Int?
|
||||
title String
|
||||
description String?
|
||||
customInputs Json?
|
||||
startTime DateTime
|
||||
endTime DateTime
|
||||
attendees Attendee[]
|
||||
location String?
|
||||
dailyRef DailyEventReference?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime?
|
||||
status BookingStatus @default(ACCEPTED)
|
||||
paid Boolean @default(false)
|
||||
payment Payment[]
|
||||
destinationCalendar DestinationCalendar? @relation(fields: [destinationCalendarId], references: [id])
|
||||
destinationCalendarId Int?
|
||||
cancellationReason String?
|
||||
rejectionReason String?
|
||||
dynamicEventSlugRef String?
|
||||
dynamicGroupSlugRef String?
|
||||
rescheduled Boolean?
|
||||
fromReschedule String?
|
||||
recurringEventId String?
|
||||
smsReminderNumber String?
|
||||
workflowReminders WorkflowReminder[]
|
||||
}
|
||||
|
||||
model Schedule {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { DestinationCalendar } from "@prisma/client";
|
||||
|
||||
import type { CalendarEvent } from "./Calendar";
|
||||
import type { Event } from "./Event";
|
||||
|
||||
|
@ -9,6 +11,7 @@ export interface PartialReference {
|
|||
meetingPassword?: string | null;
|
||||
meetingUrl?: string | null;
|
||||
externalCalendarId?: string | null;
|
||||
credentialId?: number | null;
|
||||
}
|
||||
|
||||
export interface EventResult<T> {
|
||||
|
@ -27,5 +30,7 @@ export interface CreateUpdateResult {
|
|||
|
||||
export interface PartialBooking {
|
||||
id: number;
|
||||
userId: number | null;
|
||||
references: Array<PartialReference>;
|
||||
credentialId?: number;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue