diff --git a/lib/helpers/withCost.ts b/lib/helpers/withCost.ts new file mode 100644 index 0000000000..d462536956 --- /dev/null +++ b/lib/helpers/withCost.ts @@ -0,0 +1,23 @@ +// Make a middleware that adds a cost to running the request +// by calling stripeSubscription addCost() * pricePerBooking +// Initially to test out 0,5 cent per booking via API call +// withCost(5)(endpoint) +// Should add a charge of 0.5 cent per booking to the subscription of the user making the request +import { NextMiddleware } from "next-api-middleware"; + +export const withCost = (priceInCents: number): NextMiddleware => { + return async function (req, res, next) { + console.log(req.headers); + if ( + priceInCents > 0 + // && stripeCustomerId && stripeSubscriptionId + ) { + console.log(priceInCents); + // if (req.method === allowedHttpMethod || req.method == "OPTIONS") { + await next(); + } else { + res.status(405).json({ message: `We weren't able to process the payment for this transaction` }); + res.end(); + } + }; +}; diff --git a/lib/helpers/withMiddleware.ts b/lib/helpers/withMiddleware.ts index c410882081..e15c388d51 100644 --- a/lib/helpers/withMiddleware.ts +++ b/lib/helpers/withMiddleware.ts @@ -2,7 +2,7 @@ import { label } from "next-api-middleware"; import { addRequestId } from "./addRequestid"; import { captureErrors } from "./captureErrors"; -import { HTTP_POST, HTTP_DELETE, HTTP_PATCH, HTTP_GET, httpMethod } from "./httpMethods"; +import { HTTP_POST, HTTP_DELETE, HTTP_PATCH, HTTP_GET } from "./httpMethods"; import { verifyApiKey } from "./verifyApiKey"; const withMiddleware = label( @@ -14,9 +14,8 @@ const withMiddleware = label( addRequestId, verifyApiKey, sentry: captureErrors, - httpMethod: httpMethod("GET" || "DELETE" || "PATCH" || "POST"), }, - ["sentry", "verifyApiKey", "httpMethod", "addRequestId"] // <-- Provide a list of middleware to call automatically + ["sentry", "verifyApiKey", "addRequestId"] // <-- Provide a list of middleware to call automatically ); export { withMiddleware }; diff --git a/lib/types.ts b/lib/types.ts index 100fde2b61..d0c33538c3 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -2,8 +2,10 @@ import { User, ApiKey, Team, + Credential, SelectedCalendar, EventType, + EventTypeCustomInput, Attendee, Availability, BookingReference, @@ -21,10 +23,12 @@ export type BaseResponse = { message?: string; error?: Error; }; + // User export type UserResponse = BaseResponse & { data?: Partial; }; + export type UsersResponse = BaseResponse & { data?: Partial[]; }; @@ -117,6 +121,14 @@ export type MembershipsResponse = BaseResponse & { data?: Partial[]; }; +// EventTypeCustomInput +export type EventTypeCustomInputResponse = BaseResponse & { + data?: Partial; +}; +export type EventTypeCustomInputsResponse = BaseResponse & { + data?: Partial[]; +}; + // EventType export type EventTypeResponse = BaseResponse & { data?: Partial; diff --git a/lib/validations/apiKey.ts b/lib/validations/apiKey.ts index 2d93b31e09..e12a50cefa 100644 --- a/lib/validations/apiKey.ts +++ b/lib/validations/apiKey.ts @@ -2,7 +2,7 @@ import { withValidation } from "next-validations"; import { _ApiKeyModel as ApiKey } from "@calcom/prisma/zod"; -export const schemaApiKeyBodyParams = ApiKey.omit({ id: true, userId: true, createdAt: true }); +export const schemaApiKeyBodyParams = ApiKey.omit({ id: true, userId: true, createdAt: true }).partial(); export const schemaApiKeyPublic = ApiKey.omit({ id: true, diff --git a/lib/validations/attendee.ts b/lib/validations/attendee.ts index bd55fb9361..856ab2bcae 100644 --- a/lib/validations/attendee.ts +++ b/lib/validations/attendee.ts @@ -1,11 +1,20 @@ import { withValidation } from "next-validations"; +import { z } from "zod"; import { _AttendeeModel as Attendee } from "@calcom/prisma/zod"; -export const schemaAttendeeBodyParams = Attendee.omit({ id: true }); +export const schemaAttendeeBaseBodyParams = Attendee.omit({ id: true }).partial(); export const schemaAttendeePublic = Attendee.omit({}); +const schemaAttendeeRequiredParams = z.object({ + email: z.string().email(), + name: z.string(), + timeZone: z.string(), +}); + +export const schemaAttendeeBodyParams = schemaAttendeeBaseBodyParams.merge(schemaAttendeeRequiredParams); + export const withValidAttendee = withValidation({ schema: schemaAttendeeBodyParams, type: "Zod", diff --git a/lib/validations/availability.ts b/lib/validations/availability.ts index cd747bdf73..d55cfb74fa 100644 --- a/lib/validations/availability.ts +++ b/lib/validations/availability.ts @@ -1,11 +1,21 @@ import { withValidation } from "next-validations"; +import { z } from "zod"; import { _AvailabilityModel as Availability } from "@calcom/prisma/zod"; -export const schemaAvailabilityBodyParams = Availability.omit({ id: true }); +export const schemaAvailabilityBaseBodyParams = Availability.omit({ id: true }).partial(); export const schemaAvailabilityPublic = Availability.omit({}); +const schemaAvailabilityRequiredParams = z.object({ + startTime: z.string(), + endTime: z.string(), +}); + +export const schemaAvailabilityBodyParams = schemaAvailabilityBaseBodyParams.merge( + schemaAvailabilityRequiredParams +); + export const withValidAvailability = withValidation({ schema: schemaAvailabilityBodyParams, type: "Zod", 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 e7528764ab..77eca1d156 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -1,8 +1,18 @@ import { withValidation } from "next-validations"; +import { z } from "zod"; import { _BookingModel as Booking } from "@calcom/prisma/zod"; -export const schemaBookingBodyParams = Booking.omit({ id: true }); +const schemaBookingBaseBodyParams = Booking.omit({ id: true }).partial(); + +const schemaBookingRequiredParams = z.object({ + uid: z.string(), + title: z.string(), + startTime: z.date(), + endTime: z.date(), +}); + +export const schemaBookingBodyParams = schemaBookingBaseBodyParams.merge(schemaBookingRequiredParams); export const schemaBookingPublic = Booking.omit({}); 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/event-type-custom-input.ts b/lib/validations/event-type-custom-input.ts new file mode 100644 index 0000000000..ea1e80c3bb --- /dev/null +++ b/lib/validations/event-type-custom-input.ts @@ -0,0 +1,37 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +import { _EventTypeCustomInputModel as EventTypeCustomInput } from "@calcom/prisma/zod"; + +export const schemaEventTypeCustomInputBaseBodyParams = EventTypeCustomInput.omit({ + id: true, + eventTypeId: true, +}).partial(); + +export const schemaEventTypeCustomInputPublic = EventTypeCustomInput.omit({}); + +const schemaEventTypeCustomInputRequiredParams = z.object({ + label: z.string(), + required: z.boolean(), + // eventType: EventTypeModel.optional(), + type: z.enum(["TEXT", "TEXTLONG", "NUMBER", "BOOL"]), + eventType: z.object({ + connect: z.object({ + id: z.number().optional(), + // username: z.string().optional(), + // email: z.string().optional(), + }), + // FIXME: Provide valid EventTypeModel schema here, but not sure how yet. + create: z.any(), + }), +}); + +export const schemaEventTypeCustomInputBodyParams = schemaEventTypeCustomInputBaseBodyParams.merge( + schemaEventTypeCustomInputRequiredParams +); + +export const withValidEventTypeCustomInput = withValidation({ + schema: schemaEventTypeCustomInputBodyParams, + type: "Zod", + mode: "body", +}); diff --git a/lib/validations/schedule.ts b/lib/validations/schedule.ts index ad6d403b00..e5782a08d7 100644 --- a/lib/validations/schedule.ts +++ b/lib/validations/schedule.ts @@ -1,8 +1,16 @@ import { withValidation } from "next-validations"; +import { z } from "zod"; import { _ScheduleModel as Schedule } from "@calcom/prisma/zod"; -export const schemaScheduleBodyParams = Schedule.omit({ id: true }); +const schemaScheduleBaseBodyParams = Schedule.omit({ id: true }).partial(); + +const schemaScheduleRequiredParams = z.object({ + userId: z.number(), + name: z.string(), +}); + +export const schemaScheduleBodyParams = schemaScheduleBaseBodyParams.merge(schemaScheduleRequiredParams); export const schemaSchedulePublic = Schedule.omit({}); diff --git a/lib/validations/selected-calendar.ts b/lib/validations/selected-calendar.ts index 2c8d871d52..4eab89d937 100644 --- a/lib/validations/selected-calendar.ts +++ b/lib/validations/selected-calendar.ts @@ -1,10 +1,29 @@ import { withValidation } from "next-validations"; +import { z } from "zod"; import { _SelectedCalendarModel as SelectedCalendar } from "@calcom/prisma/zod"; -export const schemaSelectedCalendarBodyParams = SelectedCalendar.omit({}); +export const schemaSelectedCalendarBaseBodyParams = SelectedCalendar.omit({ userId: true }).partial(); -export const schemaSelectedCalendarPublic = SelectedCalendar.omit({ userId: true }); +export const schemaSelectedCalendarPublic = SelectedCalendar.omit({}); + +const schemaSelectedCalendarRequiredParams = z.object({ + externalId: z.string(), + integration: z.string(), + user: z.object({ + connect: z.object({ + id: z.number().optional(), + username: z.string().optional(), + email: z.string().optional(), + }), + // FIXME: Provide valid UserModel schema here, but not sure how yet. + create: z.any(), + }), +}); + +export const schemaSelectedCalendarBodyParams = schemaSelectedCalendarBaseBodyParams.merge( + schemaSelectedCalendarRequiredParams +); export const withValidSelectedCalendar = withValidation({ schema: schemaSelectedCalendarBodyParams, 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/lib/validations/team.ts b/lib/validations/team.ts index 20b79ac1c4..010d73282a 100644 --- a/lib/validations/team.ts +++ b/lib/validations/team.ts @@ -2,7 +2,7 @@ import { withValidation } from "next-validations"; import { _TeamModel as Team } from "@calcom/prisma/zod"; -export const schemaTeamBodyParams = Team.omit({ id: true }); +export const schemaTeamBodyParams = Team.omit({ id: true }).partial(); export const schemaTeamPublic = Team.omit({}); diff --git a/lib/validations/user.ts b/lib/validations/user.ts index 2058a20c2e..ec3f7a2247 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -1,15 +1,22 @@ import { withValidation } from "next-validations"; +import { z } from "zod"; import { _UserModel as User } from "@calcom/prisma/zod"; -export const schemaUserBodyParams = User.omit({ +export const schemaUserBaseBodyParams = User.omit({ id: true, createdAt: true, password: true, twoFactorEnabled: true, twoFactorSecret: true, +}).partial(); + +const schemaUserRequiredParams = z.object({ + email: z.string().email(), }); +export const schemaUserBodyParams = schemaUserBaseBodyParams.merge(schemaUserRequiredParams); + export const schemaUserPublic = User.omit({ identityProvider: true, identityProviderId: true, diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 198f4797a8..746443213d 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -2,7 +2,7 @@ import { withValidation } from "next-validations"; import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; -export const schemaWebhookBodyParams = Webhook.omit({ id: true }); +export const schemaWebhookBodyParams = Webhook.omit({ id: true }).partial(); export const schemaWebhookPublic = Webhook.omit({}); diff --git a/package.json b/package.json index 8f496b55e7..8507464bf3 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,6 @@ "next-swagger-doc": "^0.2.1", "next-transpile-modules": "^9.0.0", "next-validations": "^0.1.11", - "typescript": "^4.6.3", - "zod": "^3.14.2" + "typescript": "^4.6.3" } } diff --git a/pages/api/_middleware.ts b/pages/api/_middleware.ts index bd5d664589..35529757ba 100644 --- a/pages/api/_middleware.ts +++ b/pages/api/_middleware.ts @@ -9,7 +9,7 @@ export default async function requireApiKeyAsQueryParams({ nextUrl }: NextReques const apiKey = nextUrl.searchParams.get("apiKey"); if (apiKey) return response; - // if no apiKey is passed, we throw early a 401 unauthorized + // if no apiKey is passed, we throw early a 401 unauthorized asking for a valid apiKey else new NextResponse( JSON.stringify({ diff --git a/pages/api/attendees/[id]/delete.ts b/pages/api/attendees/[id]/delete.ts index 99ca9eef3f..59cf150af5 100644 --- a/pages/api/attendees/[id]/delete.ts +++ b/pages/api/attendees/[id]/delete.ts @@ -2,27 +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/attendees/{id}/delete: + * delete: + * summary: Remove an existing attendee + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the attendee to delete + * tags: + * - attendees + * responses: + * 201: + * description: OK, attendee removed successfuly + * model: Attendee + * 400: + * description: Bad request. Attendee id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteAttendee(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 attendee(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const attendee = await prisma.attendee.delete({ where: { id: safe.data.id } }); - // We only remove the attendee type from the database if there's an existing resource. - if (attendee) res.status(200).json({ message: `attendee with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.attendee.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.attendee.delete({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ message: `Attendee with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `Attendee with id: ${safe.data.id} was not able to be processed`, + error, + }); } -export default withValidQueryIdTransformParseInt(attendee); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteAttendee)); diff --git a/pages/api/attendees/[id]/edit.ts b/pages/api/attendees/[id]/edit.ts index 78374a4dc0..0f0d5f2e0c 100644 --- a/pages/api/attendees/[id]/edit.ts +++ b/pages/api/attendees/[id]/edit.ts @@ -1,41 +1,58 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Attendee } from "@calcom/prisma/client"; -import { schemaAttendee, withValidAttendee } from "@lib/validations/attendee"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { AttendeeResponse } from "@lib/types"; +import { schemaAttendeeBodyParams, schemaAttendeePublic, withValidAttendee } from "@lib/validations/attendee"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: Attendee; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/attendees/{id}/edit: + * patch: + * summary: Edit an existing attendee + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the attendee to edit + * tags: + * - attendees + * responses: + * 201: + * description: OK, attendee edited successfuly + * model: Attendee + * 400: + * description: Bad request. Attendee body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editAttendee(req: NextApiRequest, res: NextApiResponse) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaAttendeeBodyParams.safeParse(req.body); -export async function editAttendee(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaAttendee.safeParse(body); + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const attendee = await prisma.attendee.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaAttendeePublic.parse(attendee); - if (method === "PATCH" && safeQuery.success && safeBody.success) { - await prisma.attendee - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((attendee) => { - res.status(200).json({ data: attendee }); - }) - .catch((error) => { - res - .status(404) - .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); + 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, }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only PATCH Method allowed for updating attendees" }); } -export default withValidQueryIdTransformParseInt(withValidAttendee(editAttendee)); +export default withMiddleware("HTTP_PATCH")( + withValidQueryIdTransformParseInt(withValidAttendee(editAttendee)) +); diff --git a/pages/api/attendees/[id]/index.ts b/pages/api/attendees/[id]/index.ts index 6fc30b78f2..6fe39d540c 100644 --- a/pages/api/attendees/[id]/index.ts +++ b/pages/api/attendees/[id]/index.ts @@ -1,30 +1,51 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Attendee } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { AttendeeResponse } from "@lib/types"; +import { schemaAttendeePublic } from "@lib/validations/attendee"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: Attendee; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/attendees/{id}: + * get: + * summary: Get a attendee by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the attendee to get + * tags: + * - attendees + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Attendee was not found + */ +export async function attendeeById(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); -export async function attendee(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); + const attendee = await prisma.attendee.findUnique({ where: { id: safe.data.id } }); + const data = schemaAttendeePublic.parse(attendee); - if (method === "GET" && safe.success) { - const attendee = await prisma.attendee.findUnique({ where: { id: safe.data.id } }); - - if (attendee) res.status(200).json({ data: attendee }); - if (!attendee) 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 (attendee) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "Attendee was not found", + error, + }); } -export default withValidQueryIdTransformParseInt(attendee); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(attendeeById)); diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index c5ac16eb09..4c94c6ed7d 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -1,19 +1,37 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Attendee } from "@calcom/prisma/client"; -type ResponseData = { - data?: Attendee[]; - error?: unknown; -}; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { AttendeesResponse } from "@lib/types"; +import { schemaAttendeePublic } from "@lib/validations/attendee"; -export default async function attendee(req: NextApiRequest, res: NextApiResponse) { - try { - const data = await prisma.attendee.findMany(); - res.status(200).json({ data }); - } catch (error) { - // FIXME: Add zod for validation/error handling - res.status(400).json({ error: error }); - } +/** + * @swagger + * /api/attendees: + * get: + * summary: Get all attendees + * tags: + * - attendees + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No attendees were found + */ +async function allAttendees(_: NextApiRequest, res: NextApiResponse) { + const attendees = await prisma.attendee.findMany(); + const data = attendees.map((attendee) => schemaAttendeePublic.parse(attendee)); + + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "No Attendees were found", + error, + }); } + +export default withMiddleware("HTTP_GET")(allAttendees); diff --git a/pages/api/attendees/new.ts b/pages/api/attendees/new.ts index f01d7a3dbe..7825755b0e 100644 --- a/pages/api/attendees/new.ts +++ b/pages/api/attendees/new.ts @@ -1,27 +1,48 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Attendee } from "@calcom/prisma/client"; -import { schemaAttendee, withValidAttendee } from "@lib/validations/attendee"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { AttendeeResponse } from "@lib/types"; +import { schemaAttendeeBodyParams, schemaAttendeePublic, withValidAttendee } from "@lib/validations/attendee"; -type ResponseData = { - data?: Attendee; - message?: string; - error?: string; -}; +/** + * @swagger + * /api/attendees/new: + * post: + * summary: Creates a new attendee + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/Attendee' + * tags: + * - attendees + * responses: + * 201: + * description: OK, attendee created + * model: Attendee + * 400: + * description: Bad request. Attendee body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createAttendee(req: NextApiRequest, res: NextApiResponse) { + const safe = schemaAttendeeBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -async function createAttendee(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - const safe = schemaAttendee.safeParse(body); + const attendee = await prisma.attendee.create({ data: safe.data }); + const data = schemaAttendeePublic.parse(attendee); - if (method === "POST" && safe.success) { - await prisma.attendee - .create({ data: safe.data }) - .then((attendee) => res.status(201).json({ data: attendee })) - .catch((error) => res.status(400).json({ message: "Could not create attendee type", error: error })); - // Reject any other HTTP method than POST - } else res.status(405).json({ error: "Only POST Method allowed" }); + if (data) res.status(201).json({ data, message: "Attendee created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new attendee", + error, + }); } -export default withValidAttendee(createAttendee); +export default withMiddleware("HTTP_POST")(withValidAttendee(createAttendee)); diff --git a/pages/api/availabilities/[id]/delete.ts b/pages/api/availabilities/[id]/delete.ts index b59534eb08..1601b014a1 100644 --- a/pages/api/availabilities/[id]/delete.ts +++ b/pages/api/availabilities/[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/availabilites/{id}/delete: + * delete: + * summary: Remove an existing availability + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the availability to delete + * tags: + * - availabilites + * responses: + * 201: + * description: OK, availability removed successfuly + * model: Availability + * 400: + * description: Bad request. Availability id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteAvailability(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 availability(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const availability = await prisma.availability.delete({ where: { id: safe.data.id } }); - // We only remove the availability type from the database if there's an existing resource. - if (availability) - res.status(200).json({ message: `availability with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.availability.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.availability.delete({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ message: `Availability with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `Availability with id: ${safe.data.id} was not able to be processed`, + error, + }); } -export default withValidQueryIdTransformParseInt(availability); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteAvailability)); diff --git a/pages/api/availabilities/[id]/edit.ts b/pages/api/availabilities/[id]/edit.ts index c12de7ddc2..e530090a43 100644 --- a/pages/api/availabilities/[id]/edit.ts +++ b/pages/api/availabilities/[id]/edit.ts @@ -1,41 +1,62 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Availability } from "@calcom/prisma/client"; -import { schemaAvailability, withValidAvailability } from "@lib/validations/availability"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { AvailabilityResponse } from "@lib/types"; +import { + schemaAvailabilityBodyParams, + schemaAvailabilityPublic, + withValidAvailability, +} from "@lib/validations/availability"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: Availability; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/availabilites/{id}/edit: + * patch: + * summary: Edit an existing availability + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the availability to edit + * tags: + * - availabilites + * responses: + * 201: + * description: OK, availability edited successfuly + * model: Availability + * 400: + * description: Bad request. Availability body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editAvailability(req: NextApiRequest, res: NextApiResponse) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaAvailabilityBodyParams.safeParse(req.body); -export async function editAvailability(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaAvailability.safeParse(body); + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const availability = await prisma.availability.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaAvailabilityPublic.parse(availability); - if (method === "PATCH" && safeQuery.success && safeBody.success) { - await prisma.availability - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((availability) => { - res.status(200).json({ data: availability }); - }) - .catch((error) => { - res - .status(404) - .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); + 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, }); - // Reject any other HTTP method than PATCH - } else res.status(405).json({ message: "Only PATCH Method allowed for updating availabilities" }); } -export default withValidQueryIdTransformParseInt(withValidAvailability(editAvailability)); +export default withMiddleware("HTTP_PATCH")( + withValidQueryIdTransformParseInt(withValidAvailability(editAvailability)) +); diff --git a/pages/api/availabilities/[id]/index.ts b/pages/api/availabilities/[id]/index.ts index 8e2573df69..22e160e436 100644 --- a/pages/api/availabilities/[id]/index.ts +++ b/pages/api/availabilities/[id]/index.ts @@ -1,30 +1,51 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Availability } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { AvailabilityResponse } from "@lib/types"; +import { schemaAvailabilityPublic } from "@lib/validations/availability"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: Availability; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/availabilites/{id}: + * get: + * summary: Get a availability by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the availability to get + * tags: + * - availabilites + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Availability was not found + */ +export async function availabilityById(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); -export async function availability(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); + const availability = await prisma.availability.findUnique({ where: { id: safe.data.id } }); + const data = schemaAvailabilityPublic.parse(availability); - if (method === "GET" && safe.success) { - const availability = await prisma.availability.findUnique({ where: { id: safe.data.id } }); - - if (availability) res.status(200).json({ data: availability }); - if (!availability) 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 (availability) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "Availability was not found", + error, + }); } -export default withValidQueryIdTransformParseInt(availability); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(availabilityById)); diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index 95cde57385..d3a2168565 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -1,19 +1,37 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Availability } from "@calcom/prisma/client"; -type ResponseData = { - data?: Availability[]; - error?: unknown; -}; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { AvailabilitysResponse } from "@lib/types"; +import { schemaAvailabilityPublic } from "@lib/validations/availability"; -export default async function availability(req: NextApiRequest, res: NextApiResponse) { - try { - const data = await prisma.availability.findMany(); - res.status(200).json({ data }); - } catch (error) { - // FIXME: Add zod for validation/error handling - res.status(400).json({ error: error }); - } +/** + * @swagger + * /api/availabilites: + * get: + * summary: Get all availabilites + * tags: + * - availabilites + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No availabilites were found + */ +async function allAvailabilitys(_: NextApiRequest, res: NextApiResponse) { + const availabilites = await prisma.availability.findMany(); + const data = availabilites.map((availability) => schemaAvailabilityPublic.parse(availability)); + + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "No Availabilitys were found", + error, + }); } + +export default withMiddleware("HTTP_GET")(allAvailabilitys); diff --git a/pages/api/availabilities/new.ts b/pages/api/availabilities/new.ts index 5df3ea02e2..2e3587e551 100644 --- a/pages/api/availabilities/new.ts +++ b/pages/api/availabilities/new.ts @@ -1,32 +1,52 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Availability } from "@calcom/prisma/client"; -import { schemaAvailability, withValidAvailability } from "@lib/validations/availability"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { AvailabilityResponse } from "@lib/types"; +import { + schemaAvailabilityBodyParams, + schemaAvailabilityPublic, + withValidAvailability, +} from "@lib/validations/availability"; -type ResponseData = { - data?: Availability; - message?: string; - error?: string; -}; +/** + * @swagger + * /api/availabilites/new: + * post: + * summary: Creates a new availability + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/Availability' + * tags: + * - availabilites + * responses: + * 201: + * description: OK, availability created + * model: Availability + * 400: + * description: Bad request. Availability body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createAvailability(req: NextApiRequest, res: NextApiResponse) { + const safe = schemaAvailabilityBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -async function createAvailability(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - if (method === "POST") { - const safe = schemaAvailability.safeParse(body); - if (safe.success && safe.data) { - await prisma.availability - .create({ data: safe.data }) - .then((availability) => res.status(201).json({ data: availability })) - .catch((error) => - res.status(400).json({ message: "Could not create availability type", error: error }) - ); - } - } else { - // Reject any other HTTP method than POST - res.status(405).json({ error: "Only POST Method allowed" }); - } + const availability = await prisma.availability.create({ data: safe.data }); + const data = schemaAvailabilityPublic.parse(availability); + + if (data) res.status(201).json({ data, message: "Availability created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new availability", + error, + }); } -export default withValidAvailability(createAvailability); +export default withMiddleware("HTTP_POST")(withValidAvailability(createAvailability)); 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 50dc9ffbf2..4e62b0e531 100644 --- a/pages/api/bookings/new.ts +++ b/pages/api/bookings/new.ts @@ -1,30 +1,48 @@ 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"; -type ResponseData = { - data?: Booking; - message?: string; - error?: string; -}; +/** + * @swagger + * /api/bookings/new: + * post: + * summary: Creates a new booking + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/Booking' + * tags: + * - bookings + * responses: + * 201: + * description: OK, booking created + * model: Booking + * 400: + * description: Bad request. Booking body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createBooking(req: NextApiRequest, res: NextApiResponse) { + const safe = schemaBookingBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -async function createBooking(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - if (method === "POST") { - const safe = schemaBooking.safeParse(body); - if (safe.success && safe.data) { - await prisma.booking - .create({ data: safe.data }) - .then((booking) => res.status(201).json({ data: booking })) - .catch((error) => res.status(400).json({ message: "Could not create booking type", error: error })); - } - } else { - // Reject any other HTTP method than POST - res.status(405).json({ error: "Only POST Method allowed" }); - } + const booking = await prisma.booking.create({ data: safe.data }); + const data = schemaBookingPublic.parse(booking); + + if (data) res.status(201).json({ data, message: "Booking created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new booking", + error, + }); } -export default withValidBooking(createBooking); +export default withMiddleware("HTTP_POST")(withValidBooking(createBooking)); diff --git a/pages/api/credentials/[id]/delete.ts b/pages/api/credentials/[id]/delete.ts index b6b0d8e361..e97e78d07c 100644 --- a/pages/api/credentials/[id]/delete.ts +++ b/pages/api/credentials/[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/credentials/{id}/delete: + * delete: + * summary: Remove an existing credential + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the credential to delete + * tags: + * - credentials + * responses: + * 201: + * description: OK, credential removed successfuly + * model: Credential + * 400: + * description: Bad request. Credential id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteCredential(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)); diff --git a/pages/api/daily-event-references/[id]/delete.ts b/pages/api/daily-event-references/[id]/delete.ts index 77c97782a6..71b61d86c4 100644 --- a/pages/api/daily-event-references/[id]/delete.ts +++ b/pages/api/daily-event-references/[id]/delete.ts @@ -3,30 +3,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; -}; - -export async function deleteDailyEventReference(req: NextApiRequest, res: NextApiResponse) { +/** + * @swagger + * /api/daily-event-references/{id}/delete: + * delete: + * summary: Remove an existing dailyEventReference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the dailyEventReference to delete + * tags: + * - dailyEventReferences + * responses: + * 201: + * description: OK, dailyEventReference removed successfuly + * model: DailyEventReference + * 400: + * description: Bad request. DailyEventReference id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteDailyEventReference(req: NextApiRequest, res: NextApiResponse) { const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (safe.success) { - const deletedDailyEventReference = await prisma.dailyEventReference.delete({ - where: { id: safe.data.id }, - }); - // We only remove the dailyEventReference type from the database if there's an existing resource. - if (deletedDailyEventReference) - res.status(200).json({ message: `dailyEventReference with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.dailyEventReference.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" }); + if (!safe.success) throw new Error("Invalid request query", safe.error); + + const data = await prisma.dailyEventReference.delete({ where: { id: safe.data.id } }); + + if (data) + res.status(200).json({ message: `DailyEventReference with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `DailyEventReference with id: ${safe.data.id} was not able to be processed`, + error, + }); } -// export default withValidQueryIdTransformParseInt(deleteDailyEventReference); export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteDailyEventReference)); diff --git a/pages/api/daily-event-references/[id]/edit.ts b/pages/api/daily-event-references/[id]/edit.ts index 372e258163..e3d9f73765 100644 --- a/pages/api/daily-event-references/[id]/edit.ts +++ b/pages/api/daily-event-references/[id]/edit.ts @@ -1,10 +1,12 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { DailyEventReference } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { DailyEventReferenceResponse } from "@lib/types"; import { - schemaDailyEventReference, + schemaDailyEventReferenceBodyParams, + schemaDailyEventReferencePublic, withValidDailyEventReference, } from "@lib/validations/daily-event-reference"; import { @@ -12,30 +14,52 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: DailyEventReference; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/daily-event-references/{id}/edit: + * patch: + * summary: Edit an existing dailyEventReference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the dailyEventReference to edit + * tags: + * - dailyEventReferences + * responses: + * 201: + * description: OK, dailyEventReference edited successfuly + * model: DailyEventReference + * 400: + * description: Bad request. DailyEventReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editDailyEventReference( + req: NextApiRequest, + res: NextApiResponse +) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaDailyEventReferenceBodyParams.safeParse(req.body); -export async function editDailyEventReference(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaDailyEventReference.safeParse(body); + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const dailyEventReference = await prisma.dailyEventReference.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaDailyEventReferencePublic.parse(dailyEventReference); - if (method === "PATCH" && safeQuery.success && safeBody.success) { - const data = await prisma.dailyEventReference.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 dailyEventReferences" }); + 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(withValidDailyEventReference(editDailyEventReference)); +export default withMiddleware("HTTP_PATCH")( + withValidQueryIdTransformParseInt(withValidDailyEventReference(editDailyEventReference)) +); diff --git a/pages/api/daily-event-references/[id]/index.ts b/pages/api/daily-event-references/[id]/index.ts index 459c4f5381..338a64470c 100644 --- a/pages/api/daily-event-references/[id]/index.ts +++ b/pages/api/daily-event-references/[id]/index.ts @@ -1,29 +1,54 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { DailyEventReference } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { DailyEventReferenceResponse } from "@lib/types"; +import { schemaDailyEventReferencePublic } from "@lib/validations/daily-event-reference"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: DailyEventReference; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/daily-event-references/{id}: + * get: + * summary: Get a dailyEventReference by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the dailyEventReference to get + * tags: + * - dailyEventReferences + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: DailyEventReference was not found + */ +export async function dailyEventReferenceById( + req: NextApiRequest, + res: NextApiResponse +) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); -export async function dailyEventReference(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "GET" && safe.success) { - const data = await prisma.dailyEventReference.findUnique({ where: { id: safe.data.id } }); + const dailyEventReference = await prisma.dailyEventReference.findUnique({ where: { id: safe.data.id } }); + const data = schemaDailyEventReferencePublic.parse(dailyEventReference); - 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 (dailyEventReference) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "DailyEventReference was not found", + error, + }); } -export default withValidQueryIdTransformParseInt(dailyEventReference); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(dailyEventReferenceById)); diff --git a/pages/api/daily-event-references/index.ts b/pages/api/daily-event-references/index.ts index a5509f8a90..774d39358c 100644 --- a/pages/api/daily-event-references/index.ts +++ b/pages/api/daily-event-references/index.ts @@ -1,15 +1,42 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { DailyEventReference } from "@calcom/prisma/client"; -type ResponseData = { - data?: DailyEventReference[]; - error?: unknown; -}; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { DailyEventReferencesResponse } from "@lib/types"; +import { schemaDailyEventReferencePublic } from "@lib/validations/daily-event-reference"; + +/** + * @swagger + * /api/daily-event-references: + * get: + * summary: Get all dailyEventReferences + * tags: + * - dailyEventReferences + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No dailyEventReferences were found + */ +async function allDailyEventReferences( + _: NextApiRequest, + res: NextApiResponse +) { + const dailyEventReferences = await prisma.dailyEventReference.findMany(); + const data = dailyEventReferences.map((dailyEventReference) => + schemaDailyEventReferencePublic.parse(dailyEventReference) + ); -export default async function dailyEventReference(req: NextApiRequest, res: NextApiResponse) { - const data = await prisma.dailyEventReference.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 DailyEventReferences were found", + error, + }); } + +export default withMiddleware("HTTP_GET")(allDailyEventReferences); diff --git a/pages/api/daily-event-references/new.ts b/pages/api/daily-event-references/new.ts index 5bbc67fb2c..baf5e83d10 100644 --- a/pages/api/daily-event-references/new.ts +++ b/pages/api/daily-event-references/new.ts @@ -1,31 +1,55 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { DailyEventReference } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { DailyEventReferenceResponse } from "@lib/types"; import { - schemaDailyEventReference, + schemaDailyEventReferenceBodyParams, + schemaDailyEventReferencePublic, withValidDailyEventReference, } from "@lib/validations/daily-event-reference"; -type ResponseData = { - data?: DailyEventReference; - message?: string; - error?: string; -}; +/** + * @swagger + * /api/daily-event-references/new: + * post: + * summary: Creates a new dailyEventReference + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/DailyEventReference' + * tags: + * - dailyEventReferences + * responses: + * 201: + * description: OK, dailyEventReference created + * model: DailyEventReference + * 400: + * description: Bad request. DailyEventReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createDailyEventReference( + req: NextApiRequest, + res: NextApiResponse +) { + const safe = schemaDailyEventReferenceBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -async function createDailyEventReference(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - const safe = schemaDailyEventReference.safeParse(body); - if (method === "POST" && safe.success) { - await prisma.dailyEventReference - .create({ data: safe.data }) - .then((data) => res.status(201).json({ data })) - .catch((error) => - res.status(400).json({ message: "Could not create dailyEventReference type", error: error }) - ); - // Reject any other HTTP method than POST - } else res.status(405).json({ error: "Only POST Method allowed" }); + const dailyEventReference = await prisma.dailyEventReference.create({ data: safe.data }); + const data = schemaDailyEventReferencePublic.parse(dailyEventReference); + + if (data) res.status(201).json({ data, message: "DailyEventReference created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new dailyEventReference", + error, + }); } -export default withValidDailyEventReference(createDailyEventReference); +export default withMiddleware("HTTP_POST")(withValidDailyEventReference(createDailyEventReference)); diff --git a/pages/api/destination-calendars/[id]/delete.ts b/pages/api/destination-calendars/[id]/delete.ts index b734fbdf9b..2573532efd 100644 --- a/pages/api/destination-calendars/[id]/delete.ts +++ b/pages/api/destination-calendars/[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/destination-calendars/{id}/delete: + * delete: + * summary: Remove an existing destinationCalendar + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the destinationCalendar to delete + * tags: + * - destinationCalendars + * responses: + * 201: + * description: OK, destinationCalendar removed successfuly + * model: DestinationCalendar + * 400: + * description: Bad request. DestinationCalendar id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteDestinationCalendar(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 deleteDestinationCalendar(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const destinationCalendar = await prisma.destinationCalendar.delete({ where: { id: safe.data.id } }); - // We only remove the destinationCalendar type from the database if there's an existing resource. - if (destinationCalendar) - res.status(200).json({ message: `destinationCalendar with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.destinationCalendar.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.destinationCalendar.delete({ where: { id: safe.data.id } }); + + if (data) + res.status(200).json({ message: `DestinationCalendar with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `DestinationCalendar with id: ${safe.data.id} was not able to be processed`, + error, + }); } -export default withValidQueryIdTransformParseInt(deleteDestinationCalendar); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteDestinationCalendar)); diff --git a/pages/api/destination-calendars/[id]/edit.ts b/pages/api/destination-calendars/[id]/edit.ts index 09c042b7e1..9dc4ae38fb 100644 --- a/pages/api/destination-calendars/[id]/edit.ts +++ b/pages/api/destination-calendars/[id]/edit.ts @@ -1,10 +1,12 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { DestinationCalendar } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { DestinationCalendarResponse } from "@lib/types"; import { - schemaDestinationCalendar, + schemaDestinationCalendarBodyParams, + schemaDestinationCalendarPublic, withValidDestinationCalendar, } from "@lib/validations/destination-calendar"; import { @@ -12,30 +14,52 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: DestinationCalendar; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/destination-calendars/{id}/edit: + * patch: + * summary: Edit an existing destinationCalendar + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the destinationCalendar to edit + * tags: + * - destinationCalendars + * responses: + * 201: + * description: OK, destinationCalendar edited successfuly + * model: DestinationCalendar + * 400: + * description: Bad request. DestinationCalendar body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editDestinationCalendar( + req: NextApiRequest, + res: NextApiResponse +) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaDestinationCalendarBodyParams.safeParse(req.body); -export async function editDestinationCalendar(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaDestinationCalendar.safeParse(body); + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const destinationCalendar = await prisma.destinationCalendar.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaDestinationCalendarPublic.parse(destinationCalendar); - if (method === "PATCH" && safeQuery.success && safeBody.success) { - const data = await prisma.destinationCalendar.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 destinationCalendars" }); + 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(withValidDestinationCalendar(editDestinationCalendar)); +export default withMiddleware("HTTP_PATCH")( + withValidQueryIdTransformParseInt(withValidDestinationCalendar(editDestinationCalendar)) +); diff --git a/pages/api/destination-calendars/[id]/index.ts b/pages/api/destination-calendars/[id]/index.ts index fde198f77f..2639e70538 100644 --- a/pages/api/destination-calendars/[id]/index.ts +++ b/pages/api/destination-calendars/[id]/index.ts @@ -1,29 +1,54 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { DestinationCalendar } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { DestinationCalendarResponse } from "@lib/types"; +import { schemaDestinationCalendarPublic } from "@lib/validations/destination-calendar"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: DestinationCalendar; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/destination-calendars/{id}: + * get: + * summary: Get a destinationCalendar by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the destinationCalendar to get + * tags: + * - destinationCalendars + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: DestinationCalendar was not found + */ +export async function destinationCalendarById( + req: NextApiRequest, + res: NextApiResponse +) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); -export async function destinationCalendar(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "GET" && safe.success) { - const data = await prisma.destinationCalendar.findUnique({ where: { id: safe.data.id } }); + const destinationCalendar = await prisma.destinationCalendar.findUnique({ where: { id: safe.data.id } }); + const data = schemaDestinationCalendarPublic.parse(destinationCalendar); - 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 (destinationCalendar) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "DestinationCalendar was not found", + error, + }); } -export default withValidQueryIdTransformParseInt(destinationCalendar); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(destinationCalendarById)); diff --git a/pages/api/destination-calendars/index.ts b/pages/api/destination-calendars/index.ts index 933ef20568..6f1a9147dd 100644 --- a/pages/api/destination-calendars/index.ts +++ b/pages/api/destination-calendars/index.ts @@ -1,15 +1,42 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { DestinationCalendar } from "@calcom/prisma/client"; -type ResponseData = { - data?: DestinationCalendar[]; - error?: unknown; -}; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { DestinationCalendarsResponse } from "@lib/types"; +import { schemaDestinationCalendarPublic } from "@lib/validations/destination-calendar"; + +/** + * @swagger + * /api/destination-calendars: + * get: + * summary: Get all destinationCalendars + * tags: + * - destinationCalendars + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No destinationCalendars were found + */ +async function allDestinationCalendars( + _: NextApiRequest, + res: NextApiResponse +) { + const destinationCalendars = await prisma.destinationCalendar.findMany(); + const data = destinationCalendars.map((destinationCalendar) => + schemaDestinationCalendarPublic.parse(destinationCalendar) + ); -export default async function destinationCalendar(req: NextApiRequest, res: NextApiResponse) { - const data = await prisma.destinationCalendar.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 DestinationCalendars were found", + error, + }); } + +export default withMiddleware("HTTP_GET")(allDestinationCalendars); diff --git a/pages/api/destination-calendars/new.ts b/pages/api/destination-calendars/new.ts index 483ff56de1..896be9f06a 100644 --- a/pages/api/destination-calendars/new.ts +++ b/pages/api/destination-calendars/new.ts @@ -1,31 +1,55 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { DestinationCalendar } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { DestinationCalendarResponse } from "@lib/types"; import { - schemaDestinationCalendar, + schemaDestinationCalendarBodyParams, + schemaDestinationCalendarPublic, withValidDestinationCalendar, } from "@lib/validations/destination-calendar"; -type ResponseData = { - data?: DestinationCalendar; - message?: string; - error?: string; -}; +/** + * @swagger + * /api/destination-calendars/new: + * post: + * summary: Creates a new destinationCalendar + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/DestinationCalendar' + * tags: + * - destinationCalendars + * responses: + * 201: + * description: OK, destinationCalendar created + * model: DestinationCalendar + * 400: + * description: Bad request. DestinationCalendar body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createDestinationCalendar( + req: NextApiRequest, + res: NextApiResponse +) { + const safe = schemaDestinationCalendarBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -async function createDestinationCalendar(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - const safe = schemaDestinationCalendar.safeParse(body); - if (method === "POST" && safe.success) { - await prisma.destinationCalendar - .create({ data: safe.data }) - .then((data) => res.status(201).json({ data })) - .catch((error) => - res.status(400).json({ message: "Could not create destinationCalendar type", error: error }) - ); - // Reject any other HTTP method than POST - } else res.status(405).json({ error: "Only POST Method allowed" }); + const destinationCalendar = await prisma.destinationCalendar.create({ data: safe.data }); + const data = schemaDestinationCalendarPublic.parse(destinationCalendar); + + if (data) res.status(201).json({ data, message: "DestinationCalendar created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new destinationCalendar", + error, + }); } -export default withValidDestinationCalendar(createDestinationCalendar); +export default withMiddleware("HTTP_POST")(withValidDestinationCalendar(createDestinationCalendar)); diff --git a/pages/api/docs.ts b/pages/api/docs.ts index e855eacfd8..8e489785bd 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -1,12 +1,14 @@ +import pjson from "@/package.json"; import { withSwagger } from "next-swagger-doc"; const swaggerHandler = withSwagger({ definition: { openapi: "3.0.0", info: { - title: "Cal.com Public API", - version: "1.0.0", + title: `${pjson.name}: ${pjson.description}`, + version: pjson.version, }, + tags: ["users", "teams"], }, apiFolder: "pages/api", }); diff --git a/pages/api/event-type-custom-inputs/[id]/delete.ts b/pages/api/event-type-custom-inputs/[id]/delete.ts index acccbac7d7..94c6bb2610 100644 --- a/pages/api/event-type-custom-inputs/[id]/delete.ts +++ b/pages/api/event-type-custom-inputs/[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/event-type-custom-inputs/{id}/delete: + * delete: + * summary: Remove an existing eventTypeCustomInput + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the eventTypeCustomInput to delete + * tags: + * - eventTypeCustomInputs + * responses: + * 201: + * description: OK, eventTypeCustomInput removed successfuly + * model: EventTypeCustomInput + * 400: + * description: Bad request. EventTypeCustomInput id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteEventTypeCustomInput(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 deleteEventTypeCustomInput(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const eventTypeCustomInput = await prisma.eventTypeCustomInput.delete({ where: { id: safe.data.id } }); - // We only remove the eventTypeCustomInput type from the database if there's an existing resource. - if (eventTypeCustomInput) - res.status(200).json({ message: `eventTypeCustomInput with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.eventTypeCustomInput.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.eventTypeCustomInput.delete({ where: { id: safe.data.id } }); + + if (data) + res.status(200).json({ message: `EventTypeCustomInput with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `EventTypeCustomInput with id: ${safe.data.id} was not able to be processed`, + error, + }); } -export default withValidQueryIdTransformParseInt(deleteEventTypeCustomInput); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteEventTypeCustomInput)); diff --git a/pages/api/event-type-custom-inputs/[id]/edit.ts b/pages/api/event-type-custom-inputs/[id]/edit.ts index 1c632034c2..c95d4aa876 100644 --- a/pages/api/event-type-custom-inputs/[id]/edit.ts +++ b/pages/api/event-type-custom-inputs/[id]/edit.ts @@ -1,41 +1,65 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { EventTypeCustomInput } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { EventTypeCustomInputResponse } from "@lib/types"; import { - schemaEventTypeCustomInput, + schemaEventTypeCustomInputBodyParams, + schemaEventTypeCustomInputPublic, withValidEventTypeCustomInput, -} from "@lib/validations/eventTypeCustomInput"; +} from "@lib/validations/event-type-custom-input"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: EventTypeCustomInput; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/event-type-custom-inputs/{id}/edit: + * patch: + * summary: Edit an existing eventTypeCustomInput + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the eventTypeCustomInput to edit + * tags: + * - eventTypeCustomInputs + * responses: + * 201: + * description: OK, eventTypeCustomInput edited successfuly + * model: EventTypeCustomInput + * 400: + * description: Bad request. EventTypeCustomInput body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editEventTypeCustomInput( + req: NextApiRequest, + res: NextApiResponse +) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaEventTypeCustomInputBodyParams.safeParse(req.body); -export async function editEventTypeCustomInput(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaEventTypeCustomInput.safeParse(body); + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const eventTypeCustomInput = await prisma.eventTypeCustomInput.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaEventTypeCustomInputPublic.parse(eventTypeCustomInput); - if (method === "PATCH" && safeQuery.success && safeBody.success) { - const data = await prisma.eventTypeCustomInput.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 eventTypeCustomInputs" }); + 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(withValidEventTypeCustomInput(editEventTypeCustomInput)); +export default withMiddleware("HTTP_PATCH")( + withValidQueryIdTransformParseInt(withValidEventTypeCustomInput(editEventTypeCustomInput)) +); diff --git a/pages/api/event-type-custom-inputs/[id]/index.ts b/pages/api/event-type-custom-inputs/[id]/index.ts index 47170af37d..5ceea367b4 100644 --- a/pages/api/event-type-custom-inputs/[id]/index.ts +++ b/pages/api/event-type-custom-inputs/[id]/index.ts @@ -1,29 +1,54 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { EventTypeCustomInput } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { EventTypeCustomInputResponse } from "@lib/types"; +import { schemaEventTypeCustomInputPublic } from "@lib/validations/event-type-custom-input"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: EventTypeCustomInput; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/event-type-custom-inputs/{id}: + * get: + * summary: Get a eventTypeCustomInput by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the eventTypeCustomInput to get + * tags: + * - eventTypeCustomInputs + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: EventTypeCustomInput was not found + */ +export async function eventTypeCustomInputById( + req: NextApiRequest, + res: NextApiResponse +) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); -export async function eventTypeCustomInput(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "GET" && safe.success) { - const data = await prisma.eventTypeCustomInput.findUnique({ where: { id: safe.data.id } }); + const eventTypeCustomInput = await prisma.eventTypeCustomInput.findUnique({ where: { id: safe.data.id } }); + const data = schemaEventTypeCustomInputPublic.parse(eventTypeCustomInput); - 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 (eventTypeCustomInput) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "EventTypeCustomInput was not found", + error, + }); } -export default withValidQueryIdTransformParseInt(eventTypeCustomInput); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(eventTypeCustomInputById)); diff --git a/pages/api/event-type-custom-inputs/index.ts b/pages/api/event-type-custom-inputs/index.ts index b39cd14bca..689d23c7ae 100644 --- a/pages/api/event-type-custom-inputs/index.ts +++ b/pages/api/event-type-custom-inputs/index.ts @@ -1,15 +1,42 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { EventTypeCustomInput } from "@calcom/prisma/client"; -type ResponseData = { - data?: EventTypeCustomInput[]; - error?: unknown; -}; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { EventTypeCustomInputsResponse } from "@lib/types"; +import { schemaEventTypeCustomInputPublic } from "@lib/validations/event-type-custom-input"; + +/** + * @swagger + * /api/event-type-custom-inputs: + * get: + * summary: Get all eventTypeCustomInputs + * tags: + * - eventTypeCustomInputs + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No eventTypeCustomInputs were found + */ +async function allEventTypeCustomInputs( + _: NextApiRequest, + res: NextApiResponse +) { + const eventTypeCustomInputs = await prisma.eventTypeCustomInput.findMany(); + const data = eventTypeCustomInputs.map((eventTypeCustomInput) => + schemaEventTypeCustomInputPublic.parse(eventTypeCustomInput) + ); -export default async function eventTypeCustomInput(req: NextApiRequest, res: NextApiResponse) { - const data = await prisma.eventTypeCustomInput.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 EventTypeCustomInputs were found", + error, + }); } + +export default withMiddleware("HTTP_GET")(allEventTypeCustomInputs); diff --git a/pages/api/event-type-custom-inputs/new.ts b/pages/api/event-type-custom-inputs/new.ts index e2a4078a59..165ed6cd20 100644 --- a/pages/api/event-type-custom-inputs/new.ts +++ b/pages/api/event-type-custom-inputs/new.ts @@ -1,31 +1,55 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { EventTypeCustomInput } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { EventTypeCustomInputResponse } from "@lib/types"; import { - schemaEventTypeCustomInput, + schemaEventTypeCustomInputBodyParams, + schemaEventTypeCustomInputPublic, withValidEventTypeCustomInput, -} from "@lib/validations/eventTypeCustomInput"; +} from "@lib/validations/event-type-custom-input"; -type ResponseData = { - data?: EventTypeCustomInput; - message?: string; - error?: string; -}; +/** + * @swagger + * /api/event-type-custom-inputs/new: + * post: + * summary: Creates a new eventTypeCustomInput + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/EventTypeCustomInput' + * tags: + * - eventTypeCustomInputs + * responses: + * 201: + * description: OK, eventTypeCustomInput created + * model: EventTypeCustomInput + * 400: + * description: Bad request. EventTypeCustomInput body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createEventTypeCustomInput( + req: NextApiRequest, + res: NextApiResponse +) { + const safe = schemaEventTypeCustomInputBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -async function createEventTypeCustomInput(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - const safe = schemaEventTypeCustomInput.safeParse(body); - if (method === "POST" && safe.success) { - await prisma.eventTypeCustomInput - .create({ data: safe.data }) - .then((data) => res.status(201).json({ data })) - .catch((error) => - res.status(400).json({ message: "Could not create eventTypeCustomInput type", error: error }) - ); - // Reject any other HTTP method than POST - } else res.status(405).json({ error: "Only POST Method allowed" }); + const eventTypeCustomInput = await prisma.eventTypeCustomInput.create({ data: safe.data }); + const data = schemaEventTypeCustomInputPublic.parse(eventTypeCustomInput); + + if (data) res.status(201).json({ data, message: "EventTypeCustomInput created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new eventTypeCustomInput", + error, + }); } -export default withValidEventTypeCustomInput(createEventTypeCustomInput); +export default withMiddleware("HTTP_POST")(withValidEventTypeCustomInput(createEventTypeCustomInput)); diff --git a/pages/api/event-types/[id]/delete.ts b/pages/api/event-types/[id]/delete.ts index 8b9add8c87..ce83548f73 100644 --- a/pages/api/event-types/[id]/delete.ts +++ b/pages/api/event-types/[id]/delete.ts @@ -11,9 +11,18 @@ import { /** * @swagger - * /api/eventTypes/:id/delete: + * /api/eventTypes/{id}/delete: * delete: - * description: Remove an existing eventType + * summary: Remove an existing eventType + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the eventType to delete + * tags: + * - eventTypes * responses: * 201: * description: OK, eventType removed successfuly diff --git a/pages/api/event-types/[id]/edit.ts b/pages/api/event-types/[id]/edit.ts index ecf8a42f76..bb181742c0 100644 --- a/pages/api/event-types/[id]/edit.ts +++ b/pages/api/event-types/[id]/edit.ts @@ -16,9 +16,18 @@ import { /** * @swagger - * /api/eventTypes/:id/edit: + * /api/eventTypes/{id}/edit: * patch: - * description: Edits an existing eventType + * summary: Edits an existing eventType + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the eventType to delete + * tags: + * - eventTypes * responses: * 201: * description: OK, eventType edited successfuly diff --git a/pages/api/event-types/[id]/index.ts b/pages/api/event-types/[id]/index.ts index cc9838dbb7..4e64863965 100644 --- a/pages/api/event-types/[id]/index.ts +++ b/pages/api/event-types/[id]/index.ts @@ -12,9 +12,16 @@ import { /** * @swagger - * /api/eventTypes/:id: + * /api/eventTypes/{id}: * get: - * description: find eventType by ID + * summary: find eventType by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the eventType to get * responses: * 200: * description: OK diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index a6ef52c501..a9bd50bce7 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -10,7 +10,7 @@ import { schemaEventTypePublic } from "@lib/validations/eventType"; * @swagger * /api/eventTypes: * get: - * description: Returns all eventTypes + * summary: Returns all eventTypes * responses: * 200: * description: OK diff --git a/pages/api/event-types/new.ts b/pages/api/event-types/new.ts index 17d2e06190..e0a6bf4707 100644 --- a/pages/api/event-types/new.ts +++ b/pages/api/event-types/new.ts @@ -14,7 +14,7 @@ import { * @swagger * /api/eventTypes/new: * post: - * description: Creates a new eventType + * summary: Creates a new eventType * responses: * 201: * description: OK, eventType created diff --git a/pages/api/memberships/[id]/delete.ts b/pages/api/memberships/[id]/delete.ts index 5cbd96fca4..b33148e6d6 100644 --- a/pages/api/memberships/[id]/delete.ts +++ b/pages/api/memberships/[id]/delete.ts @@ -2,28 +2,53 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BaseResponse } from "@lib/types"; +import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; -type ResponseData = { - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/memberships/{userId}_{teamId}/delete: + * delete: + * summary: Remove an existing membership + * parameters: + * - in: path + * - name: userId + * schema: + * type: integer + * required: true + * description: Numeric ID of the user to get the membership of + * * - name: teamId + * schema: + * type: integer + * required: true + * description: Numeric ID of the team to get the membership of + * tags: + * - memberships + * responses: + * 201: + * description: OK, membership removed successfuly + * model: Membership + * 400: + * description: Bad request. Membership id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteMembership(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdAsString.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query", safe.error); + const [userId, teamId] = safe.data.id.split("_"); + const data = await prisma.membership.delete({ + where: { userId_teamId: { userId: parseInt(userId), teamId: parseInt(teamId) } }, + }); -export async function deleteMembership(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const membership = await prisma.membership.delete({ where: { id: safe.data.id } }); - // We only remove the membership type from the database if there's an existing resource. - if (membership) - res.status(200).json({ message: `membership with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.membership.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" }); + if (data) res.status(200).json({ message: `Membership with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `Membership with id: ${safe.data.id} was not able to be processed`, + error, + }); } -export default withValidQueryIdTransformParseInt(deleteMembership); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdString(deleteMembership)); diff --git a/pages/api/memberships/[id]/edit.ts b/pages/api/memberships/[id]/edit.ts index 990c63914e..66c6ccec24 100644 --- a/pages/api/memberships/[id]/edit.ts +++ b/pages/api/memberships/[id]/edit.ts @@ -1,38 +1,51 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Membership } from "@calcom/prisma/client"; -import { schemaMembership, withValidMembership } from "@lib/validations/membership"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { MembershipResponse } from "@lib/types"; import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; + schemaMembershipBodyParams, + schemaMembershipPublic, + withValidMembership, +} from "@lib/validations/membership"; +import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; -type ResponseData = { - data?: Membership; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/memberships/{id}/edit: + * patch: + * summary: Edits an existing membership + * tags: + * - memberships + * responses: + * 201: + * description: OK, membership edited successfuly + * model: Membership + * 400: + * description: Bad request. Membership body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editMembership(req: NextApiRequest, res: NextApiResponse) { + const safeQuery = await schemaQueryIdAsString.safeParse(req.query); + const safeBody = await schemaMembershipBodyParams.safeParse(req.body); + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const [userId, teamId] = safeQuery.data.id.split("_"); -export async function editMembership(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaMembership.safeParse(body); + const membership = await prisma.membership.update({ + where: { userId_teamId: { userId: parseInt(userId), teamId: parseInt(teamId) } }, + data: safeBody.data, + }); + const data = schemaMembershipPublic.parse(membership); - if (method === "PATCH" && safeQuery.success && safeBody.success) { - const data = await prisma.membership.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 memberships" }); + 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(withValidMembership(editMembership)); +export default withMiddleware("HTTP_PATCH")(withValidQueryIdString(withValidMembership(editMembership))); diff --git a/pages/api/memberships/[id]/index.ts b/pages/api/memberships/[id]/index.ts index 6aef005fa9..5bc5f79496 100644 --- a/pages/api/memberships/[id]/index.ts +++ b/pages/api/memberships/[id]/index.ts @@ -1,29 +1,57 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Membership } from "@calcom/prisma/client"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { MembershipResponse } from "@lib/types"; +import { schemaMembershipPublic } from "@lib/validations/membership"; +import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; -type ResponseData = { - data?: Membership; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/memberships/{userId}_{teamId}: + * get: + * summary: find membership by userID and teamID + * parameters: + * - in: path + * name: userId + * schema: + * type: integer + * required: true + * description: Numeric userId of the membership to get + * - in: path + * name: teamId + * schema: + * type: integer + * required: true + * description: Numeric teamId of the membership to get + * tags: + * - memberships + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Membership was not found + */ +export async function membershipById(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdAsString.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); + const [userId, teamId] = safe.data.id.split("_"); -export async function membership(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "GET" && safe.success) { - const data = await prisma.membership.findUnique({ where: { id: safe.data.id } }); + const membership = await prisma.membership.findUnique({ + where: { userId_teamId: { userId: parseInt(userId), teamId: parseInt(teamId) } }, + }); + const data = schemaMembershipPublic.parse(membership); - 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 (membership) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "Membership was not found", + error, + }); } -export default withValidQueryIdTransformParseInt(membership); +export default withMiddleware("HTTP_GET")(withValidQueryIdString(membershipById)); diff --git a/pages/api/memberships/index.ts b/pages/api/memberships/index.ts index 59e5c21b5c..d53670ce92 100644 --- a/pages/api/memberships/index.ts +++ b/pages/api/memberships/index.ts @@ -1,15 +1,37 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Membership } from "@calcom/prisma/client"; -type ResponseData = { - data?: Membership[]; - error?: unknown; -}; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { MembershipsResponse } from "@lib/types"; +import { schemaMembershipPublic } from "@lib/validations/membership"; + +/** + * @swagger + * /api/memberships: + * get: + * summary: Returns all memberships + * tags: + * - memberships + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No memberships were found + */ +async function allMemberships(_: NextApiRequest, res: NextApiResponse) { + const memberships = await prisma.membership.findMany(); + const data = memberships.map((membership) => schemaMembershipPublic.parse(membership)); -export default async function membership(req: NextApiRequest, res: NextApiResponse) { - const data = await prisma.membership.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 Memberships were found", + error, + }); } + +export default withMiddleware("HTTP_GET")(allMemberships); diff --git a/pages/api/memberships/new.ts b/pages/api/memberships/new.ts index 8df61fc964..e3b9dbe02f 100644 --- a/pages/api/memberships/new.ts +++ b/pages/api/memberships/new.ts @@ -1,26 +1,45 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Membership } from "@calcom/prisma/client"; -import { schemaMembership, withValidMembership } from "@lib/validations/membership"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { MembershipResponse } from "@lib/types"; +import { + schemaMembershipBodyParams, + schemaMembershipPublic, + withValidMembership, +} from "@lib/validations/membership"; -type ResponseData = { - data?: Membership; - message?: string; - error?: string; -}; +/** + * @swagger + * /api/memberships/new: + * post: + * summary: Creates a new membership + * tags: + * - memberships + * responses: + * 201: + * description: OK, membership created + * model: Membership + * 400: + * description: Bad request. Membership body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createMembership(req: NextApiRequest, res: NextApiResponse) { + const safe = schemaMembershipBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -async function createMembership(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - const safe = schemaMembership.safeParse(body); - if (method === "POST" && safe.success) { - await prisma.membership - .create({ data: safe.data }) - .then((data) => res.status(201).json({ data })) - .catch((error) => res.status(400).json({ message: "Could not create membership type", error: error })); - // Reject any other HTTP method than POST - } else res.status(405).json({ error: "Only POST Method allowed" }); + const membership = await prisma.membership.create({ data: safe.data }); + const data = schemaMembershipPublic.parse(membership); + + if (data) res.status(201).json({ data, message: "Membership created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new membership", + error, + }); } -export default withValidMembership(createMembership); +export default withMiddleware("HTTP_POST")(withValidMembership(createMembership)); diff --git a/pages/api/schedules/[id]/delete.ts b/pages/api/schedules/[id]/delete.ts index 17aba616cf..4b037be9d2 100644 --- a/pages/api/schedules/[id]/delete.ts +++ b/pages/api/schedules/[id]/delete.ts @@ -2,27 +2,42 @@ 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/schedules/:id/delete: + * delete: + * summary: Remove an existing schedule + * tags: + * - schedules + * responses: + * 201: + * description: OK, schedule removed successfuly + * model: Schedule + * 400: + * description: Bad request. Schedule id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteSchedule(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 deleteSchedule(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const schedule = await prisma.schedule.delete({ where: { id: safe.data.id } }); - // We only remove the schedule type from the database if there's an existing resource. - if (schedule) res.status(200).json({ message: `schedule with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.schedule.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.schedule.delete({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ message: `Schedule with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `Schedule with id: ${safe.data.id} was not able to be processed`, + error, + }); } -export default withValidQueryIdTransformParseInt(deleteSchedule); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteSchedule)); diff --git a/pages/api/schedules/[id]/edit.ts b/pages/api/schedules/[id]/edit.ts index b40923504e..2f750536f8 100644 --- a/pages/api/schedules/[id]/edit.ts +++ b/pages/api/schedules/[id]/edit.ts @@ -1,38 +1,51 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Schedule } from "@calcom/prisma/client"; -import { schemaSchedule, withValidSchedule } from "@lib/validations/schedule"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { ScheduleResponse } from "@lib/types"; +import { schemaScheduleBodyParams, schemaSchedulePublic, withValidSchedule } from "@lib/validations/schedule"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: Schedule; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/schedules/:id/edit: + * patch: + * summary: Edits an existing schedule + * tags: + * - schedules + * responses: + * 201: + * description: OK, schedule edited successfuly + * model: Schedule + * 400: + * description: Bad request. Schedule body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editSchedule(req: NextApiRequest, res: NextApiResponse) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaScheduleBodyParams.safeParse(req.body); -export async function editSchedule(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaSchedule.safeParse(body); + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const schedule = await prisma.schedule.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaSchedulePublic.parse(schedule); - if (method === "PATCH" && safeQuery.success && safeBody.success) { - const data = await prisma.schedule.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 schedules" }); + 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(withValidSchedule(editSchedule)); +export default withMiddleware("HTTP_PATCH")( + withValidQueryIdTransformParseInt(withValidSchedule(editSchedule)) +); diff --git a/pages/api/schedules/[id]/index.ts b/pages/api/schedules/[id]/index.ts index 482267fcbe..1a8675d53f 100644 --- a/pages/api/schedules/[id]/index.ts +++ b/pages/api/schedules/[id]/index.ts @@ -1,29 +1,51 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Schedule } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { ScheduleResponse } from "@lib/types"; +import { schemaSchedulePublic } from "@lib/validations/schedule"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: Schedule; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/schedules/{id}: + * get: + * summary: Get schedule by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the schedule to delete + * tags: + * - schedules + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Schedule was not found + */ +export async function scheduleById(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); -export async function schedule(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "GET" && safe.success) { - const data = await prisma.schedule.findUnique({ where: { id: safe.data.id } }); + const schedule = await prisma.schedule.findUnique({ where: { id: safe.data.id } }); + const data = schemaSchedulePublic.parse(schedule); - 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 (schedule) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "Schedule was not found", + error, + }); } -export default withValidQueryIdTransformParseInt(schedule); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(scheduleById)); diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index fc22c4e2e0..cd09534c99 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -1,15 +1,37 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Schedule } from "@calcom/prisma/client"; -type ResponseData = { - data?: Schedule[]; - error?: unknown; -}; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { SchedulesResponse } from "@lib/types"; +import { schemaSchedulePublic } from "@lib/validations/schedule"; + +/** + * @swagger + * /api/schedules: + * get: + * summary: Returns all schedules + * tags: + * - schedules + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No schedules were found + */ +async function allSchedules(_: NextApiRequest, res: NextApiResponse) { + const schedules = await prisma.schedule.findMany(); + const data = schedules.map((schedule) => schemaSchedulePublic.parse(schedule)); -export default async function schedule(req: NextApiRequest, res: NextApiResponse) { - const data = await prisma.schedule.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 Schedules were found", + error, + }); } + +export default withMiddleware("HTTP_GET")(allSchedules); diff --git a/pages/api/schedules/new.ts b/pages/api/schedules/new.ts index 081acc9a5c..d4a3ea4416 100644 --- a/pages/api/schedules/new.ts +++ b/pages/api/schedules/new.ts @@ -1,26 +1,41 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Schedule } from "@calcom/prisma/client"; -import { schemaSchedule, withValidSchedule } from "@lib/validations/schedule"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { ScheduleResponse } from "@lib/types"; +import { schemaScheduleBodyParams, schemaSchedulePublic, withValidSchedule } from "@lib/validations/schedule"; -type ResponseData = { - data?: Schedule; - message?: string; - error?: string; -}; +/** + * @swagger + * /api/schedules/new: + * post: + * summary: Creates a new schedule + * tags: + * - schedules + * responses: + * 201: + * description: OK, schedule created + * model: Schedule + * 400: + * description: Bad request. Schedule body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createSchedule(req: NextApiRequest, res: NextApiResponse) { + const safe = schemaScheduleBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -async function createSchedule(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - const safe = schemaSchedule.safeParse(body); - if (method === "POST" && safe.success) { - await prisma.schedule - .create({ data: safe.data }) - .then((data) => res.status(201).json({ data })) - .catch((error) => res.status(400).json({ message: "Could not create schedule type", error: error })); - // Reject any other HTTP method than POST - } else res.status(405).json({ error: "Only POST Method allowed" }); + const schedule = await prisma.schedule.create({ data: safe.data }); + const data = schemaSchedulePublic.parse(schedule); + + if (data) res.status(201).json({ data, message: "Schedule created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new schedule", + error, + }); } -export default withValidSchedule(createSchedule); +export default withMiddleware("HTTP_POST")(withValidSchedule(createSchedule)); diff --git a/pages/api/selected-calendars/[id]/delete.ts b/pages/api/selected-calendars/[id]/delete.ts index 249912dce9..76b949972a 100644 --- a/pages/api/selected-calendars/[id]/delete.ts +++ b/pages/api/selected-calendars/[id]/delete.ts @@ -4,16 +4,27 @@ 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"; +import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; /** * @swagger - * /api/selectedCalendars/:id/delete: + * /api/selected-calendars/{userId}_{teamId}/delete: * delete: - * description: Remove an existing selectedCalendar + * summary: Remove an existing selectedCalendar + * parameters: + * - in: path + * - name: userId + * schema: + * type: integer + * required: true + * description: Numeric ID of the user to get the selectedCalendar of + * * - name: teamId + * schema: + * type: integer + * required: true + * description: Numeric ID of the team to get the selectedCalendar of + * tags: + * - selectedCalendars * responses: * 201: * description: OK, selectedCalendar removed successfuly @@ -24,10 +35,18 @@ import { * description: Authorization information is missing or invalid. */ export async function deleteSelectedCalendar(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); + const safe = await schemaQueryIdAsString.safeParse(req.query); if (!safe.success) throw new Error("Invalid request query", safe.error); - - const data = await prisma.selectedCalendar.delete({ where: { id: safe.data.id } }); + const [userId, integration, externalId] = safe.data.id.split("_"); + const data = await prisma.selectedCalendar.delete({ + where: { + userId_integration_externalId: { + userId: parseInt(userId), + integration: integration, + externalId: externalId, + }, + }, + }); if (data) res.status(200).json({ message: `SelectedCalendar with id: ${safe.data.id} deleted successfully` }); @@ -39,4 +58,4 @@ export async function deleteSelectedCalendar(req: NextApiRequest, res: NextApiRe }); } -export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteSelectedCalendar)); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdString(deleteSelectedCalendar)); diff --git a/pages/api/selected-calendars/[id]/edit.ts b/pages/api/selected-calendars/[id]/edit.ts index 96c9f08675..717afb9c1f 100644 --- a/pages/api/selected-calendars/[id]/edit.ts +++ b/pages/api/selected-calendars/[id]/edit.ts @@ -9,16 +9,15 @@ import { schemaSelectedCalendarPublic, withValidSelectedCalendar, } from "@lib/validations/selected-calendar"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; /** * @swagger - * /api/selectedCalendars/:id/edit: + * /api/selected-calendars/{id}/edit: * patch: - * description: Edits an existing selectedCalendar + * summary: Edits an existing selectedCalendar + * tags: + * - selectedCalendars * responses: * 201: * description: OK, selectedCalendar edited successfuly @@ -32,12 +31,19 @@ export async function editSelectedCalendar( req: NextApiRequest, res: NextApiResponse ) { - const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeQuery = await schemaQueryIdAsString.safeParse(req.query); const safeBody = await schemaSelectedCalendarBodyParams.safeParse(req.body); - if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const [userId, integration, externalId] = safeQuery.data.id.split("_"); + const selectedCalendar = await prisma.selectedCalendar.update({ - where: { id: safeQuery.data.id }, + where: { + userId_integration_externalId: { + userId: parseInt(userId), + integration: integration, + externalId: externalId, + }, + }, data: safeBody.data, }); const data = schemaSelectedCalendarPublic.parse(selectedCalendar); @@ -52,5 +58,5 @@ export async function editSelectedCalendar( } export default withMiddleware("HTTP_PATCH")( - withValidQueryIdTransformParseInt(withValidSelectedCalendar(editSelectedCalendar)) + withValidQueryIdString(withValidSelectedCalendar(editSelectedCalendar)) ); diff --git a/pages/api/selected-calendars/[id]/index.ts b/pages/api/selected-calendars/[id]/index.ts index cf932ac5a2..d88e0116ff 100644 --- a/pages/api/selected-calendars/[id]/index.ts +++ b/pages/api/selected-calendars/[id]/index.ts @@ -5,16 +5,28 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { SelectedCalendarResponse } from "@lib/types"; import { schemaSelectedCalendarPublic } from "@lib/validations/selected-calendar"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; /** * @swagger - * /api/selectedCalendars/:id: + * /api/selected-calendars/{userId}_{teamId}: * get: - * description: find selectedCalendar by ID + * summary: find selectedCalendar by userID and teamID + * parameters: + * - in: path + * name: userId + * schema: + * type: integer + * required: true + * description: Numeric userId of the selectedCalendar to get + * - in: path + * name: teamId + * schema: + * type: integer + * required: true + * description: Numeric teamId of the selectedCalendar to get + * tags: + * - selectedCalendars * responses: * 200: * description: OK @@ -27,10 +39,19 @@ export async function selectedCalendarById( req: NextApiRequest, res: NextApiResponse ) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); + const safe = await schemaQueryIdAsString.safeParse(req.query); if (!safe.success) throw new Error("Invalid request query"); + const [userId, integration, externalId] = safe.data.id.split("_"); - const selectedCalendar = await prisma.selectedCalendar.findUnique({ where: { id: safe.data.id } }); + const selectedCalendar = await prisma.selectedCalendar.findUnique({ + where: { + userId_integration_externalId: { + userId: parseInt(userId), + integration: integration, + externalId: externalId, + }, + }, + }); const data = schemaSelectedCalendarPublic.parse(selectedCalendar); if (selectedCalendar) res.status(200).json({ data }); @@ -42,4 +63,4 @@ export async function selectedCalendarById( }); } -export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(selectedCalendarById)); +export default withMiddleware("HTTP_GET")(withValidQueryIdString(selectedCalendarById)); diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index ab80b3aa0f..cb13635eec 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -10,7 +10,7 @@ import { schemaSelectedCalendarPublic } from "@lib/validations/selected-calendar * @swagger * /api/selectedCalendars: * get: - * description: Returns all selected calendars + * summary: Returns all selected calendars * responses: * 200: * description: OK diff --git a/pages/api/selected-calendars/new.ts b/pages/api/selected-calendars/new.ts index 22ae2a8657..dbca6d85a0 100644 --- a/pages/api/selected-calendars/new.ts +++ b/pages/api/selected-calendars/new.ts @@ -14,7 +14,7 @@ import { * @swagger * /api/selectedCalendars/new: * post: - * description: Creates a new selected calendar + * summary: Creates a new selected calendar * responses: * 201: * description: OK, selected calendar created diff --git a/pages/api/teams/[id]/delete.ts b/pages/api/teams/[id]/delete.ts index cf3825fd96..657e9628ce 100644 --- a/pages/api/teams/[id]/delete.ts +++ b/pages/api/teams/[id]/delete.ts @@ -13,7 +13,9 @@ import { * @swagger * /api/teams/:id/delete: * delete: - * description: Remove an existing team + * summary: Remove an existing team + * tags: + * - teams * responses: * 201: * description: OK, team removed successfuly diff --git a/pages/api/teams/[id]/edit.ts b/pages/api/teams/[id]/edit.ts index 4b1696d207..2b0411cdf8 100644 --- a/pages/api/teams/[id]/edit.ts +++ b/pages/api/teams/[id]/edit.ts @@ -14,7 +14,9 @@ import { schemaTeamBodyParams, schemaTeamPublic, withValidTeam } from "@lib/vali * @swagger * /api/teams/:id/edit: * patch: - * description: Edits an existing team + * summary: Edits an existing team + * tags: + * - teams * responses: * 201: * description: OK, team edited successfuly diff --git a/pages/api/teams/[id]/index.ts b/pages/api/teams/[id]/index.ts index 1047a479ef..218f296308 100644 --- a/pages/api/teams/[id]/index.ts +++ b/pages/api/teams/[id]/index.ts @@ -12,9 +12,18 @@ import { schemaTeamPublic } from "@lib/validations/team"; /** * @swagger - * /api/teams/:id: + * /api/teams/{id}: * get: - * description: find team by ID + * 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 diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index 7497539eeb..a4ed336c38 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -10,7 +10,9 @@ import { schemaTeamPublic } from "@lib/validations/team"; * @swagger * /api/teams: * get: - * description: Returns all teams + * summary: Returns all teams + * tags: + * - teams * responses: * 200: * description: OK diff --git a/pages/api/teams/new.ts b/pages/api/teams/new.ts index b78759d249..6100b5c42d 100644 --- a/pages/api/teams/new.ts +++ b/pages/api/teams/new.ts @@ -10,7 +10,9 @@ import { schemaTeamBodyParams, schemaTeamPublic, withValidTeam } from "@lib/vali * @swagger * /api/teams/new: * post: - * description: Creates a new team + * summary: Creates a new team + * tags: + * - teams * responses: * 201: * description: OK, team created diff --git a/pages/api/users/[id]/delete.ts b/pages/api/users/[id]/delete.ts index 51b6e36cf6..b8b5a7a59f 100644 --- a/pages/api/users/[id]/delete.ts +++ b/pages/api/users/[id]/delete.ts @@ -11,9 +11,18 @@ import { /** * @swagger - * /api/users/:id/delete: + * /api/users/{id}/delete: * delete: - * description: Remove an existing user + * 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 diff --git a/pages/api/users/[id]/edit.ts b/pages/api/users/[id]/edit.ts index b78cb1f83c..4d39bb80ce 100644 --- a/pages/api/users/[id]/edit.ts +++ b/pages/api/users/[id]/edit.ts @@ -12,9 +12,18 @@ import { schemaUserBodyParams, schemaUserPublic, withValidUser } from "@lib/vali /** * @swagger - * /api/users/:id/edit: + * /api/users/{id}/edit: * patch: - * description: Edits an existing user + * summary: Edit an existing user + * parameters: + * - 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 diff --git a/pages/api/users/[id]/index.ts b/pages/api/users/[id]/index.ts index 04be633d5d..59987519b7 100644 --- a/pages/api/users/[id]/index.ts +++ b/pages/api/users/[id]/index.ts @@ -12,9 +12,18 @@ import { schemaUserPublic } from "@lib/validations/user"; /** * @swagger - * /api/users/:id: + * /api/users/{id}: * get: - * description: find user by ID + * 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 diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index a748315a4a..6bb3763a88 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -10,7 +10,9 @@ import { schemaUserPublic } from "@lib/validations/user"; * @swagger * /api/users: * get: - * description: Returns all users + * summary: Get all users + * tags: + * - users * responses: * 200: * description: OK diff --git a/pages/api/users/new.ts b/pages/api/users/new.ts index fd717213e0..52a25015b8 100644 --- a/pages/api/users/new.ts +++ b/pages/api/users/new.ts @@ -10,7 +10,16 @@ import { schemaUserBodyParams, schemaUserPublic, withValidUser } from "@lib/vali * @swagger * /api/users/new: * post: - * description: Creates a new user + * summary: Creates a new user + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/User' + * tags: + * - users * responses: * 201: * description: OK, user created