diff --git a/lib/validations/shared/queryUserId.ts b/lib/validations/shared/queryUserId.ts new file mode 100644 index 0000000000..cbe6e282d2 --- /dev/null +++ b/lib/validations/shared/queryUserId.ts @@ -0,0 +1,15 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +import { baseApiParams } from "./baseApiParams"; + +// Extracted out as utility function so can be reused +// at different endpoints that require this validation. +export const schemaQueryUserId = baseApiParams + .extend({ + userId: z + .string() + .regex(/^\d+$/) + .transform((id) => parseInt(id)), + }) + .strict(); diff --git a/pages/api/availability/_get.ts b/pages/api/availability/_get.ts index 21450f005e..5289190c03 100644 --- a/pages/api/availability/_get.ts +++ b/pages/api/availability/_get.ts @@ -7,7 +7,7 @@ import { stringOrNumber } from "@calcom/prisma/zod-utils"; const availabilitySchema = z .object({ - userId: stringOrNumber.optional(), + userId: stringOrNumber, username: z.string().optional(), dateFrom: z.string(), dateTo: z.string(), diff --git a/pages/api/users/[id]/_delete.ts b/pages/api/users/[userId]/_delete.ts similarity index 84% rename from pages/api/users/[id]/_delete.ts rename to pages/api/users/[userId]/_delete.ts index 7d38d07372..3478c44789 100644 --- a/pages/api/users/[id]/_delete.ts +++ b/pages/api/users/[userId]/_delete.ts @@ -5,7 +5,7 @@ import { defaultResponder } from "@calcom/lib/server"; import prisma from "@calcom/prisma"; import { isAdminGuard } from "@lib/utils/isAdmin"; -import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryUserId } from "@lib/validations/shared/queryUserId"; /** * @swagger @@ -32,10 +32,11 @@ import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformP * description: Authorization information is missing or invalid. */ export async function deleteHandler(req: NextApiRequest) { - const query = schemaQueryIdParseInt.parse(req.query); + const query = schemaQueryUserId.parse(req.query); const isAdmin = await isAdminGuard(req.userId); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user - if (!isAdmin && query.id !== req.userId) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + if (!isAdmin && query.userId !== req.userId) + throw new HttpError({ statusCode: 401, message: "Unauthorized" }); const user = await prisma.user.findUnique({ where: { id: query.id } }); if (!user) throw new HttpError({ statusCode: 404, message: "User not found" }); diff --git a/pages/api/users/[id]/_get.ts b/pages/api/users/[userId]/_get.ts similarity index 82% rename from pages/api/users/[id]/_get.ts rename to pages/api/users/[userId]/_get.ts index 443b935e9c..5c76c4e315 100644 --- a/pages/api/users/[id]/_get.ts +++ b/pages/api/users/[userId]/_get.ts @@ -5,7 +5,7 @@ import { defaultResponder } from "@calcom/lib/server"; import prisma from "@calcom/prisma"; import { isAdminGuard } from "@lib/utils/isAdmin"; -import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryUserId } from "@lib/validations/shared/queryUserId"; import { schemaUserReadPublic } from "@lib/validations/user"; /** @@ -33,11 +33,12 @@ import { schemaUserReadPublic } from "@lib/validations/user"; * description: User was not found */ export async function getHandler(req: NextApiRequest) { - const query = schemaQueryIdParseInt.parse(req.query); + const query = schemaQueryUserId.parse(req.query); const isAdmin = await isAdminGuard(req.userId); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user - if (!isAdmin && query.id !== req.userId) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); - const data = await prisma.user.findUnique({ where: { id: query.id } }); + if (!isAdmin && query.userId !== req.userId) + throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + const data = await prisma.user.findUnique({ where: { id: query.userId } }); const user = schemaUserReadPublic.parse(data); return { user }; } diff --git a/pages/api/users/[id]/_patch.ts b/pages/api/users/[userId]/_patch.ts similarity index 90% rename from pages/api/users/[id]/_patch.ts rename to pages/api/users/[userId]/_patch.ts index a6551609e7..9f32e920c4 100644 --- a/pages/api/users/[id]/_patch.ts +++ b/pages/api/users/[userId]/_patch.ts @@ -5,7 +5,7 @@ import { defaultResponder } from "@calcom/lib/server"; import prisma from "@calcom/prisma"; import { isAdminGuard } from "@lib/utils/isAdmin"; -import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryUserId } from "@lib/validations/shared/queryUserId"; import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations/user"; /** @@ -54,10 +54,11 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations * description: Authorization information is missing or invalid. */ export async function patchHandler(req: NextApiRequest) { - const query = schemaQueryIdParseInt.parse(req.query); + const query = schemaQueryUserId.parse(req.query); const isAdmin = await isAdminGuard(req.userId); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user - if (!isAdmin && query.id !== req.userId) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + if (!isAdmin && query.userId !== req.userId) + throw new HttpError({ statusCode: 401, message: "Unauthorized" }); const body = schemaUserEditBodyParams.parse(req.body); const userSchedules = await prisma.schedule.findMany({ diff --git a/pages/api/users/[userId]/availability/index.ts b/pages/api/users/[userId]/availability/index.ts new file mode 100644 index 0000000000..1a27360f81 --- /dev/null +++ b/pages/api/users/[userId]/availability/index.ts @@ -0,0 +1,9 @@ +import { defaultHandler } from "@calcom/lib/server"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; + +export default withMiddleware("HTTP_GET")( + defaultHandler({ + GET: import("@api/availability/_get"), + }) +); diff --git a/pages/api/users/[id]/index.ts b/pages/api/users/[userId]/index.ts similarity index 100% rename from pages/api/users/[id]/index.ts rename to pages/api/users/[userId]/index.ts