diff --git a/README.md b/README.md index 17082202cd..4bba94e69a 100644 --- a/README.md +++ b/README.md @@ -108,8 +108,6 @@ We have some shared validations which several resources require, like baseApiPar - **[*]BodyParams** which merges both `[*]BaseBodyParams.merge([*]RequiredParams);` -- **withValid[*]** which is currently not being much used because is only useful in only post endpoints (we do post/get all in same file). This would validate the req.body of a POST call to API against our BaseBodyParams validation - ### Next Validations [Next-Validations Docs](https://next-validations.productsway.com/) @@ -127,9 +125,9 @@ We aim to provide a fully tested API for our peace of mind, this is accomplished | attendees | ✅ | ✅ | ✅ | ✅ | ✅ | | availabilities | ✅ | ✅ | ✅ | ✅ | ✅ | | booking-references | ✅ | ✅ | ✅ | ✅ | ✅ | -| daily-event-references | ✅ | ✅ | ✅ | ✅ | ✅ | +| event-references | ✅ | ✅ | ✅ | ✅ | ✅ | | destination-calendars | ✅ | ✅ | ✅ | ✅ | ✅ | -| event-type-custom-inputs | ✅ | ✅ | ✅ | ✅ | ✅ | +| custom-inputs | ✅ | ✅ | ✅ | ✅ | ✅ | | event-types | ✅ | ✅ | ✅ | ✅ | ✅ | | memberships | ✅ | ✅ | ✅ | ✅ | ✅ | | payments | ✅ | ✅ | ❌ | ❌ | ❌ | diff --git a/json-schema/json-schema.json b/json-schema/json-schema.json deleted file mode 100644 index 1ae113fddf..0000000000 --- a/json-schema/json-schema.json +++ /dev/null @@ -1,1064 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "definitions": { - "EventType": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "title": { - "type": "string", - "description": "@zod.nonempty()" - }, - "slug": { - "type": "string", - "description": "@zod.custom(imports.eventTypeSlug)" - }, - "description": { - "type": ["string", "null"] - }, - "position": { - "type": "integer", - "default": 0 - }, - "locations": { - "type": ["number", "string", "boolean", "object", "array", "null"], - "description": "@zod.custom(imports.eventTypeLocations)" - }, - "length": { - "type": "integer" - }, - "hidden": { - "type": "boolean", - "default": false - }, - "users": { - "type": "array", - "items": { - "$ref": "#/definitions/User" - } - }, - "userId": { - "type": ["integer", "null"] - }, - "team": { - "anyOf": [ - { - "$ref": "#/definitions/Team" - }, - { - "type": "null" - } - ] - }, - "bookings": { - "type": "array", - "items": { - "$ref": "#/definitions/Booking" - } - }, - "availability": { - "type": "array", - "items": { - "$ref": "#/definitions/Availability" - } - }, - "webhooks": { - "type": "array", - "items": { - "$ref": "#/definitions/Webhook" - } - }, - "destinationCalendar": { - "anyOf": [ - { - "$ref": "#/definitions/DestinationCalendar" - }, - { - "type": "null" - } - ] - }, - "eventName": { - "type": ["string", "null"] - }, - "customInputs": { - "type": "array", - "items": { - "$ref": "#/definitions/EventTypeCustomInput" - } - }, - "timeZone": { - "type": ["string", "null"] - }, - "periodType": { - "type": "string", - "default": "UNLIMITED", - "enum": ["UNLIMITED", "ROLLING", "RANGE"] - }, - "periodStartDate": { - "type": ["string", "null"], - "format": "date-time" - }, - "periodEndDate": { - "type": ["string", "null"], - "format": "date-time" - }, - "periodDays": { - "type": ["integer", "null"] - }, - "periodCountCalendarDays": { - "type": ["boolean", "null"] - }, - "requiresConfirmation": { - "type": "boolean", - "default": false - }, - "disableGuests": { - "type": "boolean", - "default": false - }, - "minimumBookingNotice": { - "type": "integer", - "default": 120 - }, - "beforeEventBuffer": { - "type": "integer", - "default": 0 - }, - "afterEventBuffer": { - "type": "integer", - "default": 0 - }, - "schedulingType": { - "type": ["string", "null"], - "enum": ["ROUND_ROBIN", "COLLECTIVE"] - }, - "schedule": { - "anyOf": [ - { - "$ref": "#/definitions/Schedule" - }, - { - "type": "null" - } - ] - }, - "price": { - "type": "integer", - "default": 0 - }, - "currency": { - "type": "string", - "default": "usd" - }, - "slotInterval": { - "type": ["integer", "null"] - }, - "metadata": { - "type": ["number", "string", "boolean", "object", "array", "null"] - } - } - }, - "Credential": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "type": { - "type": "string" - }, - "key": { - "type": ["number", "string", "boolean", "object", "array", "null"] - }, - "user": { - "anyOf": [ - { - "$ref": "#/definitions/User" - }, - { - "type": "null" - } - ] - } - } - }, - "DestinationCalendar": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "integration": { - "type": "string" - }, - "externalId": { - "type": "string" - }, - "user": { - "anyOf": [ - { - "$ref": "#/definitions/User" - }, - { - "type": "null" - } - ] - }, - "booking": { - "anyOf": [ - { - "$ref": "#/definitions/Booking" - }, - { - "type": "null" - } - ] - }, - "eventType": { - "anyOf": [ - { - "$ref": "#/definitions/EventType" - }, - { - "type": "null" - } - ] - } - } - }, - "User": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "username": { - "type": ["string", "null"] - }, - "name": { - "type": ["string", "null"] - }, - "email": { - "type": "string", - "description": "@zod.email()" - }, - "emailVerified": { - "type": ["string", "null"], - "format": "date-time" - }, - "password": { - "type": ["string", "null"] - }, - "bio": { - "type": ["string", "null"] - }, - "avatar": { - "type": ["string", "null"] - }, - "timeZone": { - "type": "string", - "default": "Europe/London" - }, - "weekStart": { - "type": "string", - "default": "Sunday" - }, - "startTime": { - "type": "integer", - "default": 0 - }, - "endTime": { - "type": "integer", - "default": 1440 - }, - "bufferTime": { - "type": "integer", - "default": 0 - }, - "hideBranding": { - "type": "boolean", - "default": false - }, - "theme": { - "type": ["string", "null"] - }, - "createdDate": { - "type": "string", - "format": "date-time" - }, - "trialEndsAt": { - "type": ["string", "null"], - "format": "date-time" - }, - "eventTypes": { - "type": "array", - "items": { - "$ref": "#/definitions/EventType" - } - }, - "credentials": { - "type": "array", - "items": { - "$ref": "#/definitions/Credential" - } - }, - "teams": { - "type": "array", - "items": { - "$ref": "#/definitions/Membership" - } - }, - "bookings": { - "type": "array", - "items": { - "$ref": "#/definitions/Booking" - } - }, - "schedules": { - "type": "array", - "items": { - "$ref": "#/definitions/Schedule" - } - }, - "defaultScheduleId": { - "type": ["integer", "null"] - }, - "selectedCalendars": { - "type": "array", - "items": { - "$ref": "#/definitions/SelectedCalendar" - } - }, - "completedOnboarding": { - "type": "boolean", - "default": false - }, - "locale": { - "type": ["string", "null"] - }, - "timeFormat": { - "type": ["integer", "null"], - "default": 12 - }, - "twoFactorSecret": { - "type": ["string", "null"] - }, - "twoFactorEnabled": { - "type": "boolean", - "default": false - }, - "identityProvider": { - "type": "string", - "default": "CAL", - "enum": ["CAL", "GOOGLE", "SAML"] - }, - "identityProviderId": { - "type": ["string", "null"] - }, - "availability": { - "type": "array", - "items": { - "$ref": "#/definitions/Availability" - } - }, - "invitedTo": { - "type": ["integer", "null"] - }, - "plan": { - "type": "string", - "default": "TRIAL", - "enum": ["FREE", "TRIAL", "PRO"] - }, - "webhooks": { - "type": "array", - "items": { - "$ref": "#/definitions/Webhook" - } - }, - "brandColor": { - "type": "string", - "default": "#292929" - }, - "darkBrandColor": { - "type": "string", - "default": "#fafafa" - }, - "destinationCalendar": { - "anyOf": [ - { - "$ref": "#/definitions/DestinationCalendar" - }, - { - "type": "null" - } - ] - }, - "away": { - "type": "boolean", - "default": false - }, - "metadata": { - "type": ["number", "string", "boolean", "object", "array", "null"] - }, - "verified": { - "type": ["boolean", "null"], - "default": false - }, - "apiKeys": { - "type": "array", - "items": { - "$ref": "#/definitions/ApiKey" - } - } - } - }, - "Team": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": ["string", "null"] - }, - "slug": { - "type": ["string", "null"] - }, - "logo": { - "type": ["string", "null"] - }, - "bio": { - "type": ["string", "null"] - }, - "hideBranding": { - "type": "boolean", - "default": false - }, - "members": { - "type": "array", - "items": { - "$ref": "#/definitions/Membership" - } - }, - "eventTypes": { - "type": "array", - "items": { - "$ref": "#/definitions/EventType" - } - } - } - }, - "Membership": { - "type": "object", - "properties": { - "accepted": { - "type": "boolean", - "default": false - }, - "role": { - "type": "string", - "enum": ["MEMBER", "ADMIN", "OWNER"] - }, - "team": { - "$ref": "#/definitions/Team" - }, - "user": { - "$ref": "#/definitions/User" - } - } - }, - "VerificationRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "identifier": { - "type": "string" - }, - "token": { - "type": "string" - }, - "expires": { - "type": "string", - "format": "date-time" - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - } - } - }, - "BookingReference": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "type": { - "type": "string" - }, - "uid": { - "type": "string" - }, - "meetingId": { - "type": ["string", "null"] - }, - "meetingPassword": { - "type": ["string", "null"] - }, - "meetingUrl": { - "type": ["string", "null"] - }, - "booking": { - "anyOf": [ - { - "$ref": "#/definitions/Booking" - }, - { - "type": "null" - } - ] - } - } - }, - "Attendee": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "email": { - "type": "string" - }, - "name": { - "type": "string" - }, - "timeZone": { - "type": "string" - }, - "locale": { - "type": ["string", "null"], - "default": "en" - }, - "booking": { - "anyOf": [ - { - "$ref": "#/definitions/Booking" - }, - { - "type": "null" - } - ] - } - } - }, - "DailyEventReference": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "dailyurl": { - "type": "string", - "default": "dailycallurl" - }, - "dailytoken": { - "type": "string", - "default": "dailytoken" - }, - "booking": { - "anyOf": [ - { - "$ref": "#/definitions/Booking" - }, - { - "type": "null" - } - ] - } - } - }, - "Booking": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "uid": { - "type": "string" - }, - "user": { - "anyOf": [ - { - "$ref": "#/definitions/User" - }, - { - "type": "null" - } - ] - }, - "references": { - "type": "array", - "items": { - "$ref": "#/definitions/BookingReference" - } - }, - "eventType": { - "anyOf": [ - { - "$ref": "#/definitions/EventType" - }, - { - "type": "null" - } - ] - }, - "title": { - "type": "string" - }, - "description": { - "type": ["string", "null"] - }, - "startTime": { - "type": "string", - "format": "date-time" - }, - "endTime": { - "type": "string", - "format": "date-time" - }, - "attendees": { - "type": "array", - "items": { - "$ref": "#/definitions/Attendee" - } - }, - "location": { - "type": ["string", "null"] - }, - "dailyRef": { - "anyOf": [ - { - "$ref": "#/definitions/DailyEventReference" - }, - { - "type": "null" - } - ] - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": ["string", "null"], - "format": "date-time" - }, - "confirmed": { - "type": "boolean", - "default": true - }, - "rejected": { - "type": "boolean", - "default": false - }, - "status": { - "type": "string", - "default": "ACCEPTED", - "enum": ["CANCELLED", "ACCEPTED", "REJECTED", "PENDING"] - }, - "paid": { - "type": "boolean", - "default": false - }, - "payment": { - "type": "array", - "items": { - "$ref": "#/definitions/Payment" - } - }, - "destinationCalendar": { - "anyOf": [ - { - "$ref": "#/definitions/DestinationCalendar" - }, - { - "type": "null" - } - ] - }, - "cancellationReason": { - "type": ["string", "null"] - }, - "rejectionReason": { - "type": ["string", "null"] - } - } - }, - "Schedule": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "user": { - "$ref": "#/definitions/User" - }, - "eventType": { - "anyOf": [ - { - "$ref": "#/definitions/EventType" - }, - { - "type": "null" - } - ] - }, - "name": { - "type": "string" - }, - "timeZone": { - "type": ["string", "null"] - }, - "availability": { - "type": "array", - "items": { - "$ref": "#/definitions/Availability" - } - } - } - }, - "Availability": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "user": { - "anyOf": [ - { - "$ref": "#/definitions/User" - }, - { - "type": "null" - } - ] - }, - "eventType": { - "anyOf": [ - { - "$ref": "#/definitions/EventType" - }, - { - "type": "null" - } - ] - }, - "days": { - "type": "array", - "items": { - "type": "integer" - } - }, - "startTime": { - "type": "string", - "format": "date-time" - }, - "endTime": { - "type": "string", - "format": "date-time" - }, - "date": { - "type": ["string", "null"], - "format": "date-time" - }, - "Schedule": { - "anyOf": [ - { - "$ref": "#/definitions/Schedule" - }, - { - "type": "null" - } - ] - } - } - }, - "SelectedCalendar": { - "type": "object", - "properties": { - "user": { - "$ref": "#/definitions/User" - }, - "integration": { - "type": "string" - }, - "externalId": { - "type": "string" - } - } - }, - "EventTypeCustomInput": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "eventType": { - "$ref": "#/definitions/EventType" - }, - "label": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["TEXT", "TEXTLONG", "NUMBER", "BOOL"] - }, - "required": { - "type": "boolean" - }, - "placeholder": { - "type": "string", - "default": "" - } - } - }, - "ResetPasswordRequest": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - }, - "email": { - "type": "string" - }, - "expires": { - "type": "string", - "format": "date-time" - } - } - }, - "ReminderMail": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "referenceId": { - "type": "integer" - }, - "reminderType": { - "type": "string", - "enum": ["PENDING_BOOKING_CONFIRMATION"] - }, - "elapsedMinutes": { - "type": "integer" - }, - "createdAt": { - "type": "string", - "format": "date-time" - } - } - }, - "Payment": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "uid": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["STRIPE"] - }, - "booking": { - "anyOf": [ - { - "$ref": "#/definitions/Booking" - }, - { - "type": "null" - } - ] - }, - "amount": { - "type": "integer" - }, - "fee": { - "type": "integer" - }, - "currency": { - "type": "string" - }, - "success": { - "type": "boolean" - }, - "refunded": { - "type": "boolean" - }, - "data": { - "type": ["number", "string", "boolean", "object", "array", "null"] - }, - "externalId": { - "type": "string" - } - } - }, - "Webhook": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "subscriberUrl": { - "type": "string" - }, - "payloadTemplate": { - "type": ["string", "null"] - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "active": { - "type": "boolean", - "default": true - }, - "eventTriggers": { - "type": "array", - "enum": ["BOOKING_CREATED", "BOOKING_RESCHEDULED", "BOOKING_CANCELLED"] - }, - "user": { - "anyOf": [ - { - "$ref": "#/definitions/User" - }, - { - "type": "null" - } - ] - }, - "eventType": { - "anyOf": [ - { - "$ref": "#/definitions/EventType" - }, - { - "type": "null" - } - ] - } - } - }, - "ApiKey": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "user": { - "anyOf": [ - { - "$ref": "#/definitions/User" - }, - { - "type": "null" - } - ] - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "expiresAt": { - "type": "string", - "format": "date-time" - }, - "note": { - "type": ["string", "null"] - } - } - } - }, - "type": "object", - "properties": { - "eventType": { - "$ref": "#/definitions/EventType" - }, - "credential": { - "$ref": "#/definitions/Credential" - }, - "destinationCalendar": { - "$ref": "#/definitions/DestinationCalendar" - }, - "user": { - "$ref": "#/definitions/User" - }, - "team": { - "$ref": "#/definitions/Team" - }, - "membership": { - "$ref": "#/definitions/Membership" - }, - "verificationRequest": { - "$ref": "#/definitions/VerificationRequest" - }, - "bookingReference": { - "$ref": "#/definitions/BookingReference" - }, - "attendee": { - "$ref": "#/definitions/Attendee" - }, - "dailyEventReference": { - "$ref": "#/definitions/DailyEventReference" - }, - "booking": { - "$ref": "#/definitions/Booking" - }, - "schedule": { - "$ref": "#/definitions/Schedule" - }, - "availability": { - "$ref": "#/definitions/Availability" - }, - "selectedCalendar": { - "$ref": "#/definitions/SelectedCalendar" - }, - "eventTypeCustomInput": { - "$ref": "#/definitions/EventTypeCustomInput" - }, - "resetPasswordRequest": { - "$ref": "#/definitions/ResetPasswordRequest" - }, - "reminderMail": { - "$ref": "#/definitions/ReminderMail" - }, - "payment": { - "$ref": "#/definitions/Payment" - }, - "webhook": { - "$ref": "#/definitions/Webhook" - }, - "apiKey": { - "$ref": "#/definitions/ApiKey" - } - } -} diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index cf5c4a8472..c4fabac652 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -8,6 +8,8 @@ import prisma from "@calcom/prisma"; declare module "next" { export interface NextApiRequest extends IncomingMessage { userId: number; + body: any; + query: { [key: string]: string | string[] }; } } @@ -20,21 +22,21 @@ export const dateNotInPast = function (date: Date) { }; // This verifies the apiKey and sets the user if it is valid. -export const verifyApiKey: NextMiddleware = async (req, res, next) => { - if (!req.query.apiKey) return res.status(401).json({ message: "No apiKey provided" }); +export const verifyApiKey: NextMiddleware = async ({ query: { apiKey }, ...req }, res, next) => { + if (!apiKey) return res.status(401).json({ message: "No apiKey provided" }); // We remove the prefix from the user provided api_key. If no env set default to "cal_" - const strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX || "cal_", ""); + const strippedApiKey = `${apiKey}`.replace(process.env.API_KEY_PREFIX || " cal_", ""); // Hash the key again before matching against the database records. const hashedKey = hashAPIKey(strippedApiKey); // Check if the hashed api key exists in database. - const apiKey = await prisma.apiKey.findUnique({ where: { hashedKey } }); + const validApiKey = await prisma.apiKey.findUnique({ where: { hashedKey } }); // If we cannot find any api key. Throw a 401 Unauthorized. - if (!apiKey) return res.status(401).json({ error: "Your apiKey is not valid" }); - if (apiKey.expiresAt && dateNotInPast(apiKey.expiresAt)) { + if (!validApiKey) return res.status(401).json({ error: "Your apiKey is not valid" }); + if (validApiKey.expiresAt && dateNotInPast(validApiKey.expiresAt)) { return res.status(401).json({ error: "This apiKey is expired" }); } - if (!apiKey.userId) return res.status(404).json({ error: "No user found for this apiKey" }); + if (!validApiKey.userId) return res.status(404).json({ error: "No user found for this apiKey" }); /* We save the user id in the request for later use */ - req.userId = apiKey.userId; + req.userId = validApiKey.userId; await next(); }; diff --git a/next.config.js b/next.config.js index fa5bc84e10..1542c7f0ff 100644 --- a/next.config.js +++ b/next.config.js @@ -1,5 +1,3 @@ -// https://www.npmjs.com/package/next-transpile-modules -// This makes our @calcom/prisma package from the monorepo to be transpiled and usable by API const withTM = require("next-transpile-modules")([ "@calcom/app-store", "@calcom/prisma", @@ -7,13 +5,11 @@ const withTM = require("next-transpile-modules")([ "@calcom/ee", ]); -// use something like withPlugins([withTM], {}) if more plugins added later. - module.exports = withTM({ async headers() { return [ { - // matching all API routes + // @note: disabling CORS matching all API routes as this will be a our Public API source: "/api/:path*", headers: [ { key: "Access-Control-Allow-Credentials", value: "true" }, @@ -30,12 +26,12 @@ module.exports = withTM({ }, async rewrites() { return [ - // This redirects requests recieved at / the root to the /api/ folder. + // @note: redirects requests from: "/:rest*" the root level to the "/api/:rest*" folder by default. { source: "/:rest*", destination: "/api/:rest*", }, - // This redirects requests to api/v*/ to /api/ passing version as a query parameter. + // @note: redirects requests from api/v*/:rest to /api/:rest?version=* passing version as a query parameter. { source: "/api/v:version/:rest*", destination: "/api/:rest*?version=:version", diff --git a/package.json b/package.json index 0c1cb9556e..42f655236a 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "dependencies": { "@calcom/prisma": "*", "@sentry/nextjs": "^6.19.3", + "modify-response-middleware": "^1.1.0", "next": "^12.1.4", "next-api-middleware": "^1.0.1", "next-swagger-doc": "^0.2.1", diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index ce41228cd0..9a2e40f106 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -10,115 +10,56 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -/** - * @swagger - * /attendees/{id}: - * get: - * summary: Find an attendee by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the attendee to get - * example: 3 - * security: - * - ApiKeyAuth: [] - * tags: - * - attendees - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Attendee was not found - * patch: - * summary: Edit an existing attendee - * consumes: - * - application/json - * requestBody: - * description: Edit an existing attendee related to one of your bookings - * required: true - * content: - * application/json: - * schema: - * type: object - * required: - * - bookingId - * - name - * - email - * - timeZone - * properties: - * email: - * type: string - * example: email@example.com - * name: - * type: string - * example: John Doe - * timeZone: - * type: string - * example: Europe/London - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * example: 3 - * required: true - * description: Numeric ID of the attendee to edit - * security: - * - ApiKeyAuth: [] - * 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. - * delete: - * summary: Remove an existing attendee - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the attendee to delete - * security: - * - ApiKeyAuth: [] - * 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 attendeeById(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body, userId } = req; +export async function attendeeById( + { method, query, body, userId }: NextApiRequest, + res: NextApiResponse +) { const safeQuery = schemaQueryIdParseInt.safeParse(query); if (!safeQuery.success) { res.status(400).json({ error: safeQuery.error }); throw new Error("Invalid request query", safeQuery.error); } - const userBookings = await prisma.booking.findMany({ - where: { userId }, - include: { attendees: true }, - }); - const attendees = userBookings.map((booking) => booking.attendees).flat(); - const attendeeIds = attendees.map((attendee) => attendee.id); - // Here we make sure to only return attendee's of the user's own bookings. - if (!attendeeIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); + const userBookingsAttendeeIds = await prisma.booking + // Find all user bookings, including attendees + .findMany({ + where: { userId }, + include: { attendees: true }, + }) + .then( + // Flatten and merge all the attendees in one array + (bookings) => + bookings + .map((bookings) => bookings.attendees) + .flat() + .map((attendee) => attendee.id) + ); + // @note: Here we make sure to only return attendee's of the user's own bookings. + if (!userBookingsAttendeeIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); else { switch (method) { + /** + * @swagger + * /attendees/{id}: + * get: + * summary: Find an attendee + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the attendee to get + * example: 3 + * tags: + * - attendees + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Attendee was not found + */ case "GET": await prisma.attendee .findUnique({ where: { id: safeQuery.data.id } }) @@ -131,7 +72,51 @@ export async function attendeeById(req: NextApiRequest, res: NextApiResponse ) { - const { method, userId } = req; - // Here we make sure to only return attendee's of the user's own bookings. const userBookings = await prisma.booking.findMany({ where: { userId, @@ -80,6 +20,21 @@ async function createOrlistAllAttendees( }); const attendees = userBookings.map((booking) => booking.attendees).flat(); if (method === "GET") { + /** + * @swagger + * /attendees: + * get: + * summary: Find all attendees + * tags: + * - attendees + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No attendees were found + */ if (attendees) res.status(200).json({ attendees }); else (error: Error) => @@ -88,13 +43,51 @@ async function createOrlistAllAttendees( error, }); } else if (method === "POST") { - const safePost = schemaAttendeeCreateBodyParams.safeParse(req.body); + /** + * @swagger + * /attendees: + * post: + * summary: Creates a new attendee + * requestBody: + * description: Create a new attendee related to one of your bookings + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - bookingId + * - name + * - email + * - timeZone + * properties: + * bookingId: + * type: number + * example: 1 + * email: + * type: string + * example: email@example.com + * name: + * type: string + * example: John Doe + * timeZone: + * type: string + * example: Europe/London + * tags: + * - attendees + * responses: + * 201: + * description: OK, attendee created + * 400: + * description: Bad request. Attendee body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safePost = schemaAttendeeCreateBodyParams.safeParse(body); if (!safePost.success) { - console.log(safePost.error); res.status(400).json({ error: safePost.error }); throw new Error("Invalid request body", safePost.error); } - const userId = req.userId; const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, include: { bookings: true }, @@ -102,7 +95,7 @@ async function createOrlistAllAttendees( if (!userWithBookings) { throw new Error("User not found"); } - const userBookingIds = userWithBookings.bookings.map((booking: any) => booking.id).flat(); + const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); // Here we make sure to only return attendee's of the user's own bookings. if (!userBookingIds.includes(safePost.data.bookingId)) res.status(401).json({ message: "Unauthorized" }); else { diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index 65f750dba7..139e36e22f 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -13,97 +13,41 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -/** - * @swagger - * /availabilities/{id}: - * get: - * summary: Find an availability by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the availability to get - * security: - * - ApiKeyAuth: [] - * tags: - * - availabilities - * externalDocs: - * url: https://docs.cal.com/availability - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Availability was not found - * patch: - * summary: Edit an existing availability - * consumes: - * - application/json - * parameters: - * - in: body - * name: availability - * description: The availability to edit - * schema: - * type: object - * $ref: '#/components/schemas/Availability' - * required: true - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the availability to edit - * security: - * - ApiKeyAuth: [] - * tags: - * - availabilities - * externalDocs: - * url: https://docs.cal.com/availability - * 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. - * delete: - * summary: Remove an existing availability - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the availability to delete - * security: - * - ApiKeyAuth: [] - * tags: - * - availabilities - * externalDocs: - * url: https://docs.cal.com/availability - * 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 availabilityById(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body } = req; +export async function availabilityById( + { method, query, body, userId }: NextApiRequest, + res: NextApiResponse +) { const safeQuery = schemaQueryIdParseInt.safeParse(query); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = req.userId; const data = await prisma.availability.findMany({ where: { userId } }); const availabiltiesIds = data.map((availability) => availability.id); if (!availabiltiesIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); else { switch (method) { + /** + * @swagger + * /availabilities/{id}: + * get: + * summary: Find an availability + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the availability to get + * tags: + * - availabilities + * externalDocs: + * url: https://docs.cal.com/availability + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Availability was not found + */ case "GET": await prisma.availability .findUnique({ where: { id: safeQuery.data.id } }) @@ -113,7 +57,30 @@ export async function availabilityById(req: NextApiRequest, res: NextApiResponse res.status(404).json({ message: `Availability with id: ${safeQuery.data.id} not found`, error }) ); break; - + /** + * @swagger + * /availabilities/{id}: + * 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: + * - availabilities + * externalDocs: + * url: https://docs.cal.com/availability + * responses: + * 201: + * description: OK, availability edited successfuly + * 400: + * description: Bad request. Availability body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ case "PATCH": const safeBody = schemaAvailabilityEditBodyParams.safeParse(body); if (!safeBody.success) throw new Error("Invalid request body"); @@ -132,14 +99,36 @@ export async function availabilityById(req: NextApiRequest, res: NextApiResponse .then((data) => schemaAvailabilityReadPublic.parse(data)) .then((availability) => res.status(200).json({ availability })) .catch((error: Error) => { - console.log(error); res.status(404).json({ message: `Availability with id: ${safeQuery.data.id} not found`, error, }); }); break; - + /** + * @swagger + * /availabilities/{id}: + * 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: + * - availabilities + * externalDocs: + * url: https://docs.cal.com/availability + * responses: + * 201: + * description: OK, availability removed successfuly + * 400: + * description: Bad request. Availability id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ case "DELETE": await prisma.availability .delete({ where: { id: safeQuery.data.id } }) diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index 3e519bc6ad..c7b53c211d 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -9,49 +9,28 @@ import { schemaAvailabilityReadPublic, } from "@lib/validations/availability"; -/** - * @swagger - * /availabilities: - * get: - * summary: Find all availabilities - * security: - * - ApiKeyAuth: [] - * tags: - * - availabilities - * externalDocs: - * url: https://docs.cal.com/availability - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No availabilities were found - * post: - * summary: Creates a new availability - * security: - * - ApiKeyAuth: [] - * tags: - * - availabilities - * externalDocs: - * url: https://docs.cal.com/availability - * 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 createOrlistAllAvailabilities( - req: NextApiRequest, + { method, body, userId }: NextApiRequest, res: NextApiResponse ) { - const { method } = req; - const userId = req.userId; - if (method === "GET") { + /** + * @swagger + * /availabilities: + * get: + * summary: Find all availabilities + * tags: + * - availabilities + * externalDocs: + * url: https://docs.cal.com/availability + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No availabilities were found + */ const data = await prisma.availability.findMany({ where: { userId } }); const availabilities = data.map((availability) => schemaAvailabilityReadPublic.parse(availability)); if (availabilities) res.status(200).json({ availabilities }); @@ -62,11 +41,27 @@ async function createOrlistAllAvailabilities( error, }); } else if (method === "POST") { - const safe = schemaAvailabilityCreateBodyParams.safeParse(req.body); + /** + * @swagger + * /availabilities: + * post: + * summary: Creates a new availability + * tags: + * - availabilities + * externalDocs: + * url: https://docs.cal.com/availability + * responses: + * 201: + * description: OK, availability created + * 400: + * description: Bad request. Availability body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safe = schemaAvailabilityCreateBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.availability.create({ data: { ...safe.data, userId } }); - console.log(data); const availability = schemaAvailabilityReadPublic.parse(data); if (availability) res.status(201).json({ availability, message: "Availability created successfully" }); diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index 21b314f728..03bc87fafb 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -14,100 +14,46 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -/** - * @swagger - * /booking-references/{id}: - * get: - * summary: Find a booking reference by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the booking reference to get - * security: - * - ApiKeyAuth: [] - * tags: - * - booking-references - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: BookingReference was not found - * patch: - * summary: Edit an existing booking reference - * consumes: - * - application/json - * parameters: - * - in: body - * name: bookingReference - * description: The bookingReference to edit - * schema: - * type: object - * $ref: '#/components/schemas/BookingReference' - * required: true - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the booking reference to edit - * security: - * - ApiKeyAuth: [] - * tags: - * - booking-references - * 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. - * delete: - * summary: Remove an existing booking reference - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the booking reference to delete - * security: - * - ApiKeyAuth: [] - * tags: - * - booking-references - * 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 bookingReferenceById( - req: NextApiRequest, + { method, query, body, userId }: NextApiRequest, res: NextApiResponse ) { - const { method, query, body } = req; const safeQuery = schemaQueryIdParseInt.safeParse(query); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = req.userId; const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, include: { bookings: true }, }); if (!userWithBookings) throw new Error("User not found"); - const userBookingIds = userWithBookings.bookings.map((booking: any) => booking.id).flat(); + const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); const bookingReference = await prisma.bookingReference.findUnique({ where: { id: safeQuery.data.id } }); - if (!bookingReference) throw new Error("BookingReference not found"); + if (!bookingReference?.bookingId) throw new Error("BookingReference: bookingId not found"); if (userBookingIds.includes(bookingReference.bookingId)) { switch (method) { case "GET": + /** + * @swagger + * /booking-references/{id}: + * get: + * summary: Find a booking reference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the booking reference to get + * tags: + * - booking-references + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: BookingReference was not found + */ + await prisma.bookingReference .findUnique({ where: { id: safeQuery.data.id } }) .then((data) => schemaBookingReferenceReadPublic.parse(data)) @@ -118,11 +64,33 @@ export async function bookingReferenceById( error, }) ); + break; - case "PATCH": - const safeBody = schemaBookingEditBodyParams.safeParse(body); + /** + * @swagger + * /booking-references/{id}: + * patch: + * summary: Edit an existing booking reference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the booking reference to edit + * tags: + * - booking-references + * responses: + * 201: + * description: OK, bookingReference edited successfuly + * 400: + * description: Bad request. BookingReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safeBody = schemaBookingEditBodyParams.safeParse(body); if (!safeBody.success) { throw new Error("Invalid request body"); } @@ -137,7 +105,28 @@ export async function bookingReferenceById( }) ); break; - + /** + * @swagger + * /booking-references/{id}: + * delete: + * summary: Remove an existing booking reference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the booking reference to delete + * tags: + * - booking-references + * responses: + * 201: + * description: OK, bookingReference removed successfuly + * 400: + * description: Bad request. BookingReference id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ case "DELETE": await prisma.bookingReference .delete({ diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index bc82f23701..c228673240 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -9,50 +9,32 @@ import { schemaBookingReferenceReadPublic, } from "@lib/validations/booking-reference"; -/** - * @swagger - * /booking-references: - * get: - * summary: Find all booking references - * security: - * - ApiKeyAuth: [] - * tags: - * - booking-references - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No booking references were found - * post: - * summary: Creates a new booking reference - * security: - * - ApiKeyAuth: [] - * tags: - * - booking-references - * responses: - * 201: - * description: OK, booking reference created - * model: BookingReference - * 400: - * description: Bad request. BookingReference body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ async function createOrlistAllBookingReferences( - req: NextApiRequest, + { method, userId, body }: NextApiRequest, res: NextApiResponse ) { - const { method } = req; - const userId = req.userId; const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, include: { bookings: true }, }); if (!userWithBookings) throw new Error("User not found"); - const userBookingIds = userWithBookings.bookings.map((booking: any) => booking.id).flat(); + const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); if (method === "GET") { + /** + * @swagger + * /booking-references: + * get: + * summary: Find all booking references + * tags: + * - booking-references + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No booking references were found + */ const data = await prisma.bookingReference.findMany({ where: { id: { in: userBookingIds } } }); const booking_references = data.map((bookingReference) => schemaBookingReferenceReadPublic.parse(bookingReference) @@ -65,13 +47,26 @@ async function createOrlistAllBookingReferences( error, }); } else if (method === "POST") { - const safe = schemaBookingCreateBodyParams.safeParse(req.body); + /** + * @swagger + * /booking-references: + * post: + * summary: Creates a new booking reference + * tags: + * - booking-references + * responses: + * 201: + * description: OK, booking reference created + * 400: + * description: Bad request. BookingReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safe = schemaBookingCreateBodyParams.safeParse(body); if (!safe.success) { throw new Error("Invalid request body"); } - // const booking_reference = schemaBookingReferencePublic.parse(data); - const userId = req.userId; const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, include: { bookings: true }, @@ -79,7 +74,8 @@ async function createOrlistAllBookingReferences( if (!userWithBookings) { throw new Error("User not found"); } - const userBookingIds = userWithBookings.bookings.map((booking: any) => booking.id).flat(); + const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); + if (!safe.data.bookingId) throw new Error("BookingReference: bookingId not found"); if (!userBookingIds.includes(safe.data.bookingId)) res.status(401).json({ message: "Unauthorized" }); else { const booking_reference = await prisma.bookingReference.create({ diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index 21be432cd1..21fdd9a937 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -10,95 +10,43 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -/** - * @swagger - * /bookings/{id}: - * get: - * summary: Find a booking by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the booking to get - * security: - * - ApiKeyAuth: [] - * tags: - * - bookings - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Booking was not found - * patch: - * summary: Edit an existing booking - * consumes: - * - application/json - * parameters: - * - in: body - * name: booking - * description: The booking to edit - * schema: - * type: object - * $ref: '#/components/schemas/Booking' - * required: true - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the booking to edit - * security: - * - ApiKeyAuth: [] - * 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. - * delete: - * summary: Remove an existing booking - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the booking to delete - * security: - * - ApiKeyAuth: [] - * 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 bookingById(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body } = req; +export async function bookingById( + { method, query, body, userId }: NextApiRequest, + res: NextApiResponse +) { const safeQuery = schemaQueryIdParseInt.safeParse(query); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = req.userId; const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, include: { bookings: true }, }); if (!userWithBookings) throw new Error("User not found"); - const userBookingIds = userWithBookings.bookings.map((booking: any) => booking.id).flat(); + const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); if (!userBookingIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); else { switch (method) { + /** + * @swagger + * /bookings/{id}: + * get: + * summary: Find a booking + * 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 + */ case "GET": await prisma.booking .findUnique({ where: { id: safeQuery.data.id } }) @@ -111,10 +59,30 @@ export async function bookingById(req: NextApiRequest, res: NextApiResponse ) { - const { method } = req; - const userId = req.userId; - if (method === "GET") { + /** + * @swagger + * /bookings: + * get: + * summary: Find all bookings + * tags: + * - bookings + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No bookings were found + */ const data = await prisma.booking.findMany({ where: { userId } }); const bookings = data.map((booking) => schemaBookingReadPublic.parse(booking)); if (bookings) res.status(200).json({ bookings }); @@ -55,7 +36,22 @@ async function createOrlistAllBookings( error, }); } else if (method === "POST") { - const safe = schemaBookingCreateBodyParams.safeParse(req.body); + /** + * @swagger + * /bookings: + * post: + * summary: Creates a new booking + * tags: + * - bookings + * responses: + * 201: + * description: OK, booking created + * 400: + * description: Bad request. Booking body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safe = schemaBookingCreateBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.booking.create({ data: { ...safe.data, userId } }); diff --git a/pages/api/event-type-custom-inputs/[id].ts b/pages/api/custom-inputs/[id].ts similarity index 80% rename from pages/api/event-type-custom-inputs/[id].ts rename to pages/api/custom-inputs/[id].ts index 7d3ffa7a5d..3339f31027 100644 --- a/pages/api/event-type-custom-inputs/[id].ts +++ b/pages/api/custom-inputs/[id].ts @@ -15,9 +15,9 @@ import { /** * @swagger - * /event-type-custom-inputs/{id}: + * /custom-inputs/{id}: * get: - * summary: Find a eventTypeCustomInput by ID + * summary: Find a eventTypeCustomInput * parameters: * - in: path * name: id @@ -25,45 +25,31 @@ import { * type: integer * required: true * description: Numeric ID of the eventTypeCustomInput to get - * security: - * - ApiKeyAuth: [] * tags: - * - event-type-custom-inputs + * - custom-inputs * responses: * 200: * description: OK * 401: * description: Authorization information is missing or invalid. * 404: - * deCustomInputscription: EventType was not found + * description: EventType was not found * patch: * summary: Edit an existing eventTypeCustomInput - * consumes: - * - application/json * parameters: - * - in: body - * name: eventTypeCustomInput - * description: The eventTypeCustomInput to edit - * schema: - * type: object - * $ref: '#/components/schemas/EventTypeCustomInput' - * required: true * - in: path * name: id * schema: * type: integer * required: true * description: Numeric ID of the eventTypeCustomInput to edit - * security: - * - ApiKeyAuth: [] * tags: - * - event-type-custom-inputs + * - custom-inputs * responses: * 201: * description: OK, eventTypeCustomInput edited successfuly - * model: EventTypeCustomInput * 400: - * desCustomInputcription: Bad request. EventType body is invalid. + * description: Bad request. EventType body is invalid. * 401: * description: Authorization information is missing or invalid. * delete: @@ -75,25 +61,23 @@ import { * type: integer * required: true * description: Numeric ID of the eventTypeCustomInput to delete - * security: - * - ApiKeyAuth: [] * tags: - * - event-type-custom-inputs + * - custom-inputs * responses: * 201: * description: OK, eventTypeCustomInput removed successfuly - * model: EventTypeCustomInput * 400: - * desCustomInputcription: Bad request. EventType id is invalid. + * description: Bad request. EventType id is invalid. * 401: * description: Authorization information is missing or invalid. */ -async function eventTypeById(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body } = req; +async function eventTypeById( + { method, query, body, userId }: NextApiRequest, + res: NextApiResponse +) { const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaEventTypeCustomInputBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = req.userId; const data = await prisma.eventType.findMany({ where: { userId } }); const userEventTypes = data.map((eventType) => eventType.id); const userEventTypeCustomInputs = await prisma.eventTypeCustomInput.findMany({ diff --git a/pages/api/event-type-custom-inputs/index.ts b/pages/api/custom-inputs/index.ts similarity index 72% rename from pages/api/event-type-custom-inputs/index.ts rename to pages/api/custom-inputs/index.ts index 01f5af921f..c7d5f9df90 100644 --- a/pages/api/event-type-custom-inputs/index.ts +++ b/pages/api/custom-inputs/index.ts @@ -9,47 +9,28 @@ import { schemaEventTypeCustomInputPublic, } from "@lib/validations/event-type-custom-input"; -/** - * @swagger - * /event-type-custom-inputs: - * get: - * summary: Find all eventTypeCustomInputs - * security: - * - ApiKeyAuth: [] - * tags: - * - event-type-custom-inputs - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No eventTypeCustomInputs were found - * post: - * summary: Creates a new eventTypeCustomInput - * security: - * - ApiKeyAuth: [] - * tags: - * - event-type-custom-inputs - * 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 createOrlistAllEventTypeCustomInputs( - req: NextApiRequest, + { userId, method, body }: NextApiRequest, res: NextApiResponse ) { - const { method } = req; - const userId = req.userId; const data = await prisma.eventType.findMany({ where: { userId } }); - const userEventTypes = data.map((eventType) => eventType.id); - + const userEventTypes: number[] = data.map((eventType) => eventType.id); if (method === "GET") { + /** + * @swagger + * /custom-inputs: + * get: + * summary: Find all eventTypeCustomInputs + * tags: + * - custom-inputs + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No eventTypeCustomInputs were found + */ const data = await prisma.eventTypeCustomInput.findMany({ where: { eventType: userEventTypes } }); const event_type_custom_inputs = data.map((eventTypeCustomInput) => schemaEventTypeCustomInputPublic.parse(eventTypeCustomInput) @@ -62,7 +43,22 @@ async function createOrlistAllEventTypeCustomInputs( error, }); } else if (method === "POST") { - const safe = schemaEventTypeCustomInputBodyParams.safeParse(req.body); + /** + * @swagger + * /custom-inputs: + * post: + * summary: Creates a new eventTypeCustomInput + * tags: + * - custom-inputs + * responses: + * 201: + * description: OK, eventTypeCustomInput created + * 400: + * description: Bad request. EventTypeCustomInput body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safe = schemaEventTypeCustomInputBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); // Since we're supporting a create or connect relation on eventType, we need to treat them differently // When using connect on event type, check if userId is the owner of the event diff --git a/pages/api/destination-calendars/[id].ts b/pages/api/destination-calendars/[id].ts index 60982a7058..f5d187eb25 100644 --- a/pages/api/destination-calendars/[id].ts +++ b/pages/api/destination-calendars/[id].ts @@ -13,90 +13,13 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -/** - * @swagger - * /destination-calendars/{id}: - * get: - * summary: Find a destination calendar by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the destination calendar to get - * security: - * - ApiKeyAuth: [] - * tags: - * - destination-calendars - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: DestinationCalendar was not found - * patch: - * summary: Edit an existing destination calendar - * consumes: - * - application/json - * parameters: - * - in: body - * name: destinationCalendar - * description: The destinationCalendar to edit - * schema: - * type: object - * $ref: '#/components/schemas/DestinationCalendar' - * required: true - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the destination calendar to edit - * security: - * - ApiKeyAuth: [] - * tags: - * - destination-calendars - * 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. - * delete: - * summary: Remove an existing destination calendar - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the destination calendar to delete - * security: - * - ApiKeyAuth: [] - * tags: - * - destination-calendars - * 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 destionationCalendarById( - req: NextApiRequest, + { method, query, body, userId }: NextApiRequest, res: NextApiResponse ) { - const { method, query, body } = req; const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaDestinationCalendarEditBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = req.userId; const data = await prisma.destinationCalendar.findMany({ where: { userId } }); const userDestinationCalendars = data.map((destinationCalendar) => destinationCalendar.id); // FIXME: Should we also check ownership of bokingId and eventTypeId to avoid users cross-pollinating other users calendars. @@ -104,6 +27,64 @@ export async function destionationCalendarById( if (userDestinationCalendars.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); else { switch (method) { + /** + * @swagger + * /destination-calendars/{id}: + * get: + * summary: Find a destination calendar + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the destination calendar to get + * tags: + * - destination-calendars + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: DestinationCalendar was not found + * patch: + * summary: Edit an existing destination calendar + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the destination calendar to edit + * tags: + * - destination-calendars + * responses: + * 201: + * description: OK, destinationCalendar edited successfuly + * 400: + * description: Bad request. DestinationCalendar body is invalid. + * 401: + * description: Authorization information is missing or invalid. + * delete: + * summary: Remove an existing destination calendar + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the destination calendar to delete + * tags: + * - destination-calendars + * responses: + * 201: + * description: OK, destinationCalendar removed successfuly + * 400: + * description: Bad request. DestinationCalendar id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ case "GET": await prisma.destinationCalendar .findUnique({ where: { id: safeQuery.data.id } }) @@ -116,7 +97,28 @@ export async function destionationCalendarById( }) ); break; - + /** + * @swagger + * /destination-calendars/{id}: + * patch: + * summary: Edit an existing destination calendar + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the destination calendar to edit + * tags: + * - destination-calendars + * responses: + * 201: + * description: OK, destinationCalendar edited successfuly + * 400: + * description: Bad request. DestinationCalendar body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ case "PATCH": if (!safeBody.success) { throw new Error("Invalid request body"); @@ -132,7 +134,28 @@ export async function destionationCalendarById( }) ); break; - + /** + * @swagger + * /destination-calendars/{id}: + * delete: + * summary: Remove an existing destination calendar + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the destination calendar to delete + * tags: + * - destination-calendars + * responses: + * 201: + * description: OK, destinationCalendar removed successfuly + * 400: + * description: Bad request. DestinationCalendar id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ case "DELETE": await prisma.destinationCalendar .delete({ diff --git a/pages/api/destination-calendars/index.ts b/pages/api/destination-calendars/index.ts index d7921491c9..4006a67c72 100644 --- a/pages/api/destination-calendars/index.ts +++ b/pages/api/destination-calendars/index.ts @@ -9,45 +9,26 @@ import { schemaDestinationCalendarReadPublic, } from "@lib/validations/destination-calendar"; -/** - * @swagger - * /destination-calendars: - * get: - * summary: Find all destination calendars - * security: - * - ApiKeyAuth: [] - * tags: - * - destination-calendars - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No destination calendars were found - * post: - * summary: Creates a new destination calendar - * security: - * - ApiKeyAuth: [] - * tags: - * - destination-calendars - * responses: - * 201: - * description: OK, destination calendar created - * model: DestinationCalendar - * 400: - * description: Bad request. DestinationCalendar body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ async function createOrlistAllDestinationCalendars( - req: NextApiRequest, + { method, body, userId }: NextApiRequest, res: NextApiResponse ) { - const { method } = req; - const userId = req.userId; - if (method === "GET") { + /** + * @swagger + * /destination-calendars: + * get: + * summary: Find all destination calendars + * tags: + * - destination-calendars + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No destination calendars were found + */ const data = await prisma.destinationCalendar.findMany({ where: { userId } }); const destination_calendars = data.map((destinationCalendar) => schemaDestinationCalendarReadPublic.parse(destinationCalendar) @@ -60,7 +41,22 @@ async function createOrlistAllDestinationCalendars( error, }); } else if (method === "POST") { - const safe = schemaDestinationCalendarCreateBodyParams.safeParse(req.body); + /** + * @swagger + * /destination-calendars: + * post: + * summary: Creates a new destination calendar + * tags: + * - destination-calendars + * responses: + * 201: + * description: OK, destination calendar created + * 400: + * description: Bad request. DestinationCalendar body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safe = schemaDestinationCalendarCreateBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.destinationCalendar.create({ data: { ...safe.data, userId } }); diff --git a/pages/api/docs.ts b/pages/api/docs.ts index 7dd7afa65d..dd544e89ae 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -1,6 +1,8 @@ -import jsonSchema from "@/json-schema/json-schema.json"; import pjson from "@/package.json"; +import modifyRes from "modify-response-middleware"; +import { use } from "next-api-middleware"; import { withSwagger } from "next-swagger-doc"; +import { NextApiRequest, NextApiResponse } from "next/types"; const swaggerHandler = withSwagger({ definition: { @@ -20,26 +22,18 @@ const swaggerHandler = withSwagger({ }, components: { securitySchemes: { ApiKeyAuth: { type: "apiKey", in: "query", name: "apiKey" } }, - security: { ApiKeyAuth: [] }, - schemas: { ...jsonSchema.definitions }, }, + security: [{ ApiKeyAuth: [] }], }, apiFolder: "pages/api", - tags: [ - "users", - "teams", - "memeberships", - "selected-calendars", - "schedules", - "payments", - "event-types", - "event-type-custom-inputs", - "destination-calendars", - "daily-event-references", - "booking-references", - "availabilities", - "attendees", - ], - sort: true, }); -export default swaggerHandler(); + +export default use( + modifyRes((content: string, _req: NextApiRequest, _res: NextApiResponse) => { + if (content) { + const parsed = JSON.parse(content); + delete parsed.channels; + return Buffer.from(JSON.stringify(parsed)); + } + }) +)(swaggerHandler()); diff --git a/pages/api/daily-event-references/[id].ts b/pages/api/event-references/[id].ts similarity index 58% rename from pages/api/daily-event-references/[id].ts rename to pages/api/event-references/[id].ts index 6ef4ac01e2..a98d5f74e9 100644 --- a/pages/api/daily-event-references/[id].ts +++ b/pages/api/event-references/[id].ts @@ -13,92 +13,15 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -/** - * @swagger - * /daily-event-references/{id}: - * get: - * summary: Find a daily event reference by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the daily event reference to get - * security: - * - ApiKeyAuth: [] - * tags: - * - daily-event-references - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: DailyEventReference was not found - * patch: - * summary: Edit an existing daily event reference - * consumes: - * - application/json - * parameters: - * - in: body - * name: dailyEventReference - * description: The dailyEventReference to edit - * schema: - * type: object - * $ref: '#/components/schemas/DailyEventReference' - * required: true - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the daily event reference to edit - * security: - * - ApiKeyAuth: [] - * tags: - * - daily-event-references - * 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. - * delete: - * summary: Remove an existing daily event reference - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the daily event reference to delete - * security: - * - ApiKeyAuth: [] - * tags: - * - daily-event-references - * 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 dailyEventReferenceById( - req: NextApiRequest, + { method, query, body, userId }: NextApiRequest, res: NextApiResponse ) { - const { method, query, body } = req; const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaDailyEventReferenceEditBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = req.userId; const userBookings = await prisma.booking.findMany({ where: { userId } }); - const userBookingIds = userBookings.map((booking) => booking.id); + const userBookingIds: number[] = userBookings.map((booking) => booking.id); const userBookingDailyEventReferences = await prisma.dailyEventReference.findMany({ where: { bookingId: { in: userBookingIds } }, }); @@ -109,6 +32,28 @@ export async function dailyEventReferenceById( res.status(401).json({ message: "Unauthorized" }); else { switch (method) { + /** + * @swagger + * /event-references/{id}: + * get: + * summary: Find a event reference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the event reference to get + * tags: + * - event-references + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: EventReference was not found + */ case "GET": await prisma.dailyEventReference .findUnique({ where: { id: safeQuery.data.id } }) @@ -122,6 +67,28 @@ export async function dailyEventReferenceById( ); break; + /** + * @swagger + * /event-references/{id}: + * patch: + * summary: Edit an existing event reference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the event reference to edit + * tags: + * - event-references + * responses: + * 201: + * description: OK, EventReference edited successfuly + * 400: + * description: Bad request. EventReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ case "PATCH": if (!safeBody.success) { throw new Error("Invalid request body"); @@ -138,6 +105,28 @@ export async function dailyEventReferenceById( ); break; + /** + * @swagger + * /event-references/{id}: + * delete: + * summary: Remove an existing event reference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the event reference to delete + * tags: + * - event-references + * responses: + * 201: + * description: OK, EventReference removed successfuly + * 400: + * description: Bad request. EventReference id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ case "DELETE": await prisma.dailyEventReference .delete({ diff --git a/pages/api/daily-event-references/index.ts b/pages/api/event-references/index.ts similarity index 67% rename from pages/api/daily-event-references/index.ts rename to pages/api/event-references/index.ts index dfafe246ce..bc19171de8 100644 --- a/pages/api/daily-event-references/index.ts +++ b/pages/api/event-references/index.ts @@ -9,47 +9,29 @@ import { schemaDailyEventReferenceReadPublic, } from "@lib/validations/daily-event-reference"; -/** - * @swagger - * /daily-event-references: - * get: - * summary: Find all daily event reference - * security: - * - ApiKeyAuth: [] - * tags: - * - daily-event-references - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No daily event references were found - * post: - * summary: Creates a new daily event reference - * security: - * - ApiKeyAuth: [] - * tags: - * - daily-event-references - * responses: - * 201: - * description: OK, daily event reference created - * model: DailyEventReference - * 400: - * description: Bad request. DailyEventReference body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ async function createOrlistAllDailyEventReferences( - req: NextApiRequest, + { method, body, userId }: NextApiRequest, res: NextApiResponse ) { - const { method } = req; - const userId = req.userId; const userBookings = await prisma.booking.findMany({ where: { userId } }); const userBookingIds = userBookings.map((booking) => booking.id); if (method === "GET") { + /** + * @swagger + * /event-references: + * get: + * summary: Find all daily event reference + * tags: + * - event-references + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No daily event references were found + */ const data = await prisma.dailyEventReference.findMany({ where: { bookingId: { in: userBookingIds } }, }); @@ -64,7 +46,22 @@ async function createOrlistAllDailyEventReferences( error, }); } else if (method === "POST") { - const safe = schemaDailyEventReferenceCreateBodyParams.safeParse(req.body); + /** + * @swagger + * /event-references: + * post: + * summary: Creates a new daily event reference + * tags: + * - event-references + * responses: + * 201: + * description: OK, daily event reference created + * 400: + * description: Bad request. DailyEventReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safe = schemaDailyEventReferenceCreateBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.dailyEventReference.create({ data: safe.data }); diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 37a5b38be7..0ece116d17 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -10,98 +10,43 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -/** - * @swagger - * /event-types/{id}: - * get: - * summary: Find a eventType by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the eventType to get - * security: - * - ApiKeyAuth: [] - * tags: - * - event-types - * externalDocs: - * url: https://docs.cal.com/event-types - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: EventType was not found - * patch: - * summary: Edit an existing eventType - * consumes: - * - application/json - * parameters: - * - in: body - * name: eventType - * description: The eventType to edit - * schema: - * type: object - * $ref: '#/components/schemas/EventType' - * required: true - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the eventType to edit - * security: - * - ApiKeyAuth: [] - * tags: - * - event-types - * externalDocs: - * url: https://docs.cal.com/event-types - * responses: - * 201: - * description: OK, eventType edited successfuly - * model: EventType - * 400: - * description: Bad request. EventType body is invalid. - * 401: - * description: Authorization information is missing or invalid. - * delete: - * summary: Remove an existing eventType - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the eventType to delete - * security: - * - ApiKeyAuth: [] - * tags: - * - event-types - * externalDocs: - * url: https://docs.cal.com/event-types - * responses: - * 201: - * description: OK, eventType removed successfuly - * model: EventType - * 400: - * description: Bad request. EventType id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function eventTypeById(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body } = req; +export async function eventTypeById( + { method, query, body, userId }: NextApiRequest, + res: NextApiResponse +) { const safeQuery = schemaQueryIdParseInt.safeParse(query); - const safeBody = schemaEventTypeBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = req.userId; const data = await prisma.eventType.findMany({ where: { userId } }); const userEventTypes = data.map((eventType) => eventType.id); if (!userEventTypes.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); else { switch (method) { + /** + * @swagger + * /event-types/{id}: + * get: + * summary: Find a eventType + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the eventType to get + * security: + * - ApiKeyAuth: [] + * tags: + * - event-types + * externalDocs: + * url: https://docs.cal.com/event-types + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: EventType was not found + */ case "GET": await prisma.eventType .findUnique({ where: { id: safeQuery.data.id } }) @@ -114,8 +59,34 @@ export async function eventTypeById(req: NextApiRequest, res: NextApiResponse ) { - const { method } = req; - const userId = req.userId; - if (method === "GET") { + /** + * @swagger + * /event-types: + * get: + * summary: Find all event types + * tags: + * - event-types + * externalDocs: + * url: https://docs.cal.com/event-types + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No event types were found + */ const data = await prisma.eventType.findMany({ where: { userId } }); const event_types = data.map((eventType) => schemaEventTypePublic.parse(eventType)); if (event_types) res.status(200).json({ event_types }); @@ -59,7 +38,24 @@ async function createOrlistAllEventTypes( error, }); } else if (method === "POST") { - const safe = schemaEventTypeBodyParams.safeParse(req.body); + /** + * @swagger + * /event-types: + * post: + * summary: Creates a new event type + * tags: + * - event-types + * externalDocs: + * url: https://docs.cal.com/event-types + * responses: + * 201: + * description: OK, event type created + * 400: + * description: Bad request. EventType body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safe = schemaEventTypeBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.eventType.create({ data: { ...safe.data, userId } }); diff --git a/pages/api/index.ts b/pages/api/index.ts index 3f72b7eaef..94461cedce 100644 --- a/pages/api/index.ts +++ b/pages/api/index.ts @@ -1,10 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; -/** - * @swagger - * security: - * - ApiKeyAuth: [] - */ export default async function CalcomApi(_: NextApiRequest, res: NextApiResponse) { res.status(201).json({ message: "Welcome to Cal.com API - docs are at https://docs.cal.com/api" }); } diff --git a/pages/api/memberships/[id].ts b/pages/api/memberships/[id].ts index 0e7498d16c..0681a629a9 100644 --- a/pages/api/memberships/[id].ts +++ b/pages/api/memberships/[id].ts @@ -7,110 +7,45 @@ import type { MembershipResponse } from "@lib/types"; import { schemaMembershipBodyParams, schemaMembershipPublic } from "@lib/validations/membership"; import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; -/** - * @swagger - * /memberships/{userId}_{teamId}: - * get: - * summary: Find a 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 - * security: - * - ApiKeyAuth: [] - * tags: - * - memberships - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Membership was not found - * patch: - * summary: Edit an existing membership - * consumes: - * - application/json - * parameters: - * - in: body - * name: membership - * description: The membership to edit - * schema: - * type: object - * $ref: '#/components/schemas/Membership' - * required: true - * - 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 - * security: - * - ApiKeyAuth: [] - * 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. - * delete: - * summary: Remove an existing membership - * 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 - * security: - * - ApiKeyAuth: [] - * 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 membershipById(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body } = req; +export async function membershipById( + { method, query, body, userId }: NextApiRequest, + res: NextApiResponse +) { const safeQuery = schemaQueryIdAsString.safeParse(query); - const safeBody = schemaMembershipBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); // This is how we set the userId and teamId in the query for managing compoundId. const [paramUserId, teamId] = safeQuery.data.id.split("_"); - const userId = req.userId; if (parseInt(paramUserId) !== userId) res.status(401).json({ message: "Unauthorized" }); else { switch (method) { + /** + * @swagger + * /memberships/{userId}_{teamId}: + * get: + * summary: Find a 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 + */ case "GET": await prisma.membership .findUnique({ @@ -131,7 +66,36 @@ export async function membershipById(req: NextApiRequest, res: NextApiResponse ) { - const { method } = req; - const userId = req.userId; if (method === "GET") { + /** + * @swagger + * /memberships: + * get: + * summary: Find all memberships + * tags: + * - memberships + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No memberships were found + */ const data = await prisma.membership.findMany({ where: { userId } }); const memberships = data.map((membership) => schemaMembershipPublic.parse(membership)); if (memberships) res.status(200).json({ memberships }); @@ -54,7 +36,22 @@ async function createOrlistAllMemberships( error, }); } else if (method === "POST") { - const safe = schemaMembershipBodyParams.safeParse(req.body); + /** + * @swagger + * /memberships: + * post: + * summary: Creates a new membership + * tags: + * - memberships + * responses: + * 201: + * description: OK, membership created + * 400: + * description: Bad request. Membership body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safe = schemaMembershipBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.membership.create({ data: { ...safe.data, userId } }); diff --git a/pages/api/payments/[id].ts b/pages/api/payments/[id].ts index 8ab4d5eab9..ebcaa0c504 100644 --- a/pages/api/payments/[id].ts +++ b/pages/api/payments/[id].ts @@ -14,7 +14,7 @@ import { * @swagger * /payments/{id}: * get: - * summary: Find one of your own payments by ID + * summary: Find a payment * parameters: * - in: path * name: id @@ -22,8 +22,6 @@ import { * type: integer * required: true * description: Numeric ID of the payment to get - * security: - * - ApiKeyAuth: [] * tags: * - payments * responses: @@ -34,11 +32,11 @@ import { * 404: * description: Payment was not found */ -export async function paymentById(req: NextApiRequest, res: NextApiResponse) { - const { method, query } = req; +export async function paymentById( + { method, query, userId }: NextApiRequest, + res: NextApiResponse +) { const safeQuery = schemaQueryIdParseInt.safeParse(query); - const userId = req.userId; - if (safeQuery.success && method === "GET") { const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, diff --git a/pages/api/payments/index.ts b/pages/api/payments/index.ts index db0cd349ca..d758421f46 100644 --- a/pages/api/payments/index.ts +++ b/pages/api/payments/index.ts @@ -11,8 +11,6 @@ import { schemaPaymentPublic } from "@lib/validations/payment"; * /payments: * get: * summary: Find all payments - * security: - * - ApiKeyAuth: [] * tags: * - payments * responses: @@ -23,9 +21,7 @@ import { schemaPaymentPublic } from "@lib/validations/payment"; * 404: * description: No payments were found */ -async function allPayments(req: NextApiRequest, res: NextApiResponse) { - const userId = req.userId; - +async function allPayments({ userId }: NextApiRequest, res: NextApiResponse) { const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, include: { bookings: true }, diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index 8a08128f4f..38066c4ab8 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -10,92 +10,40 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -/** - * @swagger - * /schedules/{id}: - * get: - * summary: Find a schedule by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the schedule to get - * security: - * - ApiKeyAuth: [] - * tags: - * - schedules - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Schedule was not found - * patch: - * summary: Edit an existing schedule - * consumes: - * - application/json - * parameters: - * - in: body - * name: schedule - * description: The schedule to edit - * schema: - * type: object - * $ref: '#/components/schemas/Schedule' - * required: true - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the schedule to edit - * security: - * - ApiKeyAuth: [] - * 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. - * delete: - * summary: Remove an existing schedule - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the schedule to delete - * security: - * - ApiKeyAuth: [] - * 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 scheduleById(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body } = req; +export async function scheduleById( + { method, query, body, userId }: NextApiRequest, + res: NextApiResponse +) { const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaScheduleBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = req.userId; const userSchedules = await prisma.schedule.findMany({ where: { userId } }); const userScheduleIds = userSchedules.map((schedule) => schedule.id); if (!userScheduleIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); else { switch (method) { + /** + * @swagger + * /schedules/{id}: + * get: + * summary: Find a schedule + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the schedule to get + * tags: + * - schedules + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Schedule was not found + */ case "GET": await prisma.schedule .findUnique({ where: { id: safeQuery.data.id } }) @@ -109,6 +57,28 @@ export async function scheduleById(req: NextApiRequest, res: NextApiResponse ) { - const { method } = req; - const userId = req.userId; - if (method === "GET") { + /** + * @swagger + * /schedules: + * get: + * summary: Find all schedules + * tags: + * - schedules + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No schedules were found + */ const data = await prisma.schedule.findMany({ where: { userId } }); const schedules = data.map((schedule) => schemaSchedulePublic.parse(schedule)); if (schedules) res.status(200).json({ schedules }); @@ -55,7 +36,22 @@ async function createOrlistAllSchedules( error, }); } else if (method === "POST") { - const safe = schemaScheduleBodyParams.safeParse(req.body); + /** + * @swagger + * /schedules: + * post: + * summary: Creates a new schedule + * tags: + * - schedules + * responses: + * 201: + * description: OK, schedule created + * 400: + * description: Bad request. Schedule body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safe = schemaScheduleBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.schedule.create({ data: { ...safe.data, userId } }); const schedule = schemaSchedulePublic.parse(data); diff --git a/pages/api/selected-calendars/[id].ts b/pages/api/selected-calendars/[id].ts index 6efbca86ee..de4d7a5570 100644 --- a/pages/api/selected-calendars/[id].ts +++ b/pages/api/selected-calendars/[id].ts @@ -10,131 +10,52 @@ import { } from "@lib/validations/selected-calendar"; import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; -/** - * @swagger - * /selected-calendars/{userId}_{integration}_{externalId}: - * get: - * summary: Find a selected-calendar by userID and teamID - * parameters: - * - in: path - * name: userId - * schema: - * type: integer - * required: true - * description: userId of the selected calendar to get - * - in: path - * name: externalId - * schema: - * type: string - * required: true - * description: externalId of the selected calendar to get - * - in: path - * name: integration - * schema: - * type: string - * required: true - * description: integration of the selected calendar to get - * security: - * - ApiKeyAuth: [] - * tags: - * - selected-calendars - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: SelectedCalendar was not found - * patch: - * summary: Edit an existing selected calendar - * consumes: - * - application/json - * parameters: - * - in: body - * name: selected-calendar - * description: The selected-calendar to edit - * schema: - * type: object - * $ref: '#/components/schemas/SelectedCalendar' - * required: true - * - in: path - * name: userId - * schema: - * type: integer - * required: true - * description: userId of the selected calendar to get - * - in: path - * name: externalId - * schema: - * type: string - * required: true - * description: externalId of the selected calendar to get - * - in: path - * name: integration - * schema: - * type: string - * required: true - * description: integration of the selected calendar to get - * security: - * - ApiKeyAuth: [] - * tags: - * - selected-calendars - * responses: - * 201: - * description: OK, selected-calendar edited successfuly - * model: SelectedCalendar - * 400: - * description: Bad request. SelectedCalendar body is invalid. - * 401: - * description: Authorization information is missing or invalid. - * delete: - * summary: Remove an existing selected-calendar - * parameters: - * - in: path - * name: userId - * schema: - * type: integer - * required: true - * description: userId of the selected calendar to get - * - in: path - * name: externalId - * schema: - * type: integer - * required: true - * description: externalId of the selected-calendar to get - * - in: path - * name: integration - * schema: - * type: string - * required: true - * description: integration of the selected calendar to get - * security: - * - ApiKeyAuth: [] - * tags: - * - selected-calendars - * responses: - * 201: - * description: OK, selected-calendar removed successfuly - * model: SelectedCalendar - * 400: - * description: Bad request. SelectedCalendar id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ export async function selectedCalendarById( - req: NextApiRequest, + { method, query, body, userId }: NextApiRequest, res: NextApiResponse ) { - const { method, query, body } = req; const safeQuery = schemaQueryIdAsString.safeParse(query); const safeBody = schemaSelectedCalendarBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); // This is how we set the userId and externalId in the query for managing compoundId. const [paramUserId, integration, externalId] = safeQuery.data.id.split("_"); - const userId = req.userId; if (userId !== parseInt(paramUserId)) res.status(401).json({ message: "Unauthorized" }); else { switch (method) { + /** + * @swagger + * /selected-calendars/{userId}_{integration}_{externalId}: + * get: + * summary: Find a selected calendar + * parameters: + * - in: path + * name: userId + * schema: + * type: integer + * required: true + * description: userId of the selected calendar to get + * - in: path + * name: externalId + * schema: + * type: string + * required: true + * description: externalId of the selected calendar to get + * - in: path + * name: integration + * schema: + * type: string + * required: true + * description: integration of the selected calendar to get + * tags: + * - selected-calendars + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: SelectedCalendar was not found + */ case "GET": await prisma.selectedCalendar .findUnique({ @@ -156,6 +77,40 @@ export async function selectedCalendarById( ); break; + /** + * @swagger + * /selected-calendars/{userId}_{integration}_{externalId}: + * patch: + * summary: Edit a selected calendar + * parameters: + * - in: path + * name: userId + * schema: + * type: integer + * required: true + * description: userId of the selected calendar to get + * - in: path + * name: externalId + * schema: + * type: string + * required: true + * description: externalId of the selected calendar to get + * - in: path + * name: integration + * schema: + * type: string + * required: true + * description: integration of the selected calendar to get + * tags: + * - selected-calendars + * responses: + * 201: + * description: OK, selected-calendar edited successfuly + * 400: + * description: Bad request. SelectedCalendar body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ case "PATCH": if (!safeBody.success) { throw new Error("Invalid request body"); @@ -180,7 +135,40 @@ export async function selectedCalendarById( }) ); break; - + /** + * @swagger + * /selected-calendars/{userId}_{integration}_{externalId}: + * delete: + * summary: Remove a selected calendar + * parameters: + * - in: path + * name: userId + * schema: + * type: integer + * required: true + * description: userId of the selected calendar to get + * - in: path + * name: externalId + * schema: + * type: integer + * required: true + * description: externalId of the selected-calendar to get + * - in: path + * name: integration + * schema: + * type: string + * required: true + * description: integration of the selected calendar to get + * tags: + * - selected-calendars + * responses: + * 201: + * description: OK, selected-calendar removed successfuly + * 400: + * description: Bad request. SelectedCalendar id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ case "DELETE": await prisma.selectedCalendar .delete({ diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index 83537208ba..cbf2e94b81 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -9,45 +9,26 @@ import { schemaSelectedCalendarPublic, } from "@lib/validations/selected-calendar"; -/** - * @swagger - * /selected-calendars: - * get: - * summary: Find all selected calendars - * security: - * - ApiKeyAuth: [] - * tags: - * - selected-calendars - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No selected calendars were found - * post: - * summary: Creates a new selected calendar - * security: - * - ApiKeyAuth: [] - * tags: - * - selected-calendars - * responses: - * 201: - * description: OK, selected calendar created - * model: SelectedCalendar - * 400: - * description: Bad request. SelectedCalendar body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ async function createOrlistAllSelectedCalendars( - req: NextApiRequest, + { method, body, userId }: NextApiRequest, res: NextApiResponse ) { - const { method } = req; - const userId = req.userId; - if (method === "GET") { + /** + * @swagger + * /selected-calendars: + * get: + * summary: Find all selected calendars + * tags: + * - selected-calendars + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No selected calendars were found + */ const data = await prisma.selectedCalendar.findMany({ where: { userId } }); const selected_calendars = data.map((selected_calendar) => schemaSelectedCalendarPublic.parse(selected_calendar) @@ -60,7 +41,33 @@ async function createOrlistAllSelectedCalendars( error, }); } else if (method === "POST") { - const safe = schemaSelectedCalendarBodyParams.safeParse(req.body); + /** + * @swagger + * /selected-calendars: + * get: + * summary: Find all selected calendars + * tags: + * - selected-calendars + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No selected calendars were found + * post: + * summary: Creates a new selected calendar + * tags: + * - selected-calendars + * responses: + * 201: + * description: OK, selected calendar created + * 400: + * description: Bad request. SelectedCalendar body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safe = schemaSelectedCalendarBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); // Create new selectedCalendar connecting it to current userId const data = await prisma.selectedCalendar.create({ diff --git a/pages/api/teams/[id].ts b/pages/api/teams/[id].ts index 0fead8e066..e49277a143 100644 --- a/pages/api/teams/[id].ts +++ b/pages/api/teams/[id].ts @@ -14,7 +14,7 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * @swagger * /teams/{id}: * get: - * summary: Find a team by ID + * summary: Find a team * parameters: * - in: path * name: id @@ -22,8 +22,6 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * type: integer * required: true * description: Numeric ID of the team to get - * security: - * - ApiKeyAuth: [] * tags: * - teams * responses: @@ -35,30 +33,18 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * description: Team was not found * patch: * summary: Edit an existing team - * consumes: - * - application/json * parameters: - * - in: body - * name: team - * description: The team to edit - * schema: - * type: object - * $ref: '#/components/schemas/Team' - * required: true * - in: path * name: id * schema: * type: integer * required: true * description: Numeric ID of the team to edit - * security: - * - ApiKeyAuth: [] * tags: * - teams * responses: * 201: * description: OK, team edited successfuly - * model: Team * 400: * description: Bad request. Team body is invalid. * 401: @@ -72,25 +58,23 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * type: integer * required: true * description: Numeric ID of the team to delete - * security: - * - ApiKeyAuth: [] * tags: * - teams * responses: * 201: * description: OK, team removed successfuly - * model: Team * 400: * description: Bad request. Team id is invalid. * 401: * description: Authorization information is missing or invalid. */ -export async function teamById(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body } = req; +export async function teamById( + { method, query, body, userId }: NextApiRequest, + res: NextApiResponse +) { const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaTeamBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = req.userId; const userWithMemberships = await prisma.membership.findMany({ where: { userId: userId }, }); diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index ce335fff9d..75aabd47b9 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -7,41 +7,26 @@ import { TeamResponse, TeamsResponse } from "@lib/types"; import { schemaMembershipPublic } from "@lib/validations/membership"; import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; -/** - * @swagger - * /teams: - * get: - * summary: Find all teams - * security: - * - ApiKeyAuth: [] - * tags: - * - teams - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No teams were found - * post: - * summary: Creates a new team - * security: - * - ApiKeyAuth: [] - * tags: - * - teams - * responses: - * 201: - * description: OK, team created - * model: Team - * 400: - * description: Bad request. Team body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createOrlistAllTeams(req: NextApiRequest, res: NextApiResponse) { - const { method } = req; - const userId = req.userId; +async function createOrlistAllTeams( + { method, body, userId }: NextApiRequest, + res: NextApiResponse +) { if (method === "GET") { + /** + * @swagger + * /teams: + * get: + * summary: Find all teams + * tags: + * - teams + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No teams were found + */ const userWithMemberships = await prisma.membership.findMany({ where: { userId: userId }, }); @@ -55,7 +40,22 @@ async function createOrlistAllTeams(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body, userId } = req; +export async function userById({ method, query, body, userId }: NextApiRequest, res: NextApiResponse) { const safeQuery = schemaQueryIdParseInt.safeParse(query); console.log(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index fa28b36f5e..046d456de9 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -10,11 +10,10 @@ import { schemaUserReadPublic } from "@lib/validations/user"; * @swagger * /users: * get: - * summary: Find all users (admin only), returns your user if regular user. - * security: - * - ApiKeyAuth: [] + * summary: Find all users. * tags: * - users + * operationId: listUsers * responses: * 200: * description: OK @@ -23,8 +22,7 @@ import { schemaUserReadPublic } from "@lib/validations/user"; * 404: * description: No users were found */ -async function allUsers(req: NextApiRequest, res: NextApiResponse) { - const userId = req.userId; +async function allUsers({ userId }: NextApiRequest, res: NextApiResponse) { const data = await prisma.user.findMany({ where: { id: userId, diff --git a/templates/endpoints/[id]/delete.ts b/templates/endpoints/[id]/delete.ts index 9c5c6f9f7c..133554ac25 100644 --- a/templates/endpoints/[id]/delete.ts +++ b/templates/endpoints/[id]/delete.ts @@ -21,22 +21,20 @@ import { * type: integer * required: true * description: Numeric ID of the resource to delete - * security: - * - ApiKeyAuth: [] + * tags: * - resources * responses: * 201: * description: OK, resource removed successfuly - * model: Resource * 400: * description: Bad request. Resource id is invalid. * 401: * description: Authorization information is missing or invalid. */ -export async function deleteResource(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query", safe.error); +export async function deleteResource({query}: NextApiRequest, res: NextApiResponse) { + const safe = schemaQueryIdParseInt.safeParse(query); + if (!safe.success) throw new Error("Invalid request query"); const data = await prisma.resource.delete({ where: { id: safe.data.id } }); diff --git a/templates/endpoints/[id]/edit.ts b/templates/endpoints/[id]/edit.ts index 8ddad4601d..e72198d82e 100644 --- a/templates/endpoints/[id]/edit.ts +++ b/templates/endpoints/[id]/edit.ts @@ -22,22 +22,20 @@ import { * type: integer * required: true * description: Numeric ID of the resource to edit - * security: - * - ApiKeyAuth: [] + * tags: * - resources * responses: * 201: * description: OK, resource edited successfuly - * model: Resource * 400: * description: Bad request. Resource body is invalid. * 401: * description: Authorization information is missing or invalid. */ -export async function editResource(req: NextApiRequest, res: NextApiResponse) { - const safeQuery = schemaQueryIdParseInt.safeParse(req.query); - const safeBody = schemaResourceBodyParams.safeParse(req.body); +export async function editResource({query, body}: NextApiRequest, res: NextApiResponse) { + const safeQuery = schemaQueryIdParseInt.safeParse(query); + const safeBody = schemaResourceBodyParams.safeParse(body); if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); const resource = await prisma.resource.update({ diff --git a/templates/endpoints/[id]/index.ts b/templates/endpoints/[id]/index.ts index 9f4c64f11d..4a0656d3b5 100644 --- a/templates/endpoints/[id]/index.ts +++ b/templates/endpoints/[id]/index.ts @@ -14,7 +14,7 @@ import { * @swagger * /v1/resources/{id}: * get: - * summary: Find a resource by ID + * summary: Find a resource * parameters: * - in: path * name: id @@ -22,8 +22,7 @@ import { * type: integer * required: true * description: Numeric ID of the resource to get - * security: - * - ApiKeyAuth: [] + * tags: * - resources * responses: @@ -34,8 +33,8 @@ import { * 404: * description: Resource was not found */ -export async function resourceById(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaQueryIdParseInt.safeParse(req.query); +export async function resourceById({query}: NextApiRequest, res: NextApiResponse) { + const safe = schemaQueryIdParseInt.safeParse(query); if (!safe.success) throw new Error("Invalid request query"); const resource = await prisma.resource.findUnique({ where: { id: safe.data.id } }); diff --git a/templates/endpoints/get_all.ts b/templates/endpoints/get_all.ts index ee66e7c773..e925133346 100644 --- a/templates/endpoints/get_all.ts +++ b/templates/endpoints/get_all.ts @@ -11,8 +11,7 @@ import { schemaResourcePublic } from "@lib/validations/resource"; * /v1/resources: * get: * summary: Find all resources - * security: - * - ApiKeyAuth: [] + * tags: * - resources * responses: diff --git a/templates/endpoints/get_all_and_post.ts b/templates/endpoints/get_all_and_post.ts index 2ce4b8dfe9..e21dc8bb9d 100644 --- a/templates/endpoints/get_all_and_post.ts +++ b/templates/endpoints/get_all_and_post.ts @@ -6,13 +6,18 @@ import { withMiddleware } from "@lib/helpers/withMiddleware"; import { PaymentResponse, PaymentsResponse } from "@lib/types"; import { schemaPaymentBodyParams, schemaPaymentPublic } from "@lib/validations/payment"; +async function createOrlistAllPayments( + {method, body}: NextApiRequest, + res: NextApiResponse +) { + if (method === "GET") { + /** * @swagger * /v1/payments: * get: * summary: Find all payments - * security: - * - ApiKeyAuth: [] + * tags: * - payments * responses: @@ -22,27 +27,7 @@ import { schemaPaymentBodyParams, schemaPaymentPublic } from "@lib/validations/p * description: Authorization information is missing or invalid. * 404: * description: No payments were found - * post: - * summary: Creates a new payment - * security: - * - ApiKeyAuth: [] - * tags: - * - payments - * responses: - * 201: - * description: OK, payment created - * model: Payment - * 400: - * description: Bad request. Payment body is invalid. - * 401: - * description: Authorization information is missing or invalid. */ -async function createOrlistAllPayments( - req: NextApiRequest, - res: NextApiResponse -) { - const { method } = req; - if (method === "GET") { const payments = await prisma.payment.findMany(); const data = payments.map((payment) => schemaPaymentPublic.parse(payment)); if (data) res.status(200).json({ data }); @@ -53,7 +38,24 @@ async function createOrlistAllPayments( error, }); } else if (method === "POST") { - const safe = schemaPaymentBodyParams.safeParse(req.body); + +/** + * @swagger + * /v1/payments: + * post: + * summary: Creates a new payment + + * tags: + * - payments + * responses: + * 201: + * description: OK, payment created + * 400: + * description: Bad request. Payment body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safe = schemaPaymentBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); const payment = await prisma.payment.create({ data: safe.data }); diff --git a/templates/endpoints/post.ts b/templates/endpoints/post.ts index 999bce39c1..896c09e691 100644 --- a/templates/endpoints/post.ts +++ b/templates/endpoints/post.ts @@ -18,22 +18,20 @@ import { schemaResourceBodyParams, schemaResourcePublic, withValidResource } fro * application/json: * schema: * $ref: '#/components/schemas/Resource' - * security: - * - ApiKeyAuth: [] + * tags: * - resources * responses: * 201: * description: OK, resource created - * model: Resource * 400: * description: Bad request. Resource body is invalid. * 401: * description: Authorization information is missing or invalid. */ -async function createResource(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaResourceBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body", safe.error); +async function createResource({body}: NextApiRequest, res: NextApiResponse) { + const safe = schemaResourceBodyParams.safeParse(body); + if (!safe.success) throw new Error("Invalid request body"); const resource = await prisma.resource.create({ data: safe.data }); const data = schemaResourcePublic.parse(resource); diff --git a/types.d.ts b/types.d.ts new file mode 100644 index 0000000000..2abf07e4c1 --- /dev/null +++ b/types.d.ts @@ -0,0 +1,2 @@ +declare module "modify-response-middleware"; +