* WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * WIP * Update CalendarService.ts * Type fixes * WIP * fix: improve cache hits * Update CalendarService.ts * Update CalendarService.ts * Update CalendarService.ts * Update CalendarService.ts * Update CalendarService.ts * Update CalendarService.ts * Feedback * Update CalendarService.ts * Update CalendarService.ts * Update _router.ts * feedback * WIP * WIP * Update schema.prisma * feedback * typefixes * Update Calendar.d.ts * fix: watches when adding a calendar * Discard changes to packages/app-store/googlecalendar/api/add.ts * WIP Signed-off-by: Omar López <zomars@me.com> * WIP Signed-off-by: Omar López <zomars@me.com> * WP Signed-off-by: Omar López <zomars@me.com> * Update calendar.ts * Update calendar.ts * Update callback.ts * Update callback.ts * Conflicts * WIP * WIP * Update CalendarService.ts * Cleanup * Discard changes to packages/features/settings/layouts/SettingsLayout.tsx * Update calendar-cache.repository.ts * WIP * Update getSelectedCalendarsToWatch.sql * WIP * Update CalendarService.ts * Cleanup * Discard changes to packages/app-store/googlecalendar/lib/CalendarService.ts * Create CalendarService.wip.ts * WIP * Update CalendarService.ts * Update getSelectedCalendarsToWatch.sql * Delete CalendarService.wip.ts * test updates * cleanup Signed-off-by: Omar López <zomars@me.com> * Update CalendarService.test.ts * Update CalendarService.ts * type fixes * Update OAuthManager.ts * Update CalendarService.ts * Almost there * Update CalendarService.test.ts * Update calendar.ts * Update callback.ts * Update toggleFeatureFlag.handler.ts * fix: feedback * Update getSelectedCalendarsToWatch.sql * Fix unit tests --------- Signed-off-by: Omar López <zomars@me.com> Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
95 lines
3.8 KiB
TypeScript
95 lines
3.8 KiB
TypeScript
import type { NextApiRequest, NextApiResponse } from "next";
|
|
import { z } from "zod";
|
|
|
|
import { getCalendarCredentials, getConnectedCalendars } from "@calcom/core/CalendarManager";
|
|
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
|
import { CalendarCache } from "@calcom/features/calendar-cache/calendar-cache";
|
|
import { HttpError } from "@calcom/lib/http-error";
|
|
import notEmpty from "@calcom/lib/notEmpty";
|
|
import { defaultHandler, defaultResponder } from "@calcom/lib/server";
|
|
import { SelectedCalendarRepository } from "@calcom/lib/server/repository/selectedCalendar";
|
|
import { UserRepository } from "@calcom/lib/server/repository/user";
|
|
|
|
const selectedCalendarSelectSchema = z.object({
|
|
integration: z.string(),
|
|
externalId: z.string(),
|
|
credentialId: z.coerce.number(),
|
|
});
|
|
|
|
/** Shared authentication middleware for GET, DELETE and POST requests */
|
|
async function authMiddleware(req: CustomNextApiRequest) {
|
|
const session = await getServerSession({ req });
|
|
|
|
if (!session?.user?.id) {
|
|
throw new HttpError({ statusCode: 401, message: "Not authenticated" });
|
|
}
|
|
|
|
const userWithCredentials = await UserRepository.findUserWithCredentials({ id: session.user.id });
|
|
|
|
if (!userWithCredentials) {
|
|
throw new HttpError({ statusCode: 401, message: "Not authenticated" });
|
|
}
|
|
req.userWithCredentials = userWithCredentials;
|
|
return userWithCredentials;
|
|
}
|
|
|
|
type CustomNextApiRequest = NextApiRequest & {
|
|
userWithCredentials?: Awaited<ReturnType<typeof authMiddleware>>;
|
|
};
|
|
|
|
async function postHandler(req: CustomNextApiRequest) {
|
|
if (!req.userWithCredentials) throw new HttpError({ statusCode: 401, message: "Not authenticated" });
|
|
const user = req.userWithCredentials;
|
|
const { integration, externalId, credentialId } = selectedCalendarSelectSchema.parse(req.body);
|
|
await SelectedCalendarRepository.upsert({
|
|
userId: user.id,
|
|
integration,
|
|
externalId,
|
|
credentialId,
|
|
});
|
|
|
|
return { message: "Calendar Selection Saved" };
|
|
}
|
|
|
|
async function deleteHandler(req: CustomNextApiRequest) {
|
|
if (!req.userWithCredentials) throw new HttpError({ statusCode: 401, message: "Not authenticated" });
|
|
const user = req.userWithCredentials;
|
|
const { integration, externalId, credentialId } = selectedCalendarSelectSchema.parse(req.query);
|
|
const calendarCacheRepository = await CalendarCache.initFromCredentialId(credentialId);
|
|
await calendarCacheRepository.unwatchCalendar({ calendarId: externalId });
|
|
await SelectedCalendarRepository.delete({
|
|
userId: user.id,
|
|
externalId,
|
|
integration,
|
|
});
|
|
|
|
return { message: "Calendar Selection Saved" };
|
|
}
|
|
|
|
async function getHandler(req: CustomNextApiRequest) {
|
|
if (!req.userWithCredentials) throw new HttpError({ statusCode: 401, message: "Not authenticated" });
|
|
const user = req.userWithCredentials;
|
|
const selectedCalendarIds = await SelectedCalendarRepository.findMany({
|
|
where: { userId: user.id },
|
|
select: { externalId: true },
|
|
});
|
|
// get user's credentials + their connected integrations
|
|
const calendarCredentials = getCalendarCredentials(user.credentials);
|
|
// get all the connected integrations' calendars (from third party)
|
|
const { connectedCalendars } = await getConnectedCalendars(calendarCredentials, user.selectedCalendars);
|
|
const calendars = connectedCalendars.flatMap((c) => c.calendars).filter(notEmpty);
|
|
const selectableCalendars = calendars.map((cal) => {
|
|
return { selected: selectedCalendarIds.findIndex((s) => s.externalId === cal.externalId) > -1, ...cal };
|
|
});
|
|
return selectableCalendars;
|
|
}
|
|
|
|
export default defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => {
|
|
await authMiddleware(req);
|
|
return defaultHandler({
|
|
GET: Promise.resolve({ default: defaultResponder(getHandler) }),
|
|
POST: Promise.resolve({ default: defaultResponder(postHandler) }),
|
|
DELETE: Promise.resolve({ default: defaultResponder(deleteHandler) }),
|
|
})(req, res);
|
|
});
|