From b572e4b0ffb5a6c8d4f0c0a9a463c5a3e53aa43d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 30 Apr 2022 20:53:19 +0200 Subject: [PATCH] fix: move all req to deconstructed --- README.md | 2 - lib/helpers/verifyApiKey.ts | 18 ++--- pages/api/availabilities/index.ts | 4 +- pages/api/booking-references/[id].ts | 93 +++++++++++++------------ pages/api/booking-references/index.ts | 1 + pages/api/bookings/index.ts | 4 +- pages/api/payments/index.ts | 4 +- pages/api/schedules/[id].ts | 7 +- pages/api/schedules/index.ts | 7 +- pages/api/selected-calendars/[id].ts | 4 +- pages/api/selected-calendars/index.ts | 4 +- pages/api/teams/[id].ts | 7 +- pages/api/teams/index.ts | 65 +++++++++-------- pages/api/users/[id].ts | 3 +- pages/api/users/index.ts | 3 +- templates/endpoints/[id]/delete.ts | 6 +- templates/endpoints/[id]/edit.ts | 6 +- templates/endpoints/[id]/index.ts | 4 +- templates/endpoints/get_all_and_post.ts | 39 ++++++----- templates/endpoints/post.ts | 6 +- types.d.ts | 1 + 21 files changed, 148 insertions(+), 140 deletions(-) diff --git a/README.md b/README.md index a9904ac3ff..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/) 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/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index 25b0866071..c7b53c211d 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -10,7 +10,7 @@ import { } from "@lib/validations/availability"; async function createOrlistAllAvailabilities( - { method, userId }: NextApiRequest, + { method, body, userId }: NextApiRequest, res: NextApiResponse ) { if (method === "GET") { @@ -58,7 +58,7 @@ async function createOrlistAllAvailabilities( * 401: * description: Authorization information is missing or invalid. */ - const safe = schemaAvailabilityCreateBodyParams.safeParse(req.body); + const safe = schemaAvailabilityCreateBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.availability.create({ data: { ...safe.data, userId } }); diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index cb0358d901..03bc87fafb 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -27,32 +27,33 @@ export async function bookingReferenceById( if (!userWithBookings) throw new Error("User not found"); 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) { - /** - * @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 - */ 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)) @@ -63,30 +64,32 @@ export async function bookingReferenceById( error, }) ); + break; - /** - * @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. - */ case "PATCH": + /** + * @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"); diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index 87cbe25cdc..c228673240 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -75,6 +75,7 @@ async function createOrlistAllBookingReferences( throw new Error("User not found"); } 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/index.ts b/pages/api/bookings/index.ts index 57a774a916..bd1595ff6c 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -7,7 +7,7 @@ import { BookingResponse, BookingsResponse } from "@lib/types"; import { schemaBookingCreateBodyParams, schemaBookingReadPublic } from "@lib/validations/booking"; async function createOrlistAllBookings( - { method, userId }: NextApiRequest, + { method, body, userId }: NextApiRequest, res: NextApiResponse ) { if (method === "GET") { @@ -51,7 +51,7 @@ async function createOrlistAllBookings( * 401: * description: Authorization information is missing or invalid. */ - const safe = schemaBookingCreateBodyParams.safeParse(req.body); + 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/payments/index.ts b/pages/api/payments/index.ts index 0c6eae0f85..d758421f46 100644 --- a/pages/api/payments/index.ts +++ b/pages/api/payments/index.ts @@ -21,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 af63d8af2b..38066c4ab8 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -10,12 +10,13 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -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" }); diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index 5da47e226c..04dbc6b1a1 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -7,12 +7,9 @@ import { ScheduleResponse, SchedulesResponse } from "@lib/types"; import { schemaScheduleBodyParams, schemaSchedulePublic } from "@lib/validations/schedule"; async function createOrlistAllSchedules( - req: NextApiRequest, + { method, body, userId }: NextApiRequest, res: NextApiResponse ) { - const { method } = req; - const userId = req.userId; - if (method === "GET") { /** * @swagger @@ -54,7 +51,7 @@ async function createOrlistAllSchedules( * 401: * description: Authorization information is missing or invalid. */ - const safe = schemaScheduleBodyParams.safeParse(req.body); + 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 10fb737cf9..de4d7a5570 100644 --- a/pages/api/selected-calendars/[id].ts +++ b/pages/api/selected-calendars/[id].ts @@ -11,16 +11,14 @@ import { import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; 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) { diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index 758d663b8f..cbf2e94b81 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -10,7 +10,7 @@ import { } from "@lib/validations/selected-calendar"; async function createOrlistAllSelectedCalendars( - { method, userId }: NextApiRequest, + { method, body, userId }: NextApiRequest, res: NextApiResponse ) { if (method === "GET") { @@ -67,7 +67,7 @@ async function createOrlistAllSelectedCalendars( * 401: * description: Authorization information is missing or invalid. */ - const safe = schemaSelectedCalendarBodyParams.safeParse(req.body); + 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 d3e971d487..e49277a143 100644 --- a/pages/api/teams/[id].ts +++ b/pages/api/teams/[id].ts @@ -68,12 +68,13 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * 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 e5ae852dd8..75aabd47b9 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -7,36 +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 - * 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 - * tags: - * - teams - * responses: - * 201: - * description: OK, team created - * 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 }, }); @@ -50,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 5f6c64d604..046d456de9 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -22,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 908e74b7d5..133554ac25 100644 --- a/templates/endpoints/[id]/delete.ts +++ b/templates/endpoints/[id]/delete.ts @@ -32,9 +32,9 @@ import { * 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 43cb6c8f8e..e72198d82e 100644 --- a/templates/endpoints/[id]/edit.ts +++ b/templates/endpoints/[id]/edit.ts @@ -33,9 +33,9 @@ import { * 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 c9b1d85152..4a0656d3b5 100644 --- a/templates/endpoints/[id]/index.ts +++ b/templates/endpoints/[id]/index.ts @@ -33,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_and_post.ts b/templates/endpoints/get_all_and_post.ts index d20075e52c..e21dc8bb9d 100644 --- a/templates/endpoints/get_all_and_post.ts +++ b/templates/endpoints/get_all_and_post.ts @@ -6,6 +6,12 @@ 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: @@ -21,6 +27,21 @@ import { schemaPaymentBodyParams, schemaPaymentPublic } from "@lib/validations/p * description: Authorization information is missing or invalid. * 404: * description: No payments were found + */ + const payments = await prisma.payment.findMany(); + const data = payments.map((payment) => schemaPaymentPublic.parse(payment)); + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "No Payments were found", + error, + }); + } else if (method === "POST") { + +/** + * @swagger + * /v1/payments: * post: * summary: Creates a new payment @@ -34,23 +55,7 @@ import { schemaPaymentBodyParams, schemaPaymentPublic } from "@lib/validations/p * 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 }); - else - (error: Error) => - res.status(404).json({ - message: "No Payments were found", - error, - }); - } else if (method === "POST") { - const safe = schemaPaymentBodyParams.safeParse(req.body); + 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 3f5b7403d7..896c09e691 100644 --- a/templates/endpoints/post.ts +++ b/templates/endpoints/post.ts @@ -29,9 +29,9 @@ import { schemaResourceBodyParams, schemaResourcePublic, withValidResource } fro * 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 index 9a7af651d1..2abf07e4c1 100644 --- a/types.d.ts +++ b/types.d.ts @@ -1 +1,2 @@ declare module "modify-response-middleware"; +