feat/calendar-cache-inbound
zomars 2023-09-29 14:36:55 -07:00
parent a10db1dd12
commit c2b1b201c2
6 changed files with 72 additions and 15 deletions

View File

@ -1,8 +1,10 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { z } from "zod";
import { getCalendar } from "@calcom/app-store/_utils/getCalendar";
import { getCalendarCredentials, getConnectedCalendars } from "@calcom/core/CalendarManager";
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
import { getFeatureFlagMap } from "@calcom/features/flags/server/utils";
import notEmpty from "@calcom/lib/notEmpty";
import prisma from "@calcom/prisma";
import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";
@ -59,11 +61,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
// already exists
update: {},
});
await handleWatchCalendar(req);
res.status(200).json({ message: "Calendar Selection Saved" });
}
if (req.method === "DELETE") {
const { integration, externalId } = selectedCalendarSelectSchema.parse(req.query);
await handleWatchCalendar(req);
await prisma.selectedCalendar.delete({
where: {
userId_integration_externalId: {
@ -98,3 +102,33 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
res.status(200).json(selectableCalendars);
}
}
let warningDisplayed = false;
/** Prevent flooding the logs while testing/building */
function logOnce(message: string) {
if (warningDisplayed) return;
console.warn(message);
warningDisplayed = true;
}
async function handleWatchCalendar(req: NextApiRequest) {
const flags = await getFeatureFlagMap(prisma);
if (!flags["calendar-cache"]) {
logOnce('[handleWatchCalendar] Skipping watching calendar due to "calendar-cache" flag being disabled');
return;
}
const { integration, externalId, credentialId } = selectedCalendarSelectSchema.parse(req.body);
if (integration !== "google") {
logOnce('[handleWatchCalendar] Skipping watching calendar due to integration not being "google"');
return;
}
const credential = await prisma.credential.findFirst({
where: { id: credentialId },
select: credentialForCalendarServiceSelect,
});
const calendar = await getCalendar(credential);
calendar?.watchCalendar?({ calendarId: externalId, credentialId: 1 });
// return calendar?.deleteEvent(bookingRef.uid, builder.calendarEvent);
throw new Error("Function not implemented.");
}

View File

@ -1,2 +1,3 @@
export { default as add } from "./add";
export { default as callback } from "./callback";
export { default as webhook } from "./webhook";

View File

@ -0,0 +1,12 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { defaultHandler, defaultResponder } from "@calcom/lib/server";
async function postHandler(req: NextApiRequest, res: NextApiResponse) {
console.log(req);
res.status(200).json({ message: "ok" });
}
export default defaultHandler({
POST: Promise.resolve({ default: defaultResponder(postHandler) }),
});

View File

@ -529,25 +529,27 @@ export default class GoogleCalendarService implements Calendar {
}
}
async watchCalendar() {
async watchCalendar({ calendarId, credentialId }: { calendarId: string; credentialId: number }) {
const calendar = await this.authedCalendar();
const res = await calendar.events.watch({
// Calendar identifier. To retrieve calendar IDs call the calendarList.list method. If you want to access the primary calendar of the currently logged in user, use the "primary" keyword.
calendarId: "primary",
const id = `${credentialId}_${calendarId}`;
await calendar.channels.stop({
requestBody: {
// An id property string that uniquely identifies this new notification channel within your project. We recommend that you use a universally unique identifier (UUID) or any similar unique string. Maximum length: 64 characters. The ID value you set is echoed back in the X-Goog-Channel-Id HTTP header of every notification message that you receive for this channel.
id: "my_id",
type: "web_hook",
address: "https://cal.dev/api/integrations/googlecalendar/webhook",
},
});
console.log(res.data);
calendar.channels.stop({
requestBody: {
id: "my_id",
id,
resourceId: "my_resourceId",
},
});
const res = await calendar.events.watch({
// Calendar identifier. To retrieve calendar IDs call the calendarList.list method. If you want to access the primary calendar of the currently logged in user, use the "primary" keyword.
calendarId,
requestBody: {
// An id property string that uniquely identifies this new notification channel within your project. We recommend that you use a universally unique identifier (UUID) or any similar unique string. Maximum length: 64 characters. The ID value you set is echoed back in the X-Goog-Channel-Id HTTP header of every notification message that you receive for this channel.
id,
type: "web_hook",
address: "https://435d-200-76-22-226.ngrok-free.app/api/integrations/googlecalendar/webhook",
// address: "https://cal.dev/api/integrations/googlecalendar/webhook",
},
});
console.log(res.data);
// Example response
// {
// "address": "my_address",

View File

@ -2,13 +2,20 @@ import type { PrismaClient } from "@calcom/prisma";
import type { AppFlags } from "../config";
// This is a temporary cache to avoid hitting the database on every lambda invocation
let TEMP_CACHE: AppFlags | null = null;
export async function getFeatureFlagMap(prisma: PrismaClient) {
// If we've already fetched the flags, return them
if (TEMP_CACHE) return TEMP_CACHE;
const flags = await prisma.feature.findMany({
orderBy: { slug: "asc" },
cacheStrategy: { swr: 300, ttl: 300 },
});
return flags.reduce<AppFlags>((acc, flag) => {
// Save the flags to the cache
TEMP_CACHE = flags.reduce<AppFlags>((acc, flag) => {
acc[flag.slug as keyof AppFlags] = flag.enabled;
return acc;
}, {} as AppFlags);
return TEMP_CACHE;
}

View File

@ -238,6 +238,7 @@ export interface Calendar {
): Promise<EventBusyDate[]>;
listCalendars(event?: CalendarEvent): Promise<IntegrationCalendar[]>;
watchCalendar?(event?: CalendarEvent): Promise<IntegrationCalendar[]>;
}
/**