Merge pull request #130 from calcom/feat/dynamic-prisma

Feature: custom Prisma for self-hosted deployments needed for new hosted admin console
pull/9078/head
Agusti Fernandez Pardo 2022-06-23 23:39:29 +02:00 committed by GitHub
commit d675535cdf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 146 additions and 128 deletions

View File

@ -180,7 +180,15 @@ See <https://github.com/vercel/next.js/blob/canary/packages/next/server/dev/hot-
To remove this limitation, we need to ensure that on local endpoints are requested by swagger at /api/v1 and not /v1
## Deployment
## Hosted api through cal.com
Go to console.com
Add a deployment or go to an existing one.
Activate API or Admin addon
Provide your DATABASE-URL
Store it safely, you'll get a customApiID, save it.
call api.cal.com?apiKey=your_cal_instance_apiKey&customApiId=cal_datasource_key
## How to deploy
We recommend deploying API in vercel.
@ -194,4 +202,4 @@ OUTPUT DIRECTORY: `apps/api/.next`
See `scripts/vercel-deploy.sh` for more info on how the deployment is done.
## Environment variables
Lastly API requires an env var for `DATABASE_URL`
Lastly API requires an env var for `DATABASE_URL`

1
lib/constants.ts Normal file
View File

@ -0,0 +1 @@
export const PRISMA_CLIENT_CACHING_TIME = 1000 * 60 * 60 * 24;

View File

@ -0,0 +1,53 @@
import { hash } from "bcryptjs";
import cache from "memory-cache";
import { NextMiddleware } from "next-api-middleware";
import { PRISMA_CLIENT_CACHING_TIME } from "@calcom/api/lib/constants";
// import prismaAdmin from "@calcom/console/modules/common/utils/prisma";
import { CONSOLE_URL } from "@calcom/lib/constants";
import { prisma, customPrisma } from "@calcom/prisma";
// This replaces the prisma client for the cusotm one if the key is valid
export const customPrismaClient: NextMiddleware = async (req, res, next) => {
const {
query: { key },
}: { query: { key?: string } } = req;
// If no custom api Id is provided, attach to request the regular cal.com prisma client.
if (!key) {
req.prisma = prisma;
await next();
} else {
// If we have a key, we check if the deployment matching the key, has a databaseUrl value set.
const databaseUrl = await fetch(
`${process.env.NEXT_PUBLIC_CONSOLE_URL || CONSOLE_URL}/api/deployments/database?key=${key}`
)
.then((res) => res.json())
.then((res) => res.databaseUrl);
if (!databaseUrl) {
res.status(400).json({ error: "no databaseUrl set up at your instance yet" });
return;
}
// FIXME: Add some checks for the databaseUrl to make sure it is valid. (e.g. not a localhost)
const hashedUrl = await hash(databaseUrl, 12);
const cachedPrisma = cache.get(hashedUrl);
/* We cache each cusotm prisma client for 24h to avoid too many requests to the database. */
if (!cachedPrisma) {
cache.put(
hashedUrl,
customPrisma({ datasources: { db: { url: databaseUrl } } }),
PRISMA_CLIENT_CACHING_TIME // Cache the prisma client for 24 hours
);
}
req.prisma = customPrisma({ datasources: { db: { url: databaseUrl } } });
/* @note:
In order to skip verifyApiKey for customPrisma requests,
we pass isAdmin true, and userId 0, if we detect them later,
we skip verifyApiKey logic and pass onto next middleware instead.
*/
req.isAdmin = true;
req.userId = 0;
}
await next();
};

View File

@ -0,0 +1,22 @@
import type { IncomingMessage } from "http";
import { NextMiddleware } from "next-api-middleware";
import type { PrismaClient } from "@calcom/prisma/client";
/** @todo figure how to use the one from `@calcom/types` */
/** @todo: remove once `@calcom/types` is updated with it.*/
declare module "next" {
export interface NextApiRequest extends IncomingMessage {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
body: any;
userId: number;
method: string;
prisma: PrismaClient;
session: { user: { id: number } };
query: { [key: string]: string | string[] };
isAdmin: boolean;
}
}
export const extendRequest: NextMiddleware = async (req, res, next) => {
await next();
};

View File

