From 5233dad5f9f9ba3813f17a10092d99c3aef7ed92 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 4 Apr 2022 00:49:05 +0200 Subject: [PATCH] re-unify into one route all id ops for teams and users --- json-schema/json-schema.json | 314 ++++++--------------------------- lib/helpers/httpMethods.ts | 12 ++ lib/helpers/withMiddleware.ts | 3 +- pages/api/teams/[id].ts | 130 ++++++++++++++ pages/api/teams/[id]/delete.ts | 50 ------ pages/api/teams/[id]/edit.ts | 63 ------- pages/api/teams/[id]/index.ts | 51 ------ pages/api/users/[id].ts | 130 ++++++++++++++ pages/api/users/[id]/delete.ts | 50 ------ pages/api/users/[id]/edit.ts | 65 ------- pages/api/users/[id]/index.ts | 51 ------ 11 files changed, 332 insertions(+), 587 deletions(-) create mode 100644 pages/api/teams/[id].ts delete mode 100644 pages/api/teams/[id]/delete.ts delete mode 100644 pages/api/teams/[id]/edit.ts delete mode 100644 pages/api/teams/[id]/index.ts create mode 100644 pages/api/users/[id].ts delete mode 100644 pages/api/users/[id]/delete.ts delete mode 100644 pages/api/users/[id]/edit.ts delete mode 100644 pages/api/users/[id]/index.ts diff --git a/json-schema/json-schema.json b/json-schema/json-schema.json index 220dbd101d..1ae113fddf 100644 --- a/json-schema/json-schema.json +++ b/json-schema/json-schema.json @@ -16,24 +16,14 @@ "description": "@zod.custom(imports.eventTypeSlug)" }, "description": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "position": { "type": "integer", "default": 0 }, "locations": { - "type": [ - "number", - "string", - "boolean", - "object", - "array", - "null" - ], + "type": ["number", "string", "boolean", "object", "array", "null"], "description": "@zod.custom(imports.eventTypeLocations)" }, "length": { @@ -50,10 +40,7 @@ } }, "userId": { - "type": [ - "integer", - "null" - ] + "type": ["integer", "null"] }, "team": { "anyOf": [ @@ -94,10 +81,7 @@ ] }, "eventName": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "customInputs": { "type": "array", @@ -106,45 +90,26 @@ } }, "timeZone": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "periodType": { "type": "string", "default": "UNLIMITED", - "enum": [ - "UNLIMITED", - "ROLLING", - "RANGE" - ] + "enum": ["UNLIMITED", "ROLLING", "RANGE"] }, "periodStartDate": { - "type": [ - "string", - "null" - ], + "type": ["string", "null"], "format": "date-time" }, "periodEndDate": { - "type": [ - "string", - "null" - ], + "type": ["string", "null"], "format": "date-time" }, "periodDays": { - "type": [ - "integer", - "null" - ] + "type": ["integer", "null"] }, "periodCountCalendarDays": { - "type": [ - "boolean", - "null" - ] + "type": ["boolean", "null"] }, "requiresConfirmation": { "type": "boolean", @@ -167,14 +132,8 @@ "default": 0 }, "schedulingType": { - "type": [ - "string", - "null" - ], - "enum": [ - "ROUND_ROBIN", - "COLLECTIVE" - ] + "type": ["string", "null"], + "enum": ["ROUND_ROBIN", "COLLECTIVE"] }, "schedule": { "anyOf": [ @@ -195,20 +154,10 @@ "default": "usd" }, "slotInterval": { - "type": [ - "integer", - "null" - ] + "type": ["integer", "null"] }, "metadata": { - "type": [ - "number", - "string", - "boolean", - "object", - "array", - "null" - ] + "type": ["number", "string", "boolean", "object", "array", "null"] } } }, @@ -222,14 +171,7 @@ "type": "string" }, "key": { - "type": [ - "number", - "string", - "boolean", - "object", - "array", - "null" - ] + "type": ["number", "string", "boolean", "object", "array", "null"] }, "user": { "anyOf": [ @@ -294,45 +236,27 @@ "type": "integer" }, "username": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "name": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "email": { "type": "string", "description": "@zod.email()" }, "emailVerified": { - "type": [ - "string", - "null" - ], + "type": ["string", "null"], "format": "date-time" }, "password": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "bio": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "avatar": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "timeZone": { "type": "string", @@ -359,20 +283,14 @@ "default": false }, "theme": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "createdDate": { "type": "string", "format": "date-time" }, "trialEndsAt": { - "type": [ - "string", - "null" - ], + "type": ["string", "null"], "format": "date-time" }, "eventTypes": { @@ -406,10 +324,7 @@ } }, "defaultScheduleId": { - "type": [ - "integer", - "null" - ] + "type": ["integer", "null"] }, "selectedCalendars": { "type": "array", @@ -422,23 +337,14 @@ "default": false }, "locale": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "timeFormat": { - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "default": 12 }, "twoFactorSecret": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "twoFactorEnabled": { "type": "boolean", @@ -447,17 +353,10 @@ "identityProvider": { "type": "string", "default": "CAL", - "enum": [ - "CAL", - "GOOGLE", - "SAML" - ] + "enum": ["CAL", "GOOGLE", "SAML"] }, "identityProviderId": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "availability": { "type": "array", @@ -466,19 +365,12 @@ } }, "invitedTo": { - "type": [ - "integer", - "null" - ] + "type": ["integer", "null"] }, "plan": { "type": "string", "default": "TRIAL", - "enum": [ - "FREE", - "TRIAL", - "PRO" - ] + "enum": ["FREE", "TRIAL", "PRO"] }, "webhooks": { "type": "array", @@ -509,20 +401,10 @@ "default": false }, "metadata": { - "type": [ - "number", - "string", - "boolean", - "object", - "array", - "null" - ] + "type": ["number", "string", "boolean", "object", "array", "null"] }, "verified": { - "type": [ - "boolean", - "null" - ], + "type": ["boolean", "null"], "default": false }, "apiKeys": { @@ -540,28 +422,16 @@ "type": "integer" }, "name": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "slug": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "logo": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "bio": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "hideBranding": { "type": "boolean", @@ -590,11 +460,7 @@ }, "role": { "type": "string", - "enum": [ - "MEMBER", - "ADMIN", - "OWNER" - ] + "enum": ["MEMBER", "ADMIN", "OWNER"] }, "team": { "$ref": "#/definitions/Team" @@ -643,22 +509,13 @@ "type": "string" }, "meetingId": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "meetingPassword": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "meetingUrl": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "booking": { "anyOf": [ @@ -688,10 +545,7 @@ "type": "string" }, "locale": { - "type": [ - "string", - "null" - ], + "type": ["string", "null"], "default": "en" }, "booking": { @@ -771,10 +625,7 @@ "type": "string" }, "description": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "startTime": { "type": "string", @@ -791,10 +642,7 @@ } }, "location": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "dailyRef": { "anyOf": [ @@ -811,10 +659,7 @@ "format": "date-time" }, "updatedAt": { - "type": [ - "string", - "null" - ], + "type": ["string", "null"], "format": "date-time" }, "confirmed": { @@ -828,12 +673,7 @@ "status": { "type": "string", "default": "ACCEPTED", - "enum": [ - "CANCELLED", - "ACCEPTED", - "REJECTED", - "PENDING" - ] + "enum": ["CANCELLED", "ACCEPTED", "REJECTED", "PENDING"] }, "paid": { "type": "boolean", @@ -856,16 +696,10 @@ ] }, "cancellationReason": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "rejectionReason": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } } }, @@ -892,10 +726,7 @@ "type": "string" }, "timeZone": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "availability": { "type": "array", @@ -946,10 +777,7 @@ "format": "date-time" }, "date": { - "type": [ - "string", - "null" - ], + "type": ["string", "null"], "format": "date-time" }, "Schedule": { @@ -992,12 +820,7 @@ }, "type": { "type": "string", - "enum": [ - "TEXT", - "TEXTLONG", - "NUMBER", - "BOOL" - ] + "enum": ["TEXT", "TEXTLONG", "NUMBER", "BOOL"] }, "required": { "type": "boolean" @@ -1042,9 +865,7 @@ }, "reminderType": { "type": "string", - "enum": [ - "PENDING_BOOKING_CONFIRMATION" - ] + "enum": ["PENDING_BOOKING_CONFIRMATION"] }, "elapsedMinutes": { "type": "integer" @@ -1066,9 +887,7 @@ }, "type": { "type": "string", - "enum": [ - "STRIPE" - ] + "enum": ["STRIPE"] }, "booking": { "anyOf": [ @@ -1096,14 +915,7 @@ "type": "boolean" }, "data": { - "type": [ - "number", - "string", - "boolean", - "object", - "array", - "null" - ] + "type": ["number", "string", "boolean", "object", "array", "null"] }, "externalId": { "type": "string" @@ -1120,10 +932,7 @@ "type": "string" }, "payloadTemplate": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "createdAt": { "type": "string", @@ -1135,11 +944,7 @@ }, "eventTriggers": { "type": "array", - "enum": [ - "BOOKING_CREATED", - "BOOKING_RESCHEDULED", - "BOOKING_CANCELLED" - ] + "enum": ["BOOKING_CREATED", "BOOKING_RESCHEDULED", "BOOKING_CANCELLED"] }, "user": { "anyOf": [ @@ -1188,10 +993,7 @@ "format": "date-time" }, "note": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } } } @@ -1259,4 +1061,4 @@ "$ref": "#/definitions/ApiKey" } } -} \ No newline at end of file +} diff --git a/lib/helpers/httpMethods.ts b/lib/helpers/httpMethods.ts index d19102d4dc..1454355f3a 100644 --- a/lib/helpers/httpMethods.ts +++ b/lib/helpers/httpMethods.ts @@ -11,7 +11,19 @@ export const httpMethod = (allowedHttpMethod: "GET" | "POST" | "PATCH" | "DELETE }; }; +export const httpMethods = (allowedHttpMethod: string[]): NextMiddleware => { + return async function (req, res, next) { + if (allowedHttpMethod.map((method) => method === req.method)) { + await next(); + } else { + res.status(405).json({ message: `Only ${allowedHttpMethod} Method allowed` }); + res.end(); + } + }; +}; + export const HTTP_POST = httpMethod("POST"); export const HTTP_GET = httpMethod("GET"); export const HTTP_PATCH = httpMethod("PATCH"); export const HTTP_DELETE = httpMethod("DELETE"); +export const HTTP_GET_DELETE_PATCH = httpMethods(["GET", "DELETE", "PATCH"]); diff --git a/lib/helpers/withMiddleware.ts b/lib/helpers/withMiddleware.ts index e15c388d51..4171fa774f 100644 --- a/lib/helpers/withMiddleware.ts +++ b/lib/helpers/withMiddleware.ts @@ -2,11 +2,12 @@ import { label } from "next-api-middleware"; import { addRequestId } from "./addRequestid"; import { captureErrors } from "./captureErrors"; -import { HTTP_POST, HTTP_DELETE, HTTP_PATCH, HTTP_GET } from "./httpMethods"; +import { HTTP_POST, HTTP_DELETE, HTTP_PATCH, HTTP_GET, HTTP_GET_DELETE_PATCH } from "./httpMethods"; import { verifyApiKey } from "./verifyApiKey"; const withMiddleware = label( { + HTTP_GET_DELETE_PATCH, HTTP_GET, HTTP_PATCH, HTTP_POST, diff --git a/pages/api/teams/[id].ts b/pages/api/teams/[id].ts new file mode 100644 index 0000000000..49895d6937 --- /dev/null +++ b/pages/api/teams/[id].ts @@ -0,0 +1,130 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { TeamResponse } from "@lib/types"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; + +/** + * @swagger + * /api/teams/{id}: + * get: + * summary: Get a team by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the team to get + * tags: + * - teams + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Team was not found + * patch: + * summary: Edit an existing team + * consumes: + * - application/json + * parameters: + * - in: body + * name: team + * description: The team to edit + * schema: + * type: object + * $ref: '#/components/schemas/Team' + * required: true + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the team to edit + * tags: + * - teams + * responses: + * 201: + * description: OK, team edited successfuly + * model: Team + * 400: + * description: Bad request. Team body is invalid. + * 401: + * description: Authorization information is missing or invalid. + * delete: + * summary: Remove an existing team + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the team to delete + * tags: + * - teams + * responses: + * 201: + * description: OK, team removed successfuly + * model: Team + * 400: + * description: Bad request. Team id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function teamById(req: NextApiRequest, res: NextApiResponse) { + const { method, query, body } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaTeamBodyParams.safeParse(body); + if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + + switch (method) { + case "GET": + await prisma.team + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data) => schemaTeamPublic.parse(data)) + .then((data: TeamResponse) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `Team with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "PATCH": + if (!safeBody.success) throw new Error("Invalid request body"); + await prisma.team + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((team) => schemaTeamPublic.parse(team)) + .then((data: TeamResponse) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `Team with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "DELETE": + await prisma.team + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ message: `Team with id: ${safeQuery.data.id} deleted successfully` }) + ) + .catch((error: Error) => + res.status(404).json({ message: `Team with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } +} + +export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(teamById)); diff --git a/pages/api/teams/[id]/delete.ts b/pages/api/teams/[id]/delete.ts deleted file mode 100644 index 0b493f3fc5..0000000000 --- a/pages/api/teams/[id]/delete.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BaseResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/teams/{id}/delete: - * delete: - * summary: Remove an existing team - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the team to remove - * tags: - * - teams - * responses: - * 201: - * description: OK, team removed successfuly - * model: Team - * 400: - * description: Bad request. Team id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function deleteTeam(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query", safe.error); - - const data = await prisma.team.delete({ where: { id: safe.data.id } }); - - if (data) res.status(200).json({ message: `Team with id: ${safe.data.id} deleted successfully` }); - else - (error: Error) => - res.status(400).json({ - message: `Team with id: ${safe.data.id} was not able to be processed`, - error, - }); -} - -export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteTeam)); diff --git a/pages/api/teams/[id]/edit.ts b/pages/api/teams/[id]/edit.ts deleted file mode 100644 index 9791e37046..0000000000 --- a/pages/api/teams/[id]/edit.ts +++ /dev/null @@ -1,63 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { TeamResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; -import { schemaTeamBodyParams, schemaTeamPublic, withValidTeam } from "@lib/validations/team"; - -/** - * @swagger - * /api/teams/{id}/edit: - * patch: - * summary: Edits an existing team - * consumes: - * - application/json - * parameters: - * - in: body - * name: team - * description: The team to edit - * schema: Team - * required: true - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the team to edit - * tags: - * - teams - * responses: - * 201: - * description: OK, team edited successfuly - * model: Team - * 400: - * description: Bad request. Team body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function editTeam(req: NextApiRequest, res: NextApiResponse) { - const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); - const safeBody = await schemaTeamBodyParams.safeParse(req.body); - - if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); - const team = await prisma.team.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - const data = schemaTeamPublic.parse(team); - - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, - error, - }); -} - -export default withMiddleware("HTTP_PATCH")(withValidQueryIdTransformParseInt(withValidTeam(editTeam))); diff --git a/pages/api/teams/[id]/index.ts b/pages/api/teams/[id]/index.ts deleted file mode 100644 index 62765e544d..0000000000 --- a/pages/api/teams/[id]/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { TeamResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; -import { schemaTeamPublic } from "@lib/validations/team"; - -/** - * @swagger - * /api/teams/{id}: - * get: - * summary: find team by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the team to get - * tags: - * - teams - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Team was not found - */ -export async function teamById(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query"); - - const team = await prisma.team.findUnique({ where: { id: safe.data.id } }); - const data = schemaTeamPublic.parse(team); - - if (team) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "Team was not found", - error, - }); -} - -export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(teamById)); diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts new file mode 100644 index 0000000000..35adf9fa08 --- /dev/null +++ b/pages/api/users/[id].ts @@ -0,0 +1,130 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { UserResponse } from "@lib/types"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaUserBodyParams, schemaUserPublic } from "@lib/validations/user"; + +/** + * @swagger + * /api/users/{id}: + * get: + * summary: Get a user by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the user to get + * tags: + * - users + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: User was not found + * patch: + * summary: Edit an existing user + * consumes: + * - application/json + * parameters: + * - in: body + * name: user + * description: The user to edit + * schema: + * type: object + * $ref: '#/components/schemas/User' + * required: true + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the user to edit + * tags: + * - users + * responses: + * 201: + * description: OK, user edited successfuly + * model: User + * 400: + * description: Bad request. User body is invalid. + * 401: + * description: Authorization information is missing or invalid. + * delete: + * summary: Remove an existing user + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the user to delete + * tags: + * - users + * responses: + * 201: + * description: OK, user removed successfuly + * model: User + * 400: + * description: Bad request. User id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function userById(req: NextApiRequest, res: NextApiResponse) { + const { method, query, body } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaUserBodyParams.safeParse(body); + if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + + switch (method) { + case "GET": + await prisma.user + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data: UserResponse) => schemaUserPublic.parse(data)) + .then((data: UserResponse) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "PATCH": + if (!safeBody.success) throw new Error("Invalid request body"); + await prisma.user + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((user) => schemaUserPublic.parse(user)) + .then((data: UserResponse) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "DELETE": + await prisma.user + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ message: `User with id: ${safeQuery.data.id} deleted successfully` }) + ) + .catch((error: Error) => + res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } +} + +export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(userById)); diff --git a/pages/api/users/[id]/delete.ts b/pages/api/users/[id]/delete.ts deleted file mode 100644 index b484d2cae5..0000000000 --- a/pages/api/users/[id]/delete.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BaseResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/users/{id}/delete: - * delete: - * summary: Remove an existing user - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the user to delete - * tags: - * - users - * responses: - * 201: - * description: OK, user removed successfuly - * model: User - * 400: - * description: Bad request. User id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function deleteUser(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query", safe.error); - - const data = await prisma.user.delete({ where: { id: safe.data.id } }); - - if (data) res.status(200).json({ message: `User with id: ${safe.data.id} deleted successfully` }); - else - (error: Error) => - res.status(400).json({ - message: `User with id: ${safe.data.id} was not able to be processed`, - error, - }); -} - -export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteUser)); diff --git a/pages/api/users/[id]/edit.ts b/pages/api/users/[id]/edit.ts deleted file mode 100644 index 7ebf00517e..0000000000 --- a/pages/api/users/[id]/edit.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { UserResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; -import { schemaUserBodyParams, schemaUserPublic, withValidUser } from "@lib/validations/user"; - -/** - * @swagger - * /api/users/{id}/edit: - * patch: - * summary: Edit an existing user - * consumes: - * - application/json - * parameters: - * - in: body - * name: user - * description: The user to edit - * schema: - * type: object - * $ref: '#/components/schemas/User' - * required: true - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the user to edit - * tags: - * - users - * responses: - * 201: - * description: OK, user edited successfuly - * model: User - * 400: - * description: Bad request. User body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function editUser(req: NextApiRequest, res: NextApiResponse) { - const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); - const safeBody = await schemaUserBodyParams.safeParse(req.body); - - if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); - const user = await prisma.user.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - const data = schemaUserPublic.parse(user); - - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, - error, - }); -} - -export default withMiddleware("HTTP_PATCH")(withValidQueryIdTransformParseInt(withValidUser(editUser))); diff --git a/pages/api/users/[id]/index.ts b/pages/api/users/[id]/index.ts deleted file mode 100644 index c9ef417223..0000000000 --- a/pages/api/users/[id]/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { UserResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; -import { schemaUserPublic } from "@lib/validations/user"; - -/** - * @swagger - * /api/users/{id}: - * get: - * summary: Get a user by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the user to get - * tags: - * - users - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: User was not found - */ -export async function userById(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query"); - - const user = await prisma.user.findUnique({ where: { id: safe.data.id } }); - const data = schemaUserPublic.parse(user); - - if (user) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "User was not found", - error, - }); -} - -export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(userById));