initail work on paid booking, improve validations
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
// Make a middleware that adds a cost to running the request
|
||||
// by calling stripeSubscription addCost() * pricePerBooking
|
||||
// Initially to test out 0,5 cent per booking via API call
|
||||
// withCost(5)(endpoint)
|
||||
// Should add a charge of 0.5 cent per booking to the subscription of the user making the request
|
||||
// Should be called in the middleware of the e
|
||||
//
|
||||
import { NextMiddleware } from "next-api-middleware";
|
||||
|
||||
export const withCost = (priceInCents: number): NextMiddleware => {
|
||||
return async function (req, res, next) {
|
||||
console.log(req.headers);
|
||||
if (
|
||||
priceInCents > 0
|
||||
// && stripeCustomerId && stripeSubscriptionId
|
||||
) {
|
||||
console.log(priceInCents);
|
||||
// if (req.method === allowedHttpMethod || req.method == "OPTIONS") {
|
||||
await next();
|
||||
} else {
|
||||
res.status(405).json({ message: `We weren't able to process the payment for this transaction` });
|
||||
res.end();
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -2,7 +2,7 @@ import { label } from "next-api-middleware";
|
||||
|
||||
import { addRequestId } from "./addRequestid";
|
||||
import { captureErrors } from "./captureErrors";
|
||||
import { HTTP_POST, HTTP_DELETE, HTTP_PATCH, HTTP_GET, httpMethod } from "./httpMethods";
|
||||
import { HTTP_POST, HTTP_DELETE, HTTP_PATCH, HTTP_GET } from "./httpMethods";
|
||||
import { verifyApiKey } from "./verifyApiKey";
|
||||
|
||||
const withMiddleware = label(
|
||||
@@ -14,9 +14,8 @@ const withMiddleware = label(
|
||||
addRequestId,
|
||||
verifyApiKey,
|
||||
sentry: captureErrors,
|
||||
httpMethod: httpMethod("GET" || "DELETE" || "PATCH" || "POST"),
|
||||
},
|
||||
["sentry", "verifyApiKey", "httpMethod", "addRequestId"] // <-- Provide a list of middleware to call automatically
|
||||
["sentry", "verifyApiKey", "addRequestId"] // <-- Provide a list of middleware to call automatically
|
||||
);
|
||||
|
||||
export { withMiddleware };
|
||||
|
||||
@@ -2,7 +2,7 @@ import { withValidation } from "next-validations";
|
||||
|
||||
import { _ApiKeyModel as ApiKey } from "@calcom/prisma/zod";
|
||||
|
||||
export const schemaApiKeyBodyParams = ApiKey.omit({ id: true, userId: true, createdAt: true });
|
||||
export const schemaApiKeyBodyParams = ApiKey.omit({ id: true, userId: true, createdAt: true }).partial();
|
||||
|
||||
export const schemaApiKeyPublic = ApiKey.omit({
|
||||
id: true,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { withValidation } from "next-validations";
|
||||
|
||||
import { _AttendeeModel as Attendee } from "@calcom/prisma/zod";
|
||||
|
||||
export const schemaAttendeeBodyParams = Attendee.omit({ id: true });
|
||||
export const schemaAttendeeBodyParams = Attendee.omit({ id: true }).partial();
|
||||
|
||||
export const schemaAttendeePublic = Attendee.omit({});
|
||||
|
||||
|
||||
@@ -1,8 +1,20 @@
|
||||
import { withValidation } from "next-validations";
|
||||
import { z } from "zod";
|
||||
|
||||
import { _BookingModel as Booking } from "@calcom/prisma/zod";
|
||||
|
||||
export const schemaBookingBodyParams = Booking.omit({ id: true });
|
||||
// Here we remove any parameters that are not needed for the API with omit.
|
||||
const schemaBookingBaseBodyParams = Booking.omit({ id: true }).partial();
|
||||
// Here we redeclare the required ones after removing the ones we don't need.
|
||||
// and making the rest optional with .partial()
|
||||
const schemaBookingRequiredParams = z.object({
|
||||
uid: z.string(),
|
||||
title: z.string(),
|
||||
startTime: z.date(),
|
||||
endTime: z.date(),
|
||||
});
|
||||
|
||||
export const schemaBookingBodyParams = schemaBookingBaseBodyParams.merge(schemaBookingRequiredParams);
|
||||
|
||||
export const schemaBookingPublic = Booking.omit({});
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { withValidation } from "next-validations";
|
||||
|
||||
import { _ScheduleModel as Schedule } from "@calcom/prisma/zod";
|
||||
|
||||
export const schemaScheduleBodyParams = Schedule.omit({ id: true });
|
||||
export const schemaScheduleBodyParams = Schedule.omit({ id: true }).partial();
|
||||
|
||||
export const schemaSchedulePublic = Schedule.omit({});
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { withValidation } from "next-validations";
|
||||
|
||||
import { _SelectedCalendarModel as SelectedCalendar } from "@calcom/prisma/zod";
|
||||
|
||||
export const schemaSelectedCalendarBodyParams = SelectedCalendar.omit({});
|
||||
export const schemaSelectedCalendarBodyParams = SelectedCalendar.omit({}).partial();
|
||||
|
||||
export const schemaSelectedCalendarPublic = SelectedCalendar.omit({ userId: true });
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { withValidation } from "next-validations";
|
||||
|
||||
import { _TeamModel as Team } from "@calcom/prisma/zod";
|
||||
|
||||
export const schemaTeamBodyParams = Team.omit({ id: true });
|
||||
export const schemaTeamBodyParams = Team.omit({ id: true }).partial();
|
||||
|
||||
export const schemaTeamPublic = Team.omit({});
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ export const schemaUserBodyParams = User.omit({
|
||||
password: true,
|
||||
twoFactorEnabled: true,
|
||||
twoFactorSecret: true,
|
||||
});
|
||||
}).partial();
|
||||
|
||||
export const schemaUserPublic = User.omit({
|
||||
identityProvider: true,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { withValidation } from "next-validations";
|
||||
|
||||
import { _WebhookModel as Webhook } from "@calcom/prisma/zod";
|
||||
|
||||
export const schemaWebhookBodyParams = Webhook.omit({ id: true });
|
||||
export const schemaWebhookBodyParams = Webhook.omit({ id: true }).partial();
|
||||
|
||||
export const schemaWebhookPublic = Webhook.omit({});
|
||||
|
||||
|
||||
+1
-2
@@ -38,7 +38,6 @@
|
||||
"next-swagger-doc": "^0.2.1",
|
||||
"next-transpile-modules": "^9.0.0",
|
||||
"next-validations": "^0.1.11",
|
||||
"typescript": "^4.6.3",
|
||||
"zod": "^3.14.2"
|
||||
"typescript": "^4.6.3"
|
||||
}
|
||||
}
|
||||
|
||||
+41
-22
@@ -1,30 +1,49 @@
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
|
||||
import prisma from "@calcom/prisma";
|
||||
import { Booking } from "@calcom/prisma/client";
|
||||
|
||||
import { schemaBooking, withValidBooking } from "@lib/validations/booking";
|
||||
import { withCost } from "@lib/helpers/withCost";
|
||||
import { withMiddleware } from "@lib/helpers/withMiddleware";
|
||||
import type { BookingResponse } from "@lib/types";
|
||||
import { schemaBookingBodyParams, schemaBookingPublic, withValidBooking } from "@lib/validations/booking";
|
||||
|
||||
type ResponseData = {
|
||||
data?: Booking;
|
||||
message?: string;
|
||||
error?: string;
|
||||
};
|
||||
/**
|
||||
* @swagger
|
||||
* /api/bookings/new:
|
||||
* post:
|
||||
* summary: Creates a new booking
|
||||
* requestBody:
|
||||
* description: Optional description in *Markdown*
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/Booking'
|
||||
* tags:
|
||||
* - bookings
|
||||
* responses:
|
||||
* 201:
|
||||
* description: OK, booking created
|
||||
* model: Booking
|
||||
* 400:
|
||||
* description: Bad request. Booking body is invalid.
|
||||
* 401:
|
||||
* description: Authorization information is missing or invalid.
|
||||
*/
|
||||
async function createBooking(req: NextApiRequest, res: NextApiResponse<BookingResponse>) {
|
||||
const safe = schemaBookingBodyParams.safeParse(req.body);
|
||||
if (!safe.success) throw new Error("Invalid request body", safe.error);
|
||||
|
||||
async function createBooking(req: NextApiRequest, res: NextApiResponse<ResponseData>) {
|
||||
const { body, method } = req;
|
||||
if (method === "POST") {
|
||||
const safe = schemaBooking.safeParse(body);
|
||||
if (safe.success && safe.data) {
|
||||
await prisma.booking
|
||||
.create({ data: safe.data })
|
||||
.then((booking) => res.status(201).json({ data: booking }))
|
||||
.catch((error) => res.status(400).json({ message: "Could not create booking type", error: error }));
|
||||
}
|
||||
} else {
|
||||
// Reject any other HTTP method than POST
|
||||
res.status(405).json({ error: "Only POST Method allowed" });
|
||||
}
|
||||
const booking = await prisma.booking.create({ data: safe.data });
|
||||
const data = schemaBookingPublic.parse(booking);
|
||||
|
||||
if (data) res.status(201).json({ data, message: "Booking created successfully" });
|
||||
else
|
||||
(error: Error) =>
|
||||
res.status(400).json({
|
||||
message: "Could not create new booking",
|
||||
error,
|
||||
});
|
||||
}
|
||||
|
||||
export default withValidBooking(createBooking);
|
||||
export default withMiddleware(withCost(5), "HTTP_POST")(withValidBooking(createBooking));
|
||||
|
||||
@@ -12,9 +12,16 @@ import { schemaTeamPublic } from "@lib/validations/team";
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /api/teams/:id:
|
||||
* /api/teams/{id}:
|
||||
* get:
|
||||
* summary: find team by ID
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: id
|
||||
* schema:
|
||||
* type: integer
|
||||
* required: true
|
||||
* description: Numeric ID of the team to get
|
||||
* tags:
|
||||
* - teams
|
||||
* responses:
|
||||
|
||||
@@ -12,12 +12,12 @@ import { schemaUserBodyParams, schemaUserPublic, withValidUser } from "@lib/vali
|
||||
* post:
|
||||
* summary: Creates a new user
|
||||
* requestBody:
|
||||
description: Optional description in *Markdown*
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/User'
|
||||
* description: Optional description in *Markdown*
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* $ref: '#/components/schemas/User'
|
||||
* tags:
|
||||
* - users
|
||||
* responses:
|
||||
|
||||
Reference in New Issue
Block a user