Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: migrate api/availability/calendar to App Router #19099

Merged
merged 3 commits into from
Feb 6, 2025
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
123 changes: 123 additions & 0 deletions apps/web/app/api/availability/calendar/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { cookies, headers } from "next/headers";
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
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 { SelectedCalendarRepository } from "@calcom/lib/server/repository/selectedCalendar";
import { UserRepository } from "@calcom/lib/server/repository/user";

import { buildLegacyRequest } from "@lib/buildLegacyCtx";

const selectedCalendarSelectSchema = z.object({
integration: z.string(),
externalId: z.string(),
credentialId: z.coerce.number(),
eventTypeId: z.coerce.number().nullish(),
});

async function authMiddleware() {
const session = await getServerSession({ req: buildLegacyRequest(headers(), cookies()) });

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" });
}

return userWithCredentials;
}

// TODO: It doesn't seem to be used from within the app. It is possible that someone outside Cal.com is using this GET endpoint
export async function GET() {
try {
const user = await authMiddleware();

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.userLevelSelectedCalendars
);

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 NextResponse.json(selectableCalendars);
} catch (error) {
if (error instanceof HttpError) {
throw error;
}
return NextResponse.json({ error: "Internal Server Error" }, { status: 500 });
}
}

export async function POST(req: NextRequest) {
try {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No this isn't great; we need an higher level apiHandler wrapper fn.

const user = await authMiddleware();
const body = await req.json();
const { integration, externalId, credentialId, eventTypeId } = selectedCalendarSelectSchema.parse(body);

await SelectedCalendarRepository.upsert({
userId: user.id,
integration,
externalId,
credentialId,
eventTypeId: eventTypeId ?? null,
});

return NextResponse.json({ message: "Calendar Selection Saved" });
} catch (error) {
if (error instanceof HttpError) {
throw error;
}
return NextResponse.json({ error: "Internal Server Error" }, { status: 500 });
}
}

export async function DELETE(req: NextRequest) {
try {
const user = await authMiddleware();
const searchParams = Object.fromEntries(req.nextUrl.searchParams.entries());

const { integration, externalId, credentialId, eventTypeId } =
selectedCalendarSelectSchema.parse(searchParams);

const calendarCacheRepository = await CalendarCache.initFromCredentialId(credentialId);
await calendarCacheRepository.unwatchCalendar({
calendarId: externalId,
eventTypeIds: [eventTypeId ?? null],
});

await SelectedCalendarRepository.delete({
where: {
userId: user.id,
externalId,
integration,
eventTypeId: eventTypeId ?? null,
},
});

return NextResponse.json({ message: "Calendar Selection Saved" });
} catch (error) {
if (error instanceof HttpError) {
throw error;
}
return NextResponse.json({ error: "Internal Server Error" }, { status: 500 });
}
}
108 changes: 0 additions & 108 deletions apps/web/pages/api/availability/calendar.ts

This file was deleted.

Loading