@ -1,24 +1,9 @@
import type { IncomingMessage } from "http";
import { NextMiddleware } from "next-api-middleware";
import { hashAPIKey } from "@calcom/ee/lib/api/apiKeys";
import prisma from "@calcom/prisma";
import { isAdminGuard } from "@lib/utils/isAdmin";
/** @todo figure how to use the one from `@calcom/types`fi */
/** @todo: remove once `@calcom/types` is updated with it.*/
declare module "next" {
export interface NextApiRequest extends IncomingMessage {
userId: number;
method: string;
isAdmin: boolean;
query: { [key: string]: string | string[] };
// eslint-disable-next-line @typescript-eslint/no-explicit-any
session: any;
}
}
// Used to check if the apiKey is not expired, could be extracted if reused. but not for now.
export const dateNotInPast = function (date: Date) {
const now = new Date();
@ -29,23 +14,30 @@ 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) => {
const { prisma, userId, isAdmin } = req;
// If the user is an admin and using a license key (from customPrisma), skip the apiKey check.
if (userId === 0 && isAdmin) {
await next();
return;
}
// Check if the apiKey query param is provided.
if (!req.query.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_"
// 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_", "");
// 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 } });
// If we cannot find any api key. Throw a 401 Unauthorized.
// If 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)) {
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" });
/* We save the user id in the request for later use */
// save the user id in the request for later use
req.userId = apiKey.userId;
/* We save the isAdmin boolean here for later use */
req.isAdmin = await isAdminGuard(req.userId);
// save the isAdmin boolean here for later use
req.isAdmin = await isAdminGuard(req.userId, prisma);
await next();
};

View File

@ -2,6 +2,8 @@ import { label } from "next-api-middleware";
import { addRequestId } from "./addRequestid";
import { captureErrors } from "./captureErrors";
import { customPrismaClient } from "./customPrisma";
import { extendRequest } from "./extendRequest";
import {
HTTP_POST,
HTTP_DELETE,
@ -22,9 +24,12 @@ const withMiddleware = label(
HTTP_DELETE,
addRequestId,
verifyApiKey,
customPrismaClient,
extendRequest,
sentry: captureErrors,
},
["sentry", "verifyApiKey", "addRequestId"] // <-- Provide a list of middleware to call automatically
// The order here, determines the order of execution, put customPrismaClient before verifyApiKey always.
["extendRequest", "sentry", "customPrismaClient", "verifyApiKey", "addRequestId"] // <-- Provide a list of middleware to call automatically
);
export { withMiddleware };

View File

@ -1,8 +1,6 @@
import { UserPermissionRole } from "@prisma/client";
import { PrismaClient, UserPermissionRole } from "@prisma/client";
import prisma from "@calcom/prisma";
export const isAdminGuard = async (userId: number) => {
export const isAdminGuard = async (userId: number, prisma: PrismaClient) => {
const user = await prisma.user.findUnique({ where: { id: userId } });
return user?.role === UserPermissionRole.ADMIN;
};

View File

@ -7,7 +7,7 @@ export type GetSubscriberOptions = {
eventTypeId: number;
triggerEvent: WebhookTriggerEvents;
};
/** @note will this not work with custom prisma? since we're importing prisma directly and not passing it from request here **/
const getWebhooks = async (options: GetSubscriberOptions) => {
const { userId, eventTypeId } = options;
const allWebhooks = await prisma.webhook.findMany({

View File

@ -18,6 +18,7 @@
},
"devDependencies": {
"@calcom/tsconfig": "*",
"@calcom/types": "*",
"babel-jest": "^28.1.0",
"jest": "^28.1.0",
"node-mocks-http": "^1.11.0"
@ -26,6 +27,8 @@
"@calcom/app-store-cli": "*",
"@calcom/prisma": "*",
"@sentry/nextjs": "^6.19.7",
"bcryptjs": "^2.4.3",
"memory-cache": "^0.2.0",
"modify-response-middleware": "^1.1.0",
"next": "^12.1.6",
"next-api-middleware": "^1.0.1",

View File

@ -1,7 +1,5 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import type { AttendeeResponse } from "@lib/types";
import { schemaAttendeeEditBodyParams, schemaAttendeeReadPublic } from "@lib/validations/attendee";
@ -11,7 +9,7 @@ import {
} from "@lib/validations/shared/queryIdTransformParseInt";
export async function attendeeById(
{ method, query, body, userId, isAdmin }: NextApiRequest,
{ method, query, body, userId, isAdmin, prisma }: NextApiRequest,
res: NextApiResponse<AttendeeResponse>
) {
const safeQuery = schemaQueryIdParseInt.safeParse(query);

View File

@ -1,13 +1,11 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import { AttendeeResponse, AttendeesResponse } from "@lib/types";
import type { AttendeeResponse, AttendeesResponse } from "@lib/types";
import { schemaAttendeeCreateBodyParams, schemaAttendeeReadPublic } from "@lib/validations/attendee";
async function createOrlistAllAttendees(
{ method, userId, body, isAdmin }: NextApiRequest,
{ method, userId, body, prisma, isAdmin }: NextApiRequest,
res: NextApiResponse<AttendeesResponse | AttendeeResponse>
) {
let attendees;
@ -138,13 +136,7 @@ async function createOrlistAllAttendees(
attendee,
message: "Attendee created successfully",
});
} else {
(error: Error) =>
res.status(400).json({
message: "Could not create new attendee",
error,
});
}
} else (error: Error) => res.status(400).json({ error });
}
} else res.status(405).json({ message: `Method ${method} not allowed` });
}

View File

@ -1,7 +1,5 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import type { AvailabilityResponse } from "@lib/types";
import {
@ -14,7 +12,7 @@ import {
} from "@lib/validations/shared/queryIdTransformParseInt";
export async function availabilityById(
{ method, query, body, userId }: NextApiRequest,
{ method, query, body, userId, prisma }: NextApiRequest,
res: NextApiResponse<AvailabilityResponse>
) {
const safeQuery = schemaQueryIdParseInt.safeParse(query);

View File

@ -1,7 +1,5 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import { AvailabilityResponse, AvailabilitiesResponse } from "@lib/types";
import {
@ -10,7 +8,7 @@ import {
} from "@lib/validations/availability";
async function createOrlistAllAvailabilities(
{ method, body, userId }: NextApiRequest,
{ method, body, userId, prisma }: NextApiRequest,
res: NextApiResponse<AvailabilitiesResponse | AvailabilityResponse>
) {
if (method === "GET") {

View File

@ -1,7 +1,5 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import type { BookingReferenceResponse } from "@lib/types";
import {
@ -14,7 +12,7 @@ import {
} from "@lib/validations/shared/queryIdTransformParseInt";
export async function bookingReferenceById(
{ method, query, body, userId }: NextApiRequest,
{ method, query, body, userId, prisma }: NextApiRequest,
res: NextApiResponse<BookingReferenceResponse>
) {
const safeQuery = schemaQueryIdParseInt.safeParse(query);
@ -64,7 +62,6 @@ export async function bookingReferenceById(
.then((data) => schemaBookingReferenceReadPublic.parse(data))
.then((booking_reference) => res.status(200).json({ booking_reference }))
.catch((error: Error) => {
console.log(error);
res.status(404).json({
message: `BookingReference with id: ${safeQuery.data.id} not found`,
error,

View File

@ -1,7 +1,5 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import { BookingReferenceResponse, BookingReferencesResponse } from "@lib/types";
import {
@ -10,7 +8,7 @@ import {
} from "@lib/validations/booking-reference";
async function createOrlistAllBookingReferences(
{ method, userId, body }: NextApiRequest,
{ method, userId, body, prisma }: NextApiRequest,
res: NextApiResponse<BookingReferencesResponse | BookingReferenceResponse>
) {
const userWithBookings = await prisma.user.findUnique({

View File

@ -1,7 +1,5 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import type { BookingResponse } from "@lib/types";
import { schemaBookingEditBodyParams, schemaBookingReadPublic } from "@lib/validations/booking";
@ -11,7 +9,7 @@ import {
} from "@lib/validations/shared/queryIdTransformParseInt";
export async function bookingById(
{ method, query, body, userId, isAdmin }: NextApiRequest,
{ method, query, body, userId, prisma, isAdmin }: NextApiRequest,
res: NextApiResponse<BookingResponse>
) {
const safeQuery = schemaQueryIdParseInt.safeParse(query);

View File

@ -2,8 +2,6 @@ import { WebhookTriggerEvents } from "@prisma/client";
import type { NextApiRequest, NextApiResponse } from "next";
import { v4 as uuidv4 } from "uuid";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import { BookingResponse, BookingsResponse } from "@lib/types";
import sendPayload from "@lib/utils/sendPayload";
@ -12,10 +10,9 @@ import { schemaBookingCreateBodyParams, schemaBookingReadPublic } from "@lib/val
import { schemaEventTypeReadPublic } from "@lib/validations/event-type";
async function createOrlistAllBookings(
{ method, body, userId, isAdmin }: NextApiRequest,
{ method, body, userId, isAdmin, prisma }: NextApiRequest,
res: NextApiResponse<BookingsResponse | BookingResponse>
) {
console.log("userIduserId", userId);
if (method === "GET") {
/**
* @swagger

View File

@ -1,7 +1,5 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import type { EventTypeCustomInputResponse } from "@lib/types";
import {
@ -72,7 +70,7 @@ import {
* description: Authorization information is missing or invalid.
*/
async function eventTypeById(
{ method, query, body, userId }: NextApiRequest,
{ method, query, body, userId, prisma }: NextApiRequest,
res: NextApiResponse<EventTypeCustomInputResponse>
) {
const safeQuery = schemaQueryIdParseInt.safeParse(query);

View File

@ -1,7 +1,5 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import { EventTypeCustomInputResponse, EventTypeCustomInputsResponse } from "@lib/types";
import {
@ -10,7 +8,7 @@ import {
} from "@lib/validations/event-type-custom-input";
async function createOrlistAllEventTypeCustomInputs(
{ userId, method, body }: NextApiRequest,
{ userId, method, body, prisma }: NextApiRequest,
res: NextApiResponse<EventTypeCustomInputsResponse | EventTypeCustomInputResponse>
) {
const data = await prisma.eventType.findMany({ where: { userId } });

View File

@ -1,7 +1,5 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import type { DestinationCalendarResponse } from "@lib/types";
import {
@ -14,7 +12,7 @@ import {
} from "@lib/validations/shared/queryIdTransformParseInt";
export async function destionationCalendarById(
{ method, query, body, userId }: NextApiRequest,
{ method, query, body, userId, prisma }: NextApiRequest,
res: NextApiResponse<DestinationCalendarResponse>
) {
const safeQuery = schemaQueryIdParseInt.safeParse(query);

View File

@ -1,7 +1,5 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import { DestinationCalendarResponse, DestinationCalendarsResponse } from "@lib/types";
import {
@ -10,7 +8,7 @@ import {
} from "@lib/validations/destination-calendar";
async function createOrlistAllDestinationCalendars(
{ method, body, userId }: NextApiRequest,
{ method, body, userId, prisma }: NextApiRequest,
res: NextApiResponse<DestinationCalendarsResponse | DestinationCalendarResponse>
) {
if (method === "GET") {

View File

@ -1,7 +1,5 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import type { DailyEventReferenceResponse } from "@lib/types";
import {
@ -14,7 +12,7 @@ import {
} from "@lib/validations/shared/queryIdTransformParseInt";
export async function dailyEventReferenceById(
{ method, query, body, userId }: NextApiRequest,
{ method, query, body, userId, prisma }: NextApiRequest,
res: NextApiResponse<DailyEventReferenceResponse>
) {
const safeQuery = schemaQueryIdParseInt.safeParse(query);

View File

@ -1,7 +1,5 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import { DailyEventReferenceResponse, DailyEventReferencesResponse } from "@lib/types";
import {
@ -10,7 +8,7 @@ import {
} from "@lib/validations/event-reference";
async function createOrlistAllDailyEventReferences(
{ method, body, userId }: NextApiRequest,
{ method, body, userId, prisma }: NextApiRequest,
res: NextApiResponse<DailyEventReferencesResponse | DailyEventReferenceResponse>
) {
const userBookings = await prisma.booking.findMany({ where: { userId } });

View File

@ -1,7 +1,5 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import type { EventTypeResponse } from "@lib/types";
import { schemaEventTypeEditBodyParams, schemaEventTypeReadPublic } from "@lib/validations/event-type";
@ -11,7 +9,7 @@ import {
} from "@lib/validations/shared/queryIdTransformParseInt";
export async function eventTypeById(
{ method, query, body, userId, isAdmin }: NextApiRequest,
{ method, query, body, userId, isAdmin, prisma }: NextApiRequest,
res: NextApiResponse<EventTypeResponse>
) {
const safeQuery = schemaQueryIdParseInt.safeParse(query);

View File

@ -1,13 +1,11 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import { EventTypeResponse, EventTypesResponse } from "@lib/types";
import { schemaEventTypeCreateBodyParams, schemaEventTypeReadPublic } from "@lib/validations/event-type";
async function createOrlistAllEventTypes(
{ method, body, userId, isAdmin }: NextApiRequest,
{ method, body, userId, isAdmin, prisma }: NextApiRequest,
res: NextApiResponse<EventTypesResponse | EventTypeResponse>
) {
if (method === "GET") {

View File

@ -1,14 +1,12 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import type { WebhookResponse } from "@lib/types";
import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString";
import { schemaWebhookEditBodyParams, schemaWebhookReadPublic } from "@lib/validations/webhook";
export async function WebhookById(
{ method, query, body, userId }: NextApiRequest,
{ method, query, body, userId, prisma }: NextApiRequest,
res: NextApiResponse<WebhookResponse>
) {
const safeQuery = schemaQueryIdAsString.safeParse(query);

View File

@ -1,14 +1,12 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { v4 as uuidv4 } from "uuid";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import { WebhookResponse, WebhooksResponse } from "@lib/types";
import { schemaWebhookCreateBodyParams } from "@lib/validations/webhook";
async function createOrlistAllWebhooks(
{ method, body, userId }: NextApiRequest,
{ method, body, userId, prisma }: NextApiRequest,
res: NextApiResponse<WebhooksResponse | WebhookResponse>
) {
if (method === "GET") {

View File

@ -1,14 +1,12 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import type { MembershipResponse } from "@lib/types";
import { schemaMembershipBodyParams, schemaMembershipPublic } from "@lib/validations/membership";
import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString";
export async function membershipById(
{ method, query, body, userId }: NextApiRequest,
{ method, query, body, userId, prisma }: NextApiRequest,
res: NextApiResponse<MembershipResponse>
) {
const safeQuery = schemaQueryIdAsString.safeParse(query);

View File

@ -1,13 +1,11 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import { MembershipResponse, MembershipsResponse } from "@lib/types";
import { schemaMembershipBodyParams, schemaMembershipPublic } from "@lib/validations/membership";
async function createOrlistAllMemberships(
{ method, body, userId }: NextApiRequest,
{ method, body, userId, prisma }: NextApiRequest,
res: NextApiResponse<MembershipsResponse | MembershipResponse>
) {
if (method === "GET") {

View File

@ -1,7 +1,5 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import type { PaymentResponse } from "@lib/types";
import { schemaPaymentPublic } from "@lib/validations/payment";
@ -33,7 +31,7 @@ import {
* description: Payment was not found
*/
export async function paymentById(
{ method, query, userId }: NextApiRequest,
{ method, query, userId, prisma }: NextApiRequest,
res: NextApiResponse<PaymentResponse>
) {
const safeQuery = schemaQueryIdParseInt.safeParse(query);

View File

@ -1,7 +1,5 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import { PaymentsResponse } from "@lib/types";
import { schemaPaymentPublic } from "@lib/validations/payment";
@ -21,7 +19,7 @@ import { schemaPaymentPublic } from "@lib/validations/payment";
* 404:
* description: No payments were found
*/
async function allPayments({ userId }: NextApiRequest, res: NextApiResponse<PaymentsResponse>) {
async function allPayments({ userId, prisma }: NextApiRequest, res: NextApiResponse<PaymentsResponse>) {
const userWithBookings = await prisma.user.findUnique({
where: { id: userId },
include: { bookings: true },

View File

@ -1,7 +1,5 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import type { ScheduleResponse } from "@lib/types";
import { schemaScheduleBodyParams, schemaSchedulePublic } from "@lib/validations/schedule";
@ -11,7 +9,7 @@ import {
} from "@lib/validations/shared/queryIdTransformParseInt";
export async function scheduleById(
{ method, query, body, userId }: NextApiRequest,
{ method, query, body, userId, prisma }: NextApiRequest,
res: NextApiResponse<ScheduleResponse>
) {
const safeQuery = schemaQueryIdParseInt.safeParse(query);

View File

@ -1,13 +1,11 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import { ScheduleResponse, SchedulesResponse } from "@lib/types";
import { schemaScheduleBodyParams, schemaSchedulePublic } from "@lib/validations/schedule";
async function createOrlistAllSchedules(
{ method, body, userId }: NextApiRequest,
{ method, body, userId, prisma }: NextApiRequest,
res: NextApiResponse<SchedulesResponse | ScheduleResponse>
) {
if (method === "GET") {

View File

@ -1,7 +1,5 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import type { SelectedCalendarResponse } from "@lib/types";
import {
@ -11,7 +9,7 @@ import {
import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString";
export async function selectedCalendarById(
{ method, query, body, userId }: NextApiRequest,
{ method, query, body, userId, prisma }: NextApiRequest,
res: NextApiResponse<SelectedCalendarResponse>
) {
const safeQuery = schemaQueryIdAsString.safeParse(query);

View File

@ -1,7 +1,5 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import { SelectedCalendarResponse, SelectedCalendarsResponse } from "@lib/types";
import {
@ -10,7 +8,7 @@ import {
} from "@lib/validations/selected-calendar";
async function createOrlistAllSelectedCalendars(
{ method, body, userId }: NextApiRequest,
{ method, body, userId, prisma }: NextApiRequest,
res: NextApiResponse<SelectedCalendarsResponse | SelectedCalendarResponse>
) {
if (method === "GET") {

View File

@ -1,7 +1,5 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import type { TeamResponse } from "@lib/types";
import {
@ -72,7 +70,7 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team";
* description: Authorization information is missing or invalid.
*/
export async function teamById(
{ method, query, body, userId }: NextApiRequest,
{ method, query, body, userId, prisma }: NextApiRequest,
res: NextApiResponse<TeamResponse>
) {
const safeQuery = schemaQueryIdParseInt.safeParse(query);

View File

@ -1,14 +1,12 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "@lib/helpers/withMiddleware";
import { TeamResponse, TeamsResponse } from "@lib/types";
import { schemaMembershipPublic } from "@lib/validations/membership";
import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team";
async function createOrlistAllTeams(
{ method, body, userId }: NextApiRequest,
{ method, body, userId, prisma }: NextApiRequest,
res: NextApiResponse<TeamsResponse | TeamResponse>
) {
if (method === "GET") {

View File

@ -33,7 +33,7 @@ import { schemaQueryUserId } from "@lib/validations/shared/queryUserId";
*/
export async function deleteHandler(req: NextApiRequest) {
const query = schemaQueryUserId.parse(req.query);
const isAdmin = await isAdminGuard(req.userId);
const isAdmin = await isAdminGuard(req.userId, req.prisma);
// Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user
if (!isAdmin && query.userId !== req.userId)
throw new HttpError({ statusCode: 401, message: "Unauthorized" });

View File

@ -34,7 +34,7 @@ import { schemaUserReadPublic } from "@lib/validations/user";
*/
export async function getHandler(req: NextApiRequest) {
const query = schemaQueryUserId.parse(req.query);
const isAdmin = await isAdminGuard(req.userId);
const isAdmin = await isAdminGuard(req.userId, req.prisma);
// Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user
if (!isAdmin && query.userId !== req.userId)
throw new HttpError({ statusCode: 401, message: "Unauthorized" });

View File

@ -55,7 +55,7 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations
*/
export async function patchHandler(req: NextApiRequest) {
const query = schemaQueryUserId.parse(req.query);
const isAdmin = await isAdminGuard(req.userId);
const isAdmin = await isAdminGuard(req.userId, req.prisma);
// Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user
if (!isAdmin && query.userId !== req.userId)
throw new HttpError({ statusCode: 401, message: "Unauthorized" });

View File

@ -24,8 +24,8 @@ import { Prisma } from ".prisma/client";
* 404:
* description: No users were found
*/
async function getHandler({ userId }: NextApiRequest) {
const isAdmin = await isAdminGuard(userId);
async function getHandler({ userId, prisma }: NextApiRequest) {
const isAdmin = await isAdminGuard(userId, prisma);
const where: Prisma.UserWhereInput = {};
// If user is not ADMIN, return only his data.
if (!isAdmin) where.id = userId;

View File

@ -8,7 +8,7 @@ import { isAdminGuard } from "@lib/utils/isAdmin";
import { schemaUserCreateBodyParams } from "@lib/validations/user";
async function postHandler(req: NextApiRequest) {
const isAdmin = await isAdminGuard(req.userId);
const isAdmin = await isAdminGuard(req.userId, req.prisma);
// If user is not ADMIN, return unauthorized.
if (!isAdmin) throw new HttpError({ statusCode: 401, message: "You are not authorized" });
const data = schemaUserCreateBodyParams.parse(req.body);