From 1c19032884c768ec37e4d8b4814a0fd7cedb819b Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 1 Apr 2022 23:03:03 +0200 Subject: [PATCH] chore: bring up to date booking references, bookings, and credentials --- lib/types.ts | 1 + lib/validations/booking-reference.ts | 12 +++- lib/validations/booking.ts | 4 +- lib/validations/credential.ts | 14 +++- lib/validations/shared/jsonSchema.ts | 9 +++ pages/api/booking-references/[id]/delete.ts | 56 ++++++++++----- pages/api/booking-references/[id]/edit.ts | 77 ++++++++++++++------- pages/api/booking-references/[id]/index.ts | 57 ++++++++++----- pages/api/booking-references/index.ts | 40 ++++++++--- pages/api/booking-references/new.ts | 64 +++++++++++------ pages/api/bookings/[id]/delete.ts | 55 ++++++++++----- pages/api/bookings/[id]/edit.ts | 75 +++++++++++--------- pages/api/bookings/[id]/index.ts | 57 ++++++++++----- pages/api/bookings/index.ts | 44 ++++++++---- pages/api/bookings/new.ts | 3 +- pages/api/credentials/[id]/delete.ts | 55 ++++++++++----- pages/api/credentials/[id]/edit.ts | 74 +++++++++++++------- pages/api/credentials/[id]/index.ts | 54 ++++++++++----- pages/api/credentials/index.ts | 38 +++++++--- pages/api/credentials/new.ts | 62 ++++++++++++----- 20 files changed, 593 insertions(+), 258 deletions(-) create mode 100644 lib/validations/shared/jsonSchema.ts diff --git a/lib/types.ts b/lib/types.ts index cec3f65c0b..806f84b18f 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -2,6 +2,7 @@ import { User, ApiKey, Team, + Credential, SelectedCalendar, EventType, Attendee, diff --git a/lib/validations/booking-reference.ts b/lib/validations/booking-reference.ts index c73be296bc..75a7d95f0c 100644 --- a/lib/validations/booking-reference.ts +++ b/lib/validations/booking-reference.ts @@ -1,11 +1,21 @@ import { withValidation } from "next-validations"; +import { z } from "zod"; import { _BookingReferenceModel as BookingReference } from "@calcom/prisma/zod"; -export const schemaBookingReferenceBodyParams = BookingReference.omit({ id: true }); +export const schemaBookingReferenceBaseBodyParams = BookingReference.omit({ id: true }).partial(); export const schemaBookingReferencePublic = BookingReference.omit({}); +const schemaBookingReferenceRequiredParams = z.object({ + type: z.string(), + uid: z.string(), +}); + +export const schemaBookingReferenceBodyParams = schemaBookingReferenceBaseBodyParams.merge( + schemaBookingReferenceRequiredParams +); + export const withValidBookingReference = withValidation({ schema: schemaBookingReferenceBodyParams, type: "Zod", diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index df5293e053..77eca1d156 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -3,10 +3,8 @@ import { z } from "zod"; import { _BookingModel as Booking } from "@calcom/prisma/zod"; -// Here we remove any parameters that are not needed for the API with omit. const schemaBookingBaseBodyParams = Booking.omit({ id: true }).partial(); -// Here we redeclare the required ones after removing the ones we don't need. -// and making the rest optional with .partial() + const schemaBookingRequiredParams = z.object({ uid: z.string(), title: z.string(), diff --git a/lib/validations/credential.ts b/lib/validations/credential.ts index 001e4870f6..9397ef2577 100644 --- a/lib/validations/credential.ts +++ b/lib/validations/credential.ts @@ -1,8 +1,20 @@ import { withValidation } from "next-validations"; +import { z } from "zod"; import { _CredentialModel as Credential } from "@calcom/prisma/zod"; -export const schemaCredentialBodyParams = Credential.omit({ id: true }); +import { jsonSchema } from "./shared/jsonSchema"; + +const schemaCredentialBaseBodyParams = Credential.omit({ id: true, userId: true }).partial(); + +const schemaCredentialRequiredParams = z.object({ + type: z.string(), + key: jsonSchema, +}); + +export const schemaCredentialBodyParams = schemaCredentialBaseBodyParams.merge( + schemaCredentialRequiredParams +); export const schemaCredentialPublic = Credential.omit({}); diff --git a/lib/validations/shared/jsonSchema.ts b/lib/validations/shared/jsonSchema.ts new file mode 100644 index 0000000000..bfc7ae1f2b --- /dev/null +++ b/lib/validations/shared/jsonSchema.ts @@ -0,0 +1,9 @@ +import { z } from "zod"; + +// Helper schema for JSON fields +type Literal = boolean | number | string; +type Json = Literal | { [key: string]: Json } | Json[]; +const literalSchema = z.union([z.string(), z.number(), z.boolean()]); +export const jsonSchema: z.ZodSchema = z.lazy(() => + z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)]) +); diff --git a/pages/api/booking-references/[id]/delete.ts b/pages/api/booking-references/[id]/delete.ts index 6f7685854f..0a49d82d21 100644 --- a/pages/api/booking-references/[id]/delete.ts +++ b/pages/api/booking-references/[id]/delete.ts @@ -2,28 +2,50 @@ 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"; -type ResponseData = { - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/booking-references/{id}/delete: + * delete: + * summary: Remove an existing bookingReference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the bookingReference to delete + * tags: + * - bookingReferences + * responses: + * 201: + * description: OK, bookingReference removed successfuly + * model: BookingReference + * 400: + * description: Bad request. BookingReference id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteBookingReference(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query", safe.error); -export async function deleteBookingReference(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const bookingReference = await prisma.bookingReference.delete({ where: { id: safe.data.id } }); - // We only remove the bookingReference type from the database if there's an existing resource. - if (bookingReference) - res.status(200).json({ message: `bookingReference with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.bookingReference.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found` }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only DELETE Method allowed" }); + const data = await prisma.bookingReference.delete({ where: { id: safe.data.id } }); + + if (data) + res.status(200).json({ message: `BookingReference with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `BookingReference with id: ${safe.data.id} was not able to be processed`, + error, + }); } -export default withValidQueryIdTransformParseInt(deleteBookingReference); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteBookingReference)); diff --git a/pages/api/booking-references/[id]/edit.ts b/pages/api/booking-references/[id]/edit.ts index b1ecfcee35..3d05537514 100644 --- a/pages/api/booking-references/[id]/edit.ts +++ b/pages/api/booking-references/[id]/edit.ts @@ -1,38 +1,65 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { BookingReference } from "@calcom/prisma/client"; -import { schemaBookingReference, withValidBookingReference } from "@lib/validations/booking-reference"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BookingReferenceResponse } from "@lib/types"; +import { + schemaBookingReferenceBodyParams, + schemaBookingReferencePublic, + withValidBookingReference, +} from "@lib/validations/booking-reference"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: BookingReference; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/booking-references/{id}/edit: + * patch: + * summary: Edit an existing bookingReference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the bookingReference to edit + * tags: + * - bookingReferences + * responses: + * 201: + * description: OK, bookingReference edited successfuly + * model: BookingReference + * 400: + * description: Bad request. BookingReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editBookingReference( + req: NextApiRequest, + res: NextApiResponse +) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaBookingReferenceBodyParams.safeParse(req.body); -export async function editBookingReference(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaBookingReference.safeParse(body); + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const bookingReference = await prisma.bookingReference.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaBookingReferencePublic.parse(bookingReference); - if (method === "PATCH" && safeQuery.success && safeBody.success) { - const data = await prisma.bookingReference.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - if (data) res.status(200).json({ data }); - else - res - .status(404) - .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated` }); - - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only PATCH Method allowed for updating bookingReferences" }); + 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 withValidQueryIdTransformParseInt(withValidBookingReference(editBookingReference)); +export default withMiddleware("HTTP_PATCH")( + withValidQueryIdTransformParseInt(withValidBookingReference(editBookingReference)) +); diff --git a/pages/api/booking-references/[id]/index.ts b/pages/api/booking-references/[id]/index.ts index 4e8483b797..ee6f7c8e84 100644 --- a/pages/api/booking-references/[id]/index.ts +++ b/pages/api/booking-references/[id]/index.ts @@ -1,29 +1,54 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { BookingReference } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BookingReferenceResponse } from "@lib/types"; +import { schemaBookingReferencePublic } from "@lib/validations/booking-reference"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: BookingReference; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/booking-references/{id}: + * get: + * summary: Get a bookingReference by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the bookingReference to get + * tags: + * - bookingReferences + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: BookingReference was not found + */ +export async function bookingReferenceById( + req: NextApiRequest, + res: NextApiResponse +) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); -export async function bookingReference(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "GET" && safe.success) { - const data = await prisma.bookingReference.findUnique({ where: { id: safe.data.id } }); + const bookingReference = await prisma.bookingReference.findUnique({ where: { id: safe.data.id } }); + const data = schemaBookingReferencePublic.parse(bookingReference); - if (data) res.status(200).json({ data }); - else res.status(404).json({ message: "Event type not found" }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only GET Method allowed" }); + if (bookingReference) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "BookingReference was not found", + error, + }); } -export default withValidQueryIdTransformParseInt(bookingReference); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(bookingReferenceById)); diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index f0244da6bb..c1c4afc9dc 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -1,15 +1,39 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { BookingReference } from "@calcom/prisma/client"; -type ResponseData = { - data?: BookingReference[]; - error?: unknown; -}; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { BookingReferencesResponse } from "@lib/types"; +import { schemaBookingReferencePublic } from "@lib/validations/booking-reference"; + +/** + * @swagger + * /api/booking-references: + * get: + * summary: Get all bookingReferences + * tags: + * - bookingReferences + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No bookingReferences were found + */ +async function allBookingReferences(_: NextApiRequest, res: NextApiResponse) { + const bookingReferences = await prisma.bookingReference.findMany(); + const data = bookingReferences.map((bookingReference) => + schemaBookingReferencePublic.parse(bookingReference) + ); -export default async function bookingReference(req: NextApiRequest, res: NextApiResponse) { - const data = await prisma.bookingReference.findMany(); if (data) res.status(200).json({ data }); - else res.status(400).json({ error: "No data found" }); + else + (error: Error) => + res.status(404).json({ + message: "No BookingReferences were found", + error, + }); } + +export default withMiddleware("HTTP_GET")(allBookingReferences); diff --git a/pages/api/booking-references/new.ts b/pages/api/booking-references/new.ts index 319e80404e..5430206cde 100644 --- a/pages/api/booking-references/new.ts +++ b/pages/api/booking-references/new.ts @@ -1,28 +1,52 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { BookingReference } from "@calcom/prisma/client"; -import { schemaBookingReference, withValidBookingReference } from "@lib/validations/booking-reference"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BookingReferenceResponse } from "@lib/types"; +import { + schemaBookingReferenceBodyParams, + schemaBookingReferencePublic, + withValidBookingReference, +} from "@lib/validations/booking-reference"; -type ResponseData = { - data?: BookingReference; - message?: string; - error?: string; -}; +/** + * @swagger + * /api/booking-references/new: + * post: + * summary: Creates a new bookingReference + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/BookingReference' + * tags: + * - bookingReferences + * responses: + * 201: + * description: OK, bookingReference created + * model: BookingReference + * 400: + * description: Bad request. BookingReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createBookingReference(req: NextApiRequest, res: NextApiResponse) { + const safe = schemaBookingReferenceBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -async function createBookingReference(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - const safe = schemaBookingReference.safeParse(body); - if (method === "POST" && safe.success) { - await prisma.bookingReference - .create({ data: safe.data }) - .then((data) => res.status(201).json({ data })) - .catch((error) => - res.status(400).json({ message: "Could not create bookingReference type", error: error }) - ); - // Reject any other HTTP method than POST - } else res.status(405).json({ error: "Only POST Method allowed" }); + const bookingReference = await prisma.bookingReference.create({ data: safe.data }); + const data = schemaBookingReferencePublic.parse(bookingReference); + + if (data) res.status(201).json({ data, message: "BookingReference created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new bookingReference", + error, + }); } -export default withValidBookingReference(createBookingReference); +export default withMiddleware("HTTP_POST")(withValidBookingReference(createBookingReference)); diff --git a/pages/api/bookings/[id]/delete.ts b/pages/api/bookings/[id]/delete.ts index a2dad90c7e..5d6e58d656 100644 --- a/pages/api/bookings/[id]/delete.ts +++ b/pages/api/bookings/[id]/delete.ts @@ -2,28 +2,49 @@ 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"; -type ResponseData = { - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/bookings/{id}/delete: + * delete: + * summary: Remove an existing booking + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the booking to delete + * tags: + * - bookings + * responses: + * 201: + * description: OK, booking removed successfuly + * model: Booking + * 400: + * description: Bad request. Booking id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteBooking(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query", safe.error); -export async function deleteBooking(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const booking = await prisma.booking.delete({ where: { id: safe.data.id } }); - // We only remove the booking type from the database if there's an existing resource. - if (booking) res.status(200).json({ message: `booking with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.booking.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found` }); - // Reject any other HTTP method than POST - } else - res.status(405).json({ message: "Only DELETE Method allowed in /availabilities/[id]/delete endpoint" }); + const data = await prisma.booking.delete({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ message: `Booking with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `Booking with id: ${safe.data.id} was not able to be processed`, + error, + }); } -export default withValidQueryIdTransformParseInt(deleteBooking); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteBooking)); diff --git a/pages/api/bookings/[id]/edit.ts b/pages/api/bookings/[id]/edit.ts index d74a512cd9..3e12bdaa86 100644 --- a/pages/api/bookings/[id]/edit.ts +++ b/pages/api/bookings/[id]/edit.ts @@ -1,45 +1,56 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Booking } from "@calcom/prisma/client"; -import { schemaBooking, withValidBooking } from "@lib/validations/booking"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BookingResponse } from "@lib/types"; +import { schemaBookingBodyParams, schemaBookingPublic, withValidBooking } from "@lib/validations/booking"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: Booking; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/bookings/{id}/edit: + * patch: + * summary: Edit an existing booking + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the booking to edit + * tags: + * - bookings + * responses: + * 201: + * description: OK, booking edited successfuly + * model: Booking + * 400: + * description: Bad request. Booking body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editBooking(req: NextApiRequest, res: NextApiResponse) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaBookingBodyParams.safeParse(req.body); -export async function editBooking(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaBooking.safeParse(body); + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const booking = await prisma.booking.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaBookingPublic.parse(booking); - if (method === "PATCH") { - if (safeQuery.success && safeBody.success) { - await prisma.booking - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((booking) => { - res.status(200).json({ data: booking }); - }) - .catch((error) => { - res - .status(404) - .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); - }); - } - } else { - // Reject any other HTTP method than POST - res.status(405).json({ message: "Only PATCH Method allowed for updating bookings" }); - } + 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 withValidQueryIdTransformParseInt(withValidBooking(editBooking)); +export default withMiddleware("HTTP_PATCH")(withValidQueryIdTransformParseInt(withValidBooking(editBooking))); diff --git a/pages/api/bookings/[id]/index.ts b/pages/api/bookings/[id]/index.ts index 8311dea842..fab8940978 100644 --- a/pages/api/bookings/[id]/index.ts +++ b/pages/api/bookings/[id]/index.ts @@ -1,32 +1,51 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Booking } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BookingResponse } from "@lib/types"; +import { schemaBookingPublic } from "@lib/validations/booking"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: Booking; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/bookings/{id}: + * get: + * summary: Get a booking by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the booking to get + * tags: + * - bookings + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Booking was not found + */ +export async function bookingById(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); -export async function booking(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); + const booking = await prisma.booking.findUnique({ where: { id: safe.data.id } }); + const data = schemaBookingPublic.parse(booking); - if (method === "GET" && safe.success) { - const booking = await prisma.booking.findUnique({ where: { id: safe.data.id } }); - - if (booking) res.status(200).json({ data: booking }); - if (!booking) res.status(404).json({ message: "Event type not found" }); - } else { - // Reject any other HTTP method than POST - res.status(405).json({ message: "Only GET Method allowed" }); - } + if (booking) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "Booking was not found", + error, + }); } -export default withValidQueryIdTransformParseInt(booking); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(bookingById)); diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index d99dc318bd..f2d724071c 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -1,19 +1,37 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Booking } from "@calcom/prisma/client"; -type ResponseData = { - data?: Booking[]; - error?: unknown; -}; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { BookingsResponse } from "@lib/types"; +import { schemaBookingPublic } from "@lib/validations/booking"; -export default async function booking(req: NextApiRequest, res: NextApiResponse) { - try { - const data = await prisma.booking.findMany(); - res.status(200).json({ data }); - } catch (error) { - // FIXME: Add zod for validation/error handling - res.status(400).json({ error: error }); - } +/** + * @swagger + * /api/bookings: + * get: + * summary: Get all bookings + * tags: + * - bookings + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No bookings were found + */ +async function allBookings(_: NextApiRequest, res: NextApiResponse) { + const bookings = await prisma.booking.findMany(); + const data = bookings.map((booking) => schemaBookingPublic.parse(booking)); + + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "No Bookings were found", + error, + }); } + +export default withMiddleware("HTTP_GET")(allBookings); diff --git a/pages/api/bookings/new.ts b/pages/api/bookings/new.ts index fcc5f89efc..4e62b0e531 100644 --- a/pages/api/bookings/new.ts +++ b/pages/api/bookings/new.ts @@ -2,7 +2,6 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { withCost } from "@lib/helpers/withCost"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { BookingResponse } from "@lib/types"; import { schemaBookingBodyParams, schemaBookingPublic, withValidBooking } from "@lib/validations/booking"; @@ -46,4 +45,4 @@ async function createBooking(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query", safe.error); -export async function deleteCredential(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const credential = await prisma.credential.delete({ where: { id: safe.data.id } }); - // We only remove the credential type from the database if there's an existing resource. - if (credential) - res.status(200).json({ message: `credential with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.credential.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found` }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only DELETE Method allowed" }); + const data = await prisma.credential.delete({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ message: `Credential with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `Credential with id: ${safe.data.id} was not able to be processed`, + error, + }); } -export default withValidQueryIdTransformParseInt(deleteCredential); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteCredential)); diff --git a/pages/api/credentials/[id]/edit.ts b/pages/api/credentials/[id]/edit.ts index b34be12932..5febf03067 100644 --- a/pages/api/credentials/[id]/edit.ts +++ b/pages/api/credentials/[id]/edit.ts @@ -1,38 +1,62 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Credential } from "@calcom/prisma/client"; -import { schemaCredential, withValidCredential } from "@lib/validations/credential"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { CredentialResponse } from "@lib/types"; +import { + schemaCredentialBodyParams, + schemaCredentialPublic, + withValidCredential, +} from "@lib/validations/credential"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: Credential; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/credentials/{id}/edit: + * patch: + * summary: Edit an existing credential + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the credential to edit + * tags: + * - credentials + * responses: + * 201: + * description: OK, credential edited successfuly + * model: Credential + * 400: + * description: Bad request. Credential body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editCredential(req: NextApiRequest, res: NextApiResponse) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaCredentialBodyParams.safeParse(req.body); -export async function editCredential(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaCredential.safeParse(body); + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const credential = await prisma.credential.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaCredentialPublic.parse(credential); - if (method === "PATCH" && safeQuery.success && safeBody.success) { - const data = await prisma.credential.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - if (data) res.status(200).json({ data }); - else - res - .status(404) - .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); - - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only PATCH Method allowed for updating credentials" }); + 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 withValidQueryIdTransformParseInt(withValidCredential(editCredential)); +export default withMiddleware("HTTP_PATCH")( + withValidQueryIdTransformParseInt(withValidCredential(editCredential)) +); diff --git a/pages/api/credentials/[id]/index.ts b/pages/api/credentials/[id]/index.ts index 18810aa488..9686700a17 100644 --- a/pages/api/credentials/[id]/index.ts +++ b/pages/api/credentials/[id]/index.ts @@ -1,29 +1,51 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Credential } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { CredentialResponse } from "@lib/types"; +import { schemaCredentialPublic } from "@lib/validations/credential"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: Credential; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/credentials/{id}: + * get: + * summary: Get a credential by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the credential to get + * tags: + * - credentials + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Credential was not found + */ +export async function credentialById(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); -export async function credential(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "GET" && safe.success) { - const data = await prisma.credential.findUnique({ where: { id: safe.data.id } }); + const credential = await prisma.credential.findUnique({ where: { id: safe.data.id } }); + const data = schemaCredentialPublic.parse(credential); - if (data) res.status(200).json({ data }); - else res.status(404).json({ message: "Event type not found" }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only GET Method allowed" }); + if (credential) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "Credential was not found", + error, + }); } -export default withValidQueryIdTransformParseInt(credential); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(credentialById)); diff --git a/pages/api/credentials/index.ts b/pages/api/credentials/index.ts index 5810b80e63..1ef98a95df 100644 --- a/pages/api/credentials/index.ts +++ b/pages/api/credentials/index.ts @@ -1,15 +1,37 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Credential } from "@calcom/prisma/client"; -type ResponseData = { - data?: Credential[]; - error?: unknown; -}; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { CredentialsResponse } from "@lib/types"; +import { schemaCredentialPublic } from "@lib/validations/credential"; + +/** + * @swagger + * /api/credentials: + * get: + * summary: Get all credentials + * tags: + * - credentials + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No credentials were found + */ +async function allCredentials(_: NextApiRequest, res: NextApiResponse) { + const credentials = await prisma.credential.findMany(); + const data = credentials.map((credential) => schemaCredentialPublic.parse(credential)); -export default async function credential(req: NextApiRequest, res: NextApiResponse) { - const data = await prisma.credential.findMany(); if (data) res.status(200).json({ data }); - else res.status(400).json({ error: "No data found" }); + else + (error: Error) => + res.status(404).json({ + message: "No Credentials were found", + error, + }); } + +export default withMiddleware("HTTP_GET")(allCredentials); diff --git a/pages/api/credentials/new.ts b/pages/api/credentials/new.ts index b823a1f1b0..265f17d3cd 100644 --- a/pages/api/credentials/new.ts +++ b/pages/api/credentials/new.ts @@ -1,26 +1,52 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Credential } from "@calcom/prisma/client"; -import { schemaCredential, withValidCredential } from "@lib/validations/credential"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { CredentialResponse } from "@lib/types"; +import { + schemaCredentialBodyParams, + schemaCredentialPublic, + withValidCredential, +} from "@lib/validations/credential"; -type ResponseData = { - data?: Credential; - message?: string; - error?: string; -}; +/** + * @swagger + * /api/credentials/new: + * post: + * summary: Creates a new credential + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/Credential' + * tags: + * - credentials + * responses: + * 201: + * description: OK, credential created + * model: Credential + * 400: + * description: Bad request. Credential body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createCredential(req: NextApiRequest, res: NextApiResponse) { + const safe = schemaCredentialBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -async function createCredential(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - const safe = schemaCredential.safeParse(body); - if (method === "POST" && safe.success) { - await prisma.credential - .create({ data: safe.data }) - .then((data) => res.status(201).json({ data })) - .catch((error) => res.status(400).json({ message: "Could not create credential type", error: error })); - // Reject any other HTTP method than POST - } else res.status(405).json({ error: "Only POST Method allowed" }); + const credential = await prisma.credential.create({ data: safe.data }); + const data = schemaCredentialPublic.parse(credential); + + if (data) res.status(201).json({ data, message: "Credential created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new credential", + error, + }); } -export default withValidCredential(createCredential); +export default withMiddleware("HTTP_POST")(withValidCredential(createCredential));