chore: refactor apiRouteMiddleware and add it to some api routes in App Router (#19146)
* chore: remove try and catch from api routes in app router * refactor * refactor apiRouteMiddleware * refactor
This commit is contained in:
1 parent
24a080b988
commit
e79af63e6c
6 files changed
+127
-156
No files matched your search
@@ -37,87 +37,68 @@ async function authMiddleware() {
|
||||
}
|
||||
|
||||
// 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();
|
||||
async function getHandler() {
|
||||
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 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 };
|
||||
});
|
||||
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 });
|
||||
}
|
||||
return NextResponse.json(selectableCalendars);
|
||||
}
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const user = await authMiddleware();
|
||||
const body = await req.json();
|
||||
const { integration, externalId, credentialId, eventTypeId } = selectedCalendarSelectSchema.parse(body);
|
||||
async function postHandler(req: NextRequest) {
|
||||
const user = await authMiddleware();
|
||||
const body = await req.json();
|
||||
const { integration, externalId, credentialId, eventTypeId } = selectedCalendarSelectSchema.parse(body);
|
||||
|
||||
await SelectedCalendarRepository.upsert({
|
||||
await SelectedCalendarRepository.upsert({
|
||||
userId: user.id,
|
||||
integration,
|
||||
externalId,
|
||||
credentialId,
|
||||
eventTypeId: eventTypeId ?? null,
|
||||
});
|
||||
|
||||
return NextResponse.json({ message: "Calendar Selection Saved" });
|
||||
}
|
||||
|
||||
async function deleteHandler(req: NextRequest) {
|
||||
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,
|
||||
integration,
|
||||
externalId,
|
||||
credentialId,
|
||||
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 });
|
||||
}
|
||||
return NextResponse.json({ message: "Calendar Selection Saved" });
|
||||
}
|
||||
|
||||
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 });
|
||||
}
|
||||
}
|
||||
export { deleteHandler as DELETE, postHandler as POST, getHandler as GET };
|
||||
@@ -4,6 +4,7 @@ import type { NextRequest } from "next/server";
|
||||
|
||||
import { getServerSession } from "@calcom/features/auth/lib/getServerSession";
|
||||
import handleCancelBooking from "@calcom/features/bookings/lib/handleCancelBooking";
|
||||
import { apiRouteMiddleware } from "@calcom/lib/server/apiRouteMiddleware";
|
||||
|
||||
import { buildLegacyRequest } from "@lib/buildLegacyCtx";
|
||||
|
||||
@@ -25,10 +26,7 @@ async function handler(req: NextRequest) {
|
||||
return NextResponse.json(result, { status: statusCode });
|
||||
}
|
||||
|
||||
export async function DELETE(req: NextRequest) {
|
||||
return handler(req);
|
||||
}
|
||||
const deleteHandler = apiRouteMiddleware((req: NextRequest) => handler(req));
|
||||
const postHandler = apiRouteMiddleware((req: NextRequest) => handler(req));
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
return handler(req);
|
||||
}
|
||||
export { deleteHandler as DELETE, postHandler as POST };
|
||||
@@ -1,6 +1,7 @@
|
||||
import { cardExamples } from "@pages/api/plain/example-cards";
|
||||
import { createHmac } from "crypto";
|
||||
import { headers } from "next/headers";
|
||||
import type { NextRequest } from "next/server";
|
||||
import { NextResponse } from "next/server";
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -26,7 +27,7 @@ const inputSchema = z.object({
|
||||
cardKeys: z.array(z.string()),
|
||||
});
|
||||
|
||||
async function handler(request: Request) {
|
||||
async function handler(request: NextRequest) {
|
||||
const headersList = headers();
|
||||
const requestBody = await request.json();
|
||||
|
||||
@@ -38,7 +39,7 @@ async function handler(request: Request) {
|
||||
.digest("hex");
|
||||
|
||||
if (incomingSignature !== expectedSignature) {
|
||||
return new Response("Forbidden", { status: 403 });
|
||||
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
||||
}
|
||||
|
||||
// Validate request body
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createHmac } from "crypto";
|
||||
import type { NextRequest } from "next/server";
|
||||
import { NextResponse } from "next/server";
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -14,16 +15,16 @@ const responseSchema = z.object({
|
||||
chatAvatarUrl: z.string(),
|
||||
});
|
||||
|
||||
async function handler(request: Request) {
|
||||
async function handler(request: NextRequest) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const session = await getServerSession({ req: request as any });
|
||||
if (!session?.user?.email) {
|
||||
return new Response("Unauthorized - No session email found", { status: 401 });
|
||||
return NextResponse.json({ error: "Unauthorized - No session email found" }, { status: 401 });
|
||||
}
|
||||
|
||||
const secret = process.env.PLAIN_CHAT_HMAC_SECRET_KEY;
|
||||
if (!secret) {
|
||||
return new Response("Missing Plain Chat secret", { status: 500 });
|
||||
return NextResponse.json({ error: "Missing Plain Chat secret" }, { status: 500 });
|
||||
}
|
||||
|
||||
const hmac = createHmac("sha256", secret);
|
||||
|
||||
@@ -22,82 +22,72 @@ const generateRandomString = () => {
|
||||
return Math.random().toString(36).substring(2, 10);
|
||||
};
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
try {
|
||||
const searchParams = req.nextUrl.searchParams;
|
||||
const { session_id } = querySchema.parse({
|
||||
session_id: searchParams.get("session_id"),
|
||||
async function getHandler(req: NextRequest) {
|
||||
const searchParams = req.nextUrl.searchParams;
|
||||
const { session_id } = querySchema.parse({
|
||||
session_id: searchParams.get("session_id"),
|
||||
});
|
||||
|
||||
const checkoutSession = await stripe.checkout.sessions.retrieve(session_id, {
|
||||
expand: ["subscription"],
|
||||
});
|
||||
if (!checkoutSession) throw new HttpError({ statusCode: 404, message: "Checkout session not found" });
|
||||
|
||||
const subscription = checkoutSession.subscription as Stripe.Subscription;
|
||||
|
||||
if (checkoutSession.payment_status !== "paid")
|
||||
throw new HttpError({ statusCode: 402, message: "Payment required" });
|
||||
|
||||
// Let's query to ensure that the team metadata carried over from the checkout session.
|
||||
const parseCheckoutSessionMetadata = checkoutSessionMetadataSchema.safeParse(checkoutSession.metadata);
|
||||
|
||||
if (!parseCheckoutSessionMetadata.success) {
|
||||
console.error(
|
||||
"Team metadata not found in checkout session",
|
||||
parseCheckoutSessionMetadata.error,
|
||||
checkoutSession.id
|
||||
);
|
||||
}
|
||||
|
||||
if (!checkoutSession.metadata?.userId) {
|
||||
throw new HttpError({
|
||||
statusCode: 400,
|
||||
message: "Can't publish team/org without userId",
|
||||
});
|
||||
}
|
||||
|
||||
const checkoutSession = await stripe.checkout.sessions.retrieve(session_id, {
|
||||
expand: ["subscription"],
|
||||
});
|
||||
if (!checkoutSession) throw new HttpError({ statusCode: 404, message: "Checkout session not found" });
|
||||
const checkoutSessionMetadata = parseCheckoutSessionMetadata.success
|
||||
? parseCheckoutSessionMetadata.data
|
||||
: {
|
||||
teamName: checkoutSession?.metadata?.teamName ?? generateRandomString(),
|
||||
teamSlug: checkoutSession?.metadata?.teamSlug ?? generateRandomString(),
|
||||
userId: checkoutSession.metadata.userId,
|
||||
};
|
||||
|
||||
const subscription = checkoutSession.subscription as Stripe.Subscription;
|
||||
|
||||
if (checkoutSession.payment_status !== "paid")
|
||||
throw new HttpError({ statusCode: 402, message: "Payment required" });
|
||||
|
||||
// Let's query to ensure that the team metadata carried over from the checkout session.
|
||||
const parseCheckoutSessionMetadata = checkoutSessionMetadataSchema.safeParse(checkoutSession.metadata);
|
||||
|
||||
if (!parseCheckoutSessionMetadata.success) {
|
||||
console.error(
|
||||
"Team metadata not found in checkout session",
|
||||
parseCheckoutSessionMetadata.error,
|
||||
checkoutSession.id
|
||||
);
|
||||
}
|
||||
|
||||
if (!checkoutSession.metadata?.userId) {
|
||||
throw new HttpError({
|
||||
statusCode: 400,
|
||||
message: "Can't publish team/org without userId",
|
||||
});
|
||||
}
|
||||
|
||||
const checkoutSessionMetadata = parseCheckoutSessionMetadata.success
|
||||
? parseCheckoutSessionMetadata.data
|
||||
: {
|
||||
teamName: checkoutSession?.metadata?.teamName ?? generateRandomString(),
|
||||
teamSlug: checkoutSession?.metadata?.teamSlug ?? generateRandomString(),
|
||||
userId: checkoutSession.metadata.userId,
|
||||
};
|
||||
|
||||
const team = await prisma.team.create({
|
||||
data: {
|
||||
name: checkoutSessionMetadata.teamName,
|
||||
slug: checkoutSessionMetadata.teamSlug,
|
||||
members: {
|
||||
create: {
|
||||
userId: checkoutSessionMetadata.userId as number,
|
||||
role: MembershipRole.OWNER,
|
||||
accepted: true,
|
||||
},
|
||||
},
|
||||
metadata: {
|
||||
paymentId: checkoutSession.id,
|
||||
subscriptionId: subscription.id || null,
|
||||
subscriptionItemId: subscription.items.data[0].id || null,
|
||||
const team = await prisma.team.create({
|
||||
data: {
|
||||
name: checkoutSessionMetadata.teamName,
|
||||
slug: checkoutSessionMetadata.teamSlug,
|
||||
members: {
|
||||
create: {
|
||||
userId: checkoutSessionMetadata.userId as number,
|
||||
role: MembershipRole.OWNER,
|
||||
accepted: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
metadata: {
|
||||
paymentId: checkoutSession.id,
|
||||
subscriptionId: subscription.id || null,
|
||||
subscriptionItemId: subscription.items.data[0].id || null,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// redirect to team screen
|
||||
return NextResponse.redirect(
|
||||
new URL(`/settings/teams/${team.id}/onboard-members?event=team_created`, req.nextUrl.origin),
|
||||
{ status: 302 }
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof HttpError) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (error instanceof z.ZodError) {
|
||||
return NextResponse.json({ message: "Invalid request data" }, { status: 400 });
|
||||
}
|
||||
|
||||
return NextResponse.json({ message: "Internal server error" }, { status: 500 });
|
||||
}
|
||||
// redirect to team screen
|
||||
return NextResponse.redirect(
|
||||
new URL(`/settings/teams/${team.id}/onboard-members?event=team_created`, req.nextUrl.origin),
|
||||
{ status: 302 }
|
||||
);
|
||||
}
|
||||
|
||||
export { getHandler as GET };
|
||||
@@ -6,7 +6,7 @@ import { NextResponse } from "next/server";
|
||||
import { getServerErrorFromUnknown } from "./getServerErrorFromUnknown";
|
||||
|
||||
export const apiRouteMiddleware =
|
||||
(handler: (req: Request, res?: Response) => Promise<Response>) =>
|
||||
(handler: (req: NextRequest, res?: NextResponse) => Promise<NextResponse>) =>
|
||||
async (req: NextRequest, res: NextResponse) => {
|
||||
try {
|
||||
return await handler(req, res);
|
||||
|
||||
Reference in new issue
Block a user