perf: bookings query improvement (#10687)
This commit is contained in:
parent
43b3d68447
commit
5503d9d432
|
@ -1,6 +1,5 @@
|
|||
import type { PrismaClient } from "@prisma/client";
|
||||
|
||||
import { entityPrismaWhereClause } from "@calcom/lib/entityPermissionUtils";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import { TRPCError } from "@calcom/trpc/server";
|
||||
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import type { PrismaClient } from "@prisma/client";
|
||||
import type { App_RoutingForms_Form } from "@prisma/client";
|
||||
import { Prisma } from "@prisma/client";
|
||||
|
||||
import { entityPrismaWhereClause, canEditEntity } from "@calcom/lib/entityPermissionUtils";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import { TRPCError } from "@calcom/trpc/server";
|
||||
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import type { PrismaClient } from "@prisma/client";
|
||||
|
||||
import { entityPrismaWhereClause } from "@calcom/lib/entityPermissionUtils";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
|
||||
|
||||
import { getSerializableForm } from "../lib/getSerializableForm";
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { hasFilter } from "@calcom/features/filters/lib/hasFilter";
|
||||
import { entityPrismaWhereClause, canEditEntity } from "@calcom/lib/entityPermissionUtils";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import type { PrismaClient, Prisma } from "@calcom/prisma/client";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import type { Prisma } from "@calcom/prisma/client";
|
||||
import { entries } from "@calcom/prisma/zod-utils";
|
||||
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import type { PrismaClient } from "@prisma/client";
|
||||
|
||||
import logger from "@calcom/lib/logger";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import { TRPCError } from "@calcom/trpc/server";
|
||||
|
||||
import { jsonLogicToPrisma } from "../jsonLogicToPrisma";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { PrismaClient } from "@prisma/client";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { z } from "zod";
|
||||
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import { TRPCError } from "@calcom/trpc/server";
|
||||
|
||||
import { getSerializableForm } from "../lib/getSerializableForm";
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import type { Prisma, PrismaClient } from "@prisma/client";
|
||||
import type { Prisma } from "@prisma/client";
|
||||
import type { z } from "zod";
|
||||
|
||||
import { bookingResponsesDbSchema } from "@calcom/features/bookings/lib/getBookingResponsesSchema";
|
||||
import slugify from "@calcom/lib/slugify";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import prisma from "@calcom/prisma";
|
||||
|
||||
type BookingSelect = {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { Prisma, PrismaClient, Workflow, WorkflowsOnEventTypes, WorkflowStep } from "@prisma/client";
|
||||
import type { Prisma, Workflow, WorkflowsOnEventTypes, WorkflowStep } from "@prisma/client";
|
||||
|
||||
import { scheduleTrigger } from "@calcom/app-store/zapier/lib/nodeScheduler";
|
||||
import type { EventManagerUser } from "@calcom/core/EventManager";
|
||||
|
@ -11,6 +11,7 @@ import type { EventTypeInfo } from "@calcom/features/webhooks/lib/sendPayload";
|
|||
import sendPayload from "@calcom/features/webhooks/lib/sendPayload";
|
||||
import { getTeamIdFromEventType } from "@calcom/lib/getTeamIdFromEventType";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import { BookingStatus, WebhookTriggerEvents } from "@calcom/prisma/enums";
|
||||
import { bookingMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||
import type { AdditionalInformation, CalendarEvent } from "@calcom/types/Calendar";
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import type { PrismaClient } from "@prisma/client";
|
||||
import cache from "memory-cache";
|
||||
import { z } from "zod";
|
||||
|
||||
import { CONSOLE_URL } from "@calcom/lib/constants";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
|
||||
const CACHING_TIME = 86400000; // 24 hours in milliseconds
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { PrismaClient } from "@prisma/client";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
|
||||
export async function getDeploymentKey(prisma: PrismaClient) {
|
||||
const deployment = await prisma.deployment.findUnique({
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import type { PrismaClient, Prisma } from "@prisma/client";
|
||||
import type { Prisma } from "@prisma/client";
|
||||
import short from "short-uuid";
|
||||
import { v5 as uuidv5 } from "uuid";
|
||||
|
||||
import { sendSlugReplacementEmail } from "@calcom/emails/email-manager";
|
||||
import { getTranslation } from "@calcom/lib/server/i18n";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import { SchedulingType } from "@calcom/prisma/enums";
|
||||
import { _EventTypeModel } from "@calcom/prisma/zod";
|
||||
import { allManagedEventTypeProps, unlockedManagedEventTypeProps } from "@calcom/prisma/zod-utils";
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import type { SAMLSSORecord, OIDCSSORecord } from "@boxyhq/saml-jackson";
|
||||
import type { PrismaClient } from "@prisma/client";
|
||||
|
||||
import { HOSTED_CAL_FEATURES } from "@calcom/lib/constants";
|
||||
import { isTeamAdmin } from "@calcom/lib/server/queries/teams";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import { TRPCError } from "@calcom/trpc/server";
|
||||
|
||||
export const samlDatabaseUrl = process.env.SAML_DATABASE_URL || "";
|
||||
|
|
|
@ -9,7 +9,7 @@ import { getSlugOrRequestedSlug } from "@calcom/features/ee/organizations/lib/or
|
|||
import { isRecurringEvent, parseRecurringEvent } from "@calcom/lib";
|
||||
import { getDefaultEvent, getUsernameList } from "@calcom/lib/defaultEvents";
|
||||
import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML";
|
||||
import type { PrismaClient } from "@calcom/prisma/client";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import type { BookerLayoutSettings } from "@calcom/prisma/zod-utils";
|
||||
import {
|
||||
bookerLayoutOptions,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { PrismaClient } from "@prisma/client";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
|
||||
import type { AppFlags } from "../config";
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import type { PrismaClient } from "@prisma/client";
|
||||
|
||||
import defaultPrisma from "@calcom/prisma";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import type { WebhookTriggerEvents } from "@calcom/prisma/enums";
|
||||
|
||||
export type GetSubscriberOptions = {
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import type { Prisma, PrismaClient } from "@prisma/client";
|
||||
import type { Prisma } from "@prisma/client";
|
||||
import type { z } from "zod";
|
||||
|
||||
import { bookingResponsesDbSchema } from "@calcom/features/bookings/lib/getBookingResponsesSchema";
|
||||
import slugify from "@calcom/lib/slugify";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
|
||||
type BookingSelect = {
|
||||
description: true;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import type { PrismaClient } from "@prisma/client";
|
||||
import { Prisma } from "@prisma/client";
|
||||
|
||||
import { getLocationGroupedOptions } from "@calcom/app-store/server";
|
||||
|
@ -10,6 +9,7 @@ import { parseBookingLimit, parseDurationLimit, parseRecurringEvent } from "@cal
|
|||
import { CAL_URL } from "@calcom/lib/constants";
|
||||
import getPaymentAppData from "@calcom/lib/getPaymentAppData";
|
||||
import { getTranslation } from "@calcom/lib/server/i18n";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import { SchedulingType, MembershipRole, AppCategories } from "@calcom/prisma/enums";
|
||||
import { customInputSchema, EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { PrismaClient } from "@prisma/client";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
|
||||
export async function maybeGetBookingUidFromSeat(prisma: PrismaClient, uid: string) {
|
||||
// Look bookingUid in bookingSeat
|
||||
|
|
|
@ -1,28 +1,65 @@
|
|||
import type { Prisma } from "@prisma/client";
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import { PrismaClient as PrismaClientWithoutExtension } from "@prisma/client";
|
||||
|
||||
import { bookingReferenceMiddleware } from "./middleware";
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line no-var
|
||||
var prisma: PrismaClient | undefined;
|
||||
var prisma: typeof prismaWithClientExtensions;
|
||||
}
|
||||
|
||||
const prismaOptions: Prisma.PrismaClientOptions = {};
|
||||
|
||||
if (!!process.env.NEXT_PUBLIC_DEBUG) prismaOptions.log = ["query", "error", "warn"];
|
||||
|
||||
export const prisma = globalThis.prisma || new PrismaClient(prismaOptions);
|
||||
const prismaWithoutClientExtensions = new PrismaClientWithoutExtension(prismaOptions);
|
||||
|
||||
export const customPrisma = (options: Prisma.PrismaClientOptions) =>
|
||||
new PrismaClient({ ...prismaOptions, ...options });
|
||||
new PrismaClientWithoutExtension({ ...prismaOptions, ...options });
|
||||
|
||||
// If any changed on middleware server restart is required
|
||||
// TODO: Migrate it to $extends
|
||||
bookingReferenceMiddleware(prismaWithoutClientExtensions);
|
||||
|
||||
// FIXME: Due to some reason, there are types failing in certain places due to the $extends. Fix it and then enable it
|
||||
// Specifically we get errors like `Type 'string | Date | null | undefined' is not assignable to type 'Exact<string | Date | null | undefined, string | Date | null | undefined>'`
|
||||
// const prismaWithClientExtensions = prismaWithoutClientExtensions.$extends({
|
||||
// query: {
|
||||
// $allModels: {
|
||||
// async $allOperations({ model, operation, args, query }) {
|
||||
// const start = performance.now();
|
||||
// /* your custom logic here */
|
||||
// const res = await query(args);
|
||||
// const end = performance.now();
|
||||
// logger.debug("Query Perf: ", `${model}.${operation} took ${(end - start).toFixed(2)}ms\n`);
|
||||
// return res;
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
// .$extends({
|
||||
// name: "teamUpdateWithMetadata",
|
||||
// query: {
|
||||
// team: {
|
||||
// async update({ model, operation, args, query }) {
|
||||
// if (args.data.metadata) {
|
||||
// // Prepare args.data with merged metadata
|
||||
// }
|
||||
// return query(args);
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// })
|
||||
|
||||
const prismaWithClientExtensions = prismaWithoutClientExtensions;
|
||||
|
||||
export const prisma = (globalThis.prisma as typeof prismaWithClientExtensions) || prismaWithClientExtensions;
|
||||
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
globalThis.prisma = prisma;
|
||||
}
|
||||
// If any changed on middleware server restart is required
|
||||
bookingReferenceMiddleware(prisma);
|
||||
|
||||
export type PrismaClient = typeof prisma;
|
||||
export default prisma;
|
||||
|
||||
export * from "./selects";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { PrismaClient } from "@prisma/client";
|
||||
import type { PrismaClient } from "@prisma/client";
|
||||
|
||||
function middleware(prisma: PrismaClient) {
|
||||
/***********************************/
|
||||
|
|
|
@ -0,0 +1,325 @@
|
|||
/**
|
||||
* This script can be used to seed the database with a lot of data for performance testing.
|
||||
* TODO: Make it more structured and configurable from CLI
|
||||
* Run it as `npx ts-node --transpile-only ./seed-performance-testing.ts`
|
||||
*/
|
||||
import { uuid } from "short-uuid";
|
||||
|
||||
import dailyMeta from "@calcom/app-store/dailyvideo/_metadata";
|
||||
import googleMeetMeta from "@calcom/app-store/googlevideo/_metadata";
|
||||
import zoomMeta from "@calcom/app-store/zoomvideo/_metadata";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { BookingStatus } from "@calcom/prisma/enums";
|
||||
|
||||
import { createUserAndEventType } from "./seed-utils";
|
||||
|
||||
async function createManyDifferentUsersWithDifferentEventTypesAndBookings({
|
||||
tillUser,
|
||||
startFrom = 0,
|
||||
}: {
|
||||
tillUser: number;
|
||||
startFrom?: number;
|
||||
}) {
|
||||
for (let i = startFrom; i < tillUser; i++) {
|
||||
await createUserAndEventType({
|
||||
user: {
|
||||
email: `pro${i}@example.com`,
|
||||
name: "Pro Example",
|
||||
password: "1111",
|
||||
username: `pro${i}`,
|
||||
theme: "light",
|
||||
},
|
||||
eventTypes: [
|
||||
{
|
||||
title: "30min",
|
||||
slug: "30min",
|
||||
length: 30,
|
||||
_bookings: [
|
||||
{
|
||||
uid: uuid(),
|
||||
title: "30min",
|
||||
startTime: dayjs().add(1, "day").toDate(),
|
||||
endTime: dayjs().add(1, "day").add(30, "minutes").toDate(),
|
||||
},
|
||||
{
|
||||
uid: uuid(),
|
||||
title: "30min",
|
||||
startTime: dayjs().add(2, "day").toDate(),
|
||||
endTime: dayjs().add(2, "day").add(30, "minutes").toDate(),
|
||||
status: BookingStatus.PENDING,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "60min",
|
||||
slug: "60min",
|
||||
length: 60,
|
||||
},
|
||||
{
|
||||
title: "Multiple duration",
|
||||
slug: "multiple-duration",
|
||||
length: 75,
|
||||
metadata: {
|
||||
multipleDuration: [30, 75, 90],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "paid",
|
||||
slug: "paid",
|
||||
length: 60,
|
||||
price: 100,
|
||||
},
|
||||
{
|
||||
title: "In person meeting",
|
||||
slug: "in-person",
|
||||
length: 60,
|
||||
locations: [{ type: "inPerson", address: "London" }],
|
||||
},
|
||||
{
|
||||
title: "Zoom Event",
|
||||
slug: "zoom",
|
||||
length: 60,
|
||||
locations: [{ type: zoomMeta.appData?.location?.type }],
|
||||
},
|
||||
{
|
||||
title: "Daily Event",
|
||||
slug: "daily",
|
||||
length: 60,
|
||||
locations: [{ type: dailyMeta.appData?.location?.type }],
|
||||
},
|
||||
{
|
||||
title: "Google Meet",
|
||||
slug: "google-meet",
|
||||
length: 60,
|
||||
locations: [{ type: googleMeetMeta.appData?.location?.type }],
|
||||
},
|
||||
{
|
||||
title: "Yoga class",
|
||||
slug: "yoga-class",
|
||||
length: 30,
|
||||
recurringEvent: { freq: 2, count: 12, interval: 1 },
|
||||
_bookings: [
|
||||
{
|
||||
uid: uuid(),
|
||||
title: "Yoga class",
|
||||
recurringEventId: Buffer.from("yoga-class").toString("base64"),
|
||||
startTime: dayjs().add(1, "day").toDate(),
|
||||
endTime: dayjs().add(1, "day").add(30, "minutes").toDate(),
|
||||
status: BookingStatus.ACCEPTED,
|
||||
},
|
||||
{
|
||||
uid: uuid(),
|
||||
title: "Yoga class",
|
||||
recurringEventId: Buffer.from("yoga-class").toString("base64"),
|
||||
startTime: dayjs().add(1, "day").add(1, "week").toDate(),
|
||||
endTime: dayjs().add(1, "day").add(1, "week").add(30, "minutes").toDate(),
|
||||
status: BookingStatus.ACCEPTED,
|
||||
},
|
||||
{
|
||||
uid: uuid(),
|
||||
title: "Yoga class",
|
||||
recurringEventId: Buffer.from("yoga-class").toString("base64"),
|
||||
startTime: dayjs().add(1, "day").add(2, "week").toDate(),
|
||||
endTime: dayjs().add(1, "day").add(2, "week").add(30, "minutes").toDate(),
|
||||
status: BookingStatus.ACCEPTED,
|
||||
},
|
||||
{
|
||||
uid: uuid(),
|
||||
title: "Yoga class",
|
||||
recurringEventId: Buffer.from("yoga-class").toString("base64"),
|
||||
startTime: dayjs().add(1, "day").add(3, "week").toDate(),
|
||||
endTime: dayjs().add(1, "day").add(3, "week").add(30, "minutes").toDate(),
|
||||
status: BookingStatus.ACCEPTED,
|
||||
},
|
||||
{
|
||||
uid: uuid(),
|
||||
title: "Yoga class",
|
||||
recurringEventId: Buffer.from("yoga-class").toString("base64"),
|
||||
startTime: dayjs().add(1, "day").add(4, "week").toDate(),
|
||||
endTime: dayjs().add(1, "day").add(4, "week").add(30, "minutes").toDate(),
|
||||
status: BookingStatus.ACCEPTED,
|
||||
},
|
||||
{
|
||||
uid: uuid(),
|
||||
title: "Yoga class",
|
||||
recurringEventId: Buffer.from("yoga-class").toString("base64"),
|
||||
startTime: dayjs().add(1, "day").add(5, "week").toDate(),
|
||||
endTime: dayjs().add(1, "day").add(5, "week").add(30, "minutes").toDate(),
|
||||
status: BookingStatus.ACCEPTED,
|
||||
},
|
||||
{
|
||||
uid: uuid(),
|
||||
title: "Seeded Yoga class",
|
||||
description: "seeded",
|
||||
recurringEventId: Buffer.from("seeded-yoga-class").toString("base64"),
|
||||
startTime: dayjs().subtract(4, "day").toDate(),
|
||||
endTime: dayjs().subtract(4, "day").add(30, "minutes").toDate(),
|
||||
status: BookingStatus.ACCEPTED,
|
||||
},
|
||||
{
|
||||
uid: uuid(),
|
||||
title: "Seeded Yoga class",
|
||||
description: "seeded",
|
||||
recurringEventId: Buffer.from("seeded-yoga-class").toString("base64"),
|
||||
startTime: dayjs().subtract(4, "day").add(1, "week").toDate(),
|
||||
endTime: dayjs().subtract(4, "day").add(1, "week").add(30, "minutes").toDate(),
|
||||
status: BookingStatus.ACCEPTED,
|
||||
},
|
||||
{
|
||||
uid: uuid(),
|
||||
title: "Seeded Yoga class",
|
||||
description: "seeded",
|
||||
recurringEventId: Buffer.from("seeded-yoga-class").toString("base64"),
|
||||
startTime: dayjs().subtract(4, "day").add(2, "week").toDate(),
|
||||
endTime: dayjs().subtract(4, "day").add(2, "week").add(30, "minutes").toDate(),
|
||||
status: BookingStatus.ACCEPTED,
|
||||
},
|
||||
{
|
||||
uid: uuid(),
|
||||
title: "Seeded Yoga class",
|
||||
description: "seeded",
|
||||
recurringEventId: Buffer.from("seeded-yoga-class").toString("base64"),
|
||||
startTime: dayjs().subtract(4, "day").add(3, "week").toDate(),
|
||||
endTime: dayjs().subtract(4, "day").add(3, "week").add(30, "minutes").toDate(),
|
||||
status: BookingStatus.ACCEPTED,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Tennis class",
|
||||
slug: "tennis-class",
|
||||
length: 60,
|
||||
recurringEvent: { freq: 2, count: 10, interval: 2 },
|
||||
requiresConfirmation: true,
|
||||
_bookings: [
|
||||
{
|
||||
uid: uuid(),
|
||||
title: "Tennis class",
|
||||
recurringEventId: Buffer.from("tennis-class").toString("base64"),
|
||||
startTime: dayjs().add(2, "day").toDate(),
|
||||
endTime: dayjs().add(2, "day").add(60, "minutes").toDate(),
|
||||
status: BookingStatus.PENDING,
|
||||
},
|
||||
{
|
||||
uid: uuid(),
|
||||
title: "Tennis class",
|
||||
recurringEventId: Buffer.from("tennis-class").toString("base64"),
|
||||
startTime: dayjs().add(2, "day").add(2, "week").toDate(),
|
||||
endTime: dayjs().add(2, "day").add(2, "week").add(60, "minutes").toDate(),
|
||||
status: BookingStatus.PENDING,
|
||||
},
|
||||
{
|
||||
uid: uuid(),
|
||||
title: "Tennis class",
|
||||
recurringEventId: Buffer.from("tennis-class").toString("base64"),
|
||||
startTime: dayjs().add(2, "day").add(4, "week").toDate(),
|
||||
endTime: dayjs().add(2, "day").add(4, "week").add(60, "minutes").toDate(),
|
||||
status: BookingStatus.PENDING,
|
||||
},
|
||||
{
|
||||
uid: uuid(),
|
||||
title: "Tennis class",
|
||||
recurringEventId: Buffer.from("tennis-class").toString("base64"),
|
||||
startTime: dayjs().add(2, "day").add(8, "week").toDate(),
|
||||
endTime: dayjs().add(2, "day").add(8, "week").add(60, "minutes").toDate(),
|
||||
status: BookingStatus.PENDING,
|
||||
},
|
||||
{
|
||||
uid: uuid(),
|
||||
title: "Tennis class",
|
||||
recurringEventId: Buffer.from("tennis-class").toString("base64"),
|
||||
startTime: dayjs().add(2, "day").add(10, "week").toDate(),
|
||||
endTime: dayjs().add(2, "day").add(10, "week").add(60, "minutes").toDate(),
|
||||
status: BookingStatus.PENDING,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function createAUserWithManyBookings() {
|
||||
const random = Math.random();
|
||||
await createUserAndEventType({
|
||||
user: {
|
||||
email: `pro-${random}@example.com`,
|
||||
name: "Pro Example",
|
||||
password: "1111",
|
||||
username: `pro-${random}`,
|
||||
theme: "light",
|
||||
},
|
||||
eventTypes: [
|
||||
{
|
||||
title: "30min",
|
||||
slug: "30min",
|
||||
length: 30,
|
||||
_numBookings: 100,
|
||||
},
|
||||
{
|
||||
title: "60min",
|
||||
slug: "60min",
|
||||
length: 60,
|
||||
_numBookings: 100,
|
||||
},
|
||||
{
|
||||
title: "Multiple duration",
|
||||
slug: "multiple-duration",
|
||||
length: 75,
|
||||
metadata: {
|
||||
multipleDuration: [30, 75, 90],
|
||||
},
|
||||
_numBookings: 100,
|
||||
},
|
||||
{
|
||||
title: "paid",
|
||||
slug: "paid",
|
||||
length: 60,
|
||||
price: 100,
|
||||
_numBookings: 100,
|
||||
},
|
||||
{
|
||||
title: "Zoom Event",
|
||||
slug: "zoom",
|
||||
length: 60,
|
||||
locations: [{ type: zoomMeta.appData?.location?.type }],
|
||||
_numBookings: 100,
|
||||
},
|
||||
{
|
||||
title: "Daily Event",
|
||||
slug: "daily",
|
||||
length: 60,
|
||||
locations: [{ type: dailyMeta.appData?.location?.type }],
|
||||
_numBookings: 100,
|
||||
},
|
||||
{
|
||||
title: "Google Meet",
|
||||
slug: "google-meet",
|
||||
length: 60,
|
||||
locations: [{ type: googleMeetMeta.appData?.location?.type }],
|
||||
_numBookings: 100,
|
||||
},
|
||||
{
|
||||
title: "Yoga class",
|
||||
slug: "yoga-class",
|
||||
length: 30,
|
||||
_numBookings: 100,
|
||||
},
|
||||
{
|
||||
title: "Tennis class",
|
||||
slug: "tennis-class",
|
||||
length: 60,
|
||||
recurringEvent: { freq: 2, count: 10, interval: 2 },
|
||||
requiresConfirmation: true,
|
||||
_numBookings: 100,
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
// createManyDifferentUsersWithDifferentEventTypesAndBookings({
|
||||
// tillUser: 20000,
|
||||
// startFrom: 10000,
|
||||
// });
|
||||
|
||||
createAUserWithManyBookings();
|
|
@ -0,0 +1,147 @@
|
|||
import type { Prisma, UserPermissionRole } from "@prisma/client";
|
||||
import { uuid } from "short-uuid";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { hashPassword } from "@calcom/features/auth/lib/hashPassword";
|
||||
import { DEFAULT_SCHEDULE, getAvailabilityFromSchedule } from "@calcom/lib/availability";
|
||||
|
||||
import prisma from ".";
|
||||
|
||||
export async function createUserAndEventType({
|
||||
user,
|
||||
eventTypes = [],
|
||||
}: {
|
||||
user: {
|
||||
email: string;
|
||||
password: string;
|
||||
username: string;
|
||||
name: string;
|
||||
completedOnboarding?: boolean;
|
||||
timeZone?: string;
|
||||
role?: UserPermissionRole;
|
||||
theme?: "dark" | "light";
|
||||
};
|
||||
eventTypes?: Array<
|
||||
Prisma.EventTypeUncheckedCreateInput & {
|
||||
_bookings?: Prisma.BookingCreateInput[];
|
||||
_numBookings?: number;
|
||||
}
|
||||
>;
|
||||
}) {
|
||||
const userData = {
|
||||
...user,
|
||||
password: await hashPassword(user.password),
|
||||
emailVerified: new Date(),
|
||||
completedOnboarding: user.completedOnboarding ?? true,
|
||||
locale: "en",
|
||||
schedules:
|
||||
user.completedOnboarding ?? true
|
||||
? {
|
||||
create: {
|
||||
name: "Working Hours",
|
||||
availability: {
|
||||
createMany: {
|
||||
data: getAvailabilityFromSchedule(DEFAULT_SCHEDULE),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
};
|
||||
|
||||
const theUser = await prisma.user.upsert({
|
||||
where: { email_username: { email: user.email, username: user.username } },
|
||||
update: userData,
|
||||
create: userData,
|
||||
});
|
||||
|
||||
console.log(
|
||||
`👤 Upserted '${user.username}' with email "${user.email}" & password "${user.password}". Booking page 👉 ${process.env.NEXT_PUBLIC_WEBAPP_URL}/${user.username}`
|
||||
);
|
||||
|
||||
for (const eventTypeInput of eventTypes) {
|
||||
const { _bookings, _numBookings, ...eventTypeData } = eventTypeInput;
|
||||
let bookingFields;
|
||||
if (_bookings && _numBookings) {
|
||||
throw new Error("You can't set both _bookings and _numBookings");
|
||||
} else if (_numBookings) {
|
||||
bookingFields = [...Array(_numBookings).keys()].map((i) => ({
|
||||
startTime: dayjs()
|
||||
.add(1, "day")
|
||||
.add(i * 5 + 0, "minutes")
|
||||
.toDate(),
|
||||
endTime: dayjs()
|
||||
.add(1, "day")
|
||||
.add(i * 5 + 30, "minutes")
|
||||
.toDate(),
|
||||
title: `${eventTypeInput.title}:${i + 1}`,
|
||||
uid: uuid(),
|
||||
}));
|
||||
} else {
|
||||
bookingFields = _bookings || [];
|
||||
}
|
||||
eventTypeData.userId = theUser.id;
|
||||
eventTypeData.users = { connect: { id: theUser.id } };
|
||||
|
||||
const eventType = await prisma.eventType.findFirst({
|
||||
where: {
|
||||
slug: eventTypeData.slug,
|
||||
users: {
|
||||
some: {
|
||||
id: eventTypeData.userId,
|
||||
},
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (eventType) {
|
||||
console.log(
|
||||
`\t📆 Event type ${eventTypeData.slug} already seems seeded - ${process.env.NEXT_PUBLIC_WEBAPP_URL}/${user.username}/${eventTypeData.slug}`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
const { id } = await prisma.eventType.create({
|
||||
data: eventTypeData,
|
||||
});
|
||||
|
||||
console.log(
|
||||
`\t📆 Event type ${eventTypeData.slug} with id ${id}, length ${eventTypeData.length}min - ${process.env.NEXT_PUBLIC_WEBAPP_URL}/${user.username}/${eventTypeData.slug}`
|
||||
);
|
||||
|
||||
for (const bookingInput of bookingFields) {
|
||||
await prisma.booking.create({
|
||||
data: {
|
||||
...bookingInput,
|
||||
user: {
|
||||
connect: {
|
||||
email: user.email,
|
||||
},
|
||||
},
|
||||
attendees: {
|
||||
create: {
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
timeZone: "Europe/London",
|
||||
},
|
||||
},
|
||||
eventType: {
|
||||
connect: {
|
||||
id,
|
||||
},
|
||||
},
|
||||
status: bookingInput.status,
|
||||
},
|
||||
});
|
||||
console.log(
|
||||
`\t\t☎️ Created booking ${bookingInput.title} at ${new Date(
|
||||
bookingInput.startTime
|
||||
).toLocaleDateString()}`
|
||||
);
|
||||
}
|
||||
}
|
||||
console.log("👤 User with it's event-types and bookings created", theUser.email);
|
||||
return theUser;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import type { Prisma, UserPermissionRole } from "@prisma/client";
|
||||
import type { Prisma } from "@prisma/client";
|
||||
import { uuid } from "short-uuid";
|
||||
import type z from "zod";
|
||||
|
||||
|
@ -6,132 +6,13 @@ import dailyMeta from "@calcom/app-store/dailyvideo/_metadata";
|
|||
import googleMeetMeta from "@calcom/app-store/googlevideo/_metadata";
|
||||
import zoomMeta from "@calcom/app-store/zoomvideo/_metadata";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { hashPassword } from "@calcom/features/auth/lib/hashPassword";
|
||||
import { DEFAULT_SCHEDULE, getAvailabilityFromSchedule } from "@calcom/lib/availability";
|
||||
import { BookingStatus, MembershipRole } from "@calcom/prisma/enums";
|
||||
|
||||
import prisma from ".";
|
||||
import mainAppStore from "./seed-app-store";
|
||||
import { createUserAndEventType } from "./seed-utils";
|
||||
import type { teamMetadataSchema } from "./zod-utils";
|
||||
|
||||
async function createUserAndEventType({
|
||||
user,
|
||||
eventTypes = [],
|
||||
}: {
|
||||
user: {
|
||||
email: string;
|
||||
password: string;
|
||||
username: string;
|
||||
name: string;
|
||||
completedOnboarding?: boolean;
|
||||
timeZone?: string;
|
||||
role?: UserPermissionRole;
|
||||
theme?: "dark" | "light";
|
||||
};
|
||||
eventTypes?: Array<
|
||||
Prisma.EventTypeUncheckedCreateInput & {
|
||||
_bookings?: Prisma.BookingCreateInput[];
|
||||
}
|
||||
>;
|
||||
}) {
|
||||
const userData = {
|
||||
...user,
|
||||
password: await hashPassword(user.password),
|
||||
emailVerified: new Date(),
|
||||
completedOnboarding: user.completedOnboarding ?? true,
|
||||
locale: "en",
|
||||
schedules:
|
||||
user.completedOnboarding ?? true
|
||||
? {
|
||||
create: {
|
||||
name: "Working Hours",
|
||||
availability: {
|
||||
createMany: {
|
||||
data: getAvailabilityFromSchedule(DEFAULT_SCHEDULE),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
};
|
||||
|
||||
const theUser = await prisma.user.upsert({
|
||||
where: { email_username: { email: user.email, username: user.username } },
|
||||
update: userData,
|
||||
create: userData,
|
||||
});
|
||||
|
||||
console.log(
|
||||
`👤 Upserted '${user.username}' with email "${user.email}" & password "${user.password}". Booking page 👉 ${process.env.NEXT_PUBLIC_WEBAPP_URL}/${user.username}`
|
||||
);
|
||||
|
||||
for (const eventTypeInput of eventTypes) {
|
||||
const { _bookings: bookingFields = [], ...eventTypeData } = eventTypeInput;
|
||||
eventTypeData.userId = theUser.id;
|
||||
eventTypeData.users = { connect: { id: theUser.id } };
|
||||
|
||||
const eventType = await prisma.eventType.findFirst({
|
||||
where: {
|
||||
slug: eventTypeData.slug,
|
||||
users: {
|
||||
some: {
|
||||
id: eventTypeData.userId,
|
||||
},
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (eventType) {
|
||||
console.log(
|
||||
`\t📆 Event type ${eventTypeData.slug} already seems seeded - ${process.env.NEXT_PUBLIC_WEBAPP_URL}/${user.username}/${eventTypeData.slug}`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
const { id } = await prisma.eventType.create({
|
||||
data: eventTypeData,
|
||||
});
|
||||
|
||||
console.log(
|
||||
`\t📆 Event type ${eventTypeData.slug} with id ${id}, length ${eventTypeData.length}min - ${process.env.NEXT_PUBLIC_WEBAPP_URL}/${user.username}/${eventTypeData.slug}`
|
||||
);
|
||||
for (const bookingInput of bookingFields) {
|
||||
await prisma.booking.create({
|
||||
data: {
|
||||
...bookingInput,
|
||||
user: {
|
||||
connect: {
|
||||
email: user.email,
|
||||
},
|
||||
},
|
||||
attendees: {
|
||||
create: {
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
timeZone: "Europe/London",
|
||||
},
|
||||
},
|
||||
eventType: {
|
||||
connect: {
|
||||
id,
|
||||
},
|
||||
},
|
||||
status: bookingInput.status,
|
||||
},
|
||||
});
|
||||
console.log(
|
||||
`\t\t☎️ Created booking ${bookingInput.title} at ${new Date(
|
||||
bookingInput.startTime
|
||||
).toLocaleDateString()}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return theUser;
|
||||
}
|
||||
|
||||
async function createTeamAndAddUsers(
|
||||
teamInput: Prisma.TeamCreateInput,
|
||||
users: { id: number; username: string; role?: MembershipRole }[] = []
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import type { Session } from "next-auth";
|
||||
|
||||
import { WEBAPP_URL } from "@calcom/lib/constants";
|
||||
import logger from "@calcom/lib/logger";
|
||||
import { MembershipRole } from "@calcom/prisma/enums";
|
||||
import { teamMetadataSchema, userMetadata } from "@calcom/prisma/zod-utils";
|
||||
|
||||
|
@ -131,17 +132,25 @@ const getUserSession = async (ctx: TRPCContextInner) => {
|
|||
|
||||
return { user, session };
|
||||
};
|
||||
const sessionMiddleware = middleware(async ({ ctx, next }) => {
|
||||
const { user, session } = await getUserSession(ctx);
|
||||
|
||||
const sessionMiddleware = middleware(async ({ ctx, next }) => {
|
||||
const middlewareStart = performance.now();
|
||||
const { user, session } = await getUserSession(ctx);
|
||||
const middlewareEnd = performance.now();
|
||||
logger.debug("Perf:t.sessionMiddleware", middlewareEnd - middlewareStart);
|
||||
return next({
|
||||
ctx: { user, session },
|
||||
});
|
||||
});
|
||||
|
||||
export const isAuthed = middleware(async ({ ctx, next }) => {
|
||||
const middlewareStart = performance.now();
|
||||
|
||||
const { user, session } = await getUserSession(ctx);
|
||||
|
||||
const middlewareEnd = performance.now();
|
||||
logger.debug("Perf:t.isAuthed", middlewareEnd - middlewareStart);
|
||||
|
||||
if (!user || !session) {
|
||||
throw new TRPCError({ code: "UNAUTHORIZED" });
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { type PrismaClient } from "@prisma/client";
|
||||
|
||||
import { isOrganization, withRoleCanCreateEntity } from "@calcom/lib/entityPermissionUtils";
|
||||
import { getBookerUrl } from "@calcom/lib/server/getBookerUrl";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
|
||||
|
||||
import { TRPCError } from "@trpc/server";
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import type { PrismaClient } from "@prisma/client";
|
||||
|
||||
import { getPublicEvent } from "@calcom/features/eventtypes/lib/getPublicEvent";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
|
||||
import type { TEventInputSchema } from "./event.schema";
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import type { PrismaClient } from "@prisma/client";
|
||||
|
||||
import { samlTenantProduct } from "@calcom/features/ee/sso/lib/saml";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
|
||||
import type { TSamlTenantProductInputSchema } from "./samlTenantProduct.schema";
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import type { Prisma, PrismaClient } from "@prisma/client";
|
||||
import type { Prisma } from "@prisma/client";
|
||||
|
||||
import { appKeysSchemas } from "@calcom/app-store/apps.keys-schemas.generated";
|
||||
import { getLocalAppMetadata } from "@calcom/app-store/utils";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import { AppCategories } from "@calcom/prisma/enums";
|
||||
|
||||
import type { TrpcSessionUser } from "../../../trpc";
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import type { Prisma } from "@prisma/client";
|
||||
import type { PrismaClient } from "@prisma/client";
|
||||
|
||||
import { appKeysSchemas } from "@calcom/app-store/apps.keys-schemas.generated";
|
||||
import { getLocalAppMetadata } from "@calcom/app-store/utils";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import type { AppCategories } from "@calcom/prisma/enums";
|
||||
|
||||
// import prisma from "@calcom/prisma";
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import type { PrismaClient } from "@prisma/client";
|
||||
|
||||
import { getLocalAppMetadata } from "@calcom/app-store/utils";
|
||||
import { sendDisabledAppEmail } from "@calcom/emails";
|
||||
import { getTranslation } from "@calcom/lib/server";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import { AppCategories } from "@calcom/prisma/enums";
|
||||
|
||||
import { TRPCError } from "@trpc/server";
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import type { Availability as AvailabilityModel, Schedule as ScheduleModel, User } from "@prisma/client";
|
||||
|
||||
import type { PrismaClient } from "@calcom/prisma/client";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import type { Schedule } from "@calcom/types/schedule";
|
||||
|
||||
export const getDefaultScheduleId = async (userId: number, prisma: PrismaClient) => {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { parseRecurringEvent } from "@calcom/lib";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import { bookingMinimalSelect } from "@calcom/prisma";
|
||||
import type { Prisma, PrismaClient } from "@calcom/prisma/client";
|
||||
import type { Prisma } from "@calcom/prisma/client";
|
||||
import { BookingStatus } from "@calcom/prisma/enums";
|
||||
import { EventTypeMetaDataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
|
@ -72,6 +73,62 @@ export const getHandler = async ({ ctx, input }: GetOptions) => {
|
|||
unconfirmed: { startTime: "asc" },
|
||||
};
|
||||
|
||||
const passedBookingsStatusFilter = bookingListingFilters[bookingListingByStatus];
|
||||
const orderBy = bookingListingOrderby[bookingListingByStatus];
|
||||
|
||||
const { bookings, recurringInfo } = await getBookings({
|
||||
user,
|
||||
prisma,
|
||||
passedBookingsStatusFilter,
|
||||
filters: input.filters,
|
||||
orderBy,
|
||||
take,
|
||||
skip,
|
||||
});
|
||||
|
||||
const bookingsFetched = bookings.length;
|
||||
let nextCursor: typeof skip | null = skip;
|
||||
if (bookingsFetched > take) {
|
||||
nextCursor += bookingsFetched;
|
||||
} else {
|
||||
nextCursor = null;
|
||||
}
|
||||
|
||||
return {
|
||||
bookings,
|
||||
recurringInfo,
|
||||
nextCursor,
|
||||
};
|
||||
};
|
||||
|
||||
const set = new Set();
|
||||
const getUniqueBookings = <T extends { uid: string }>(arr: T[]) => {
|
||||
const unique = arr.filter((booking) => {
|
||||
const duplicate = set.has(booking.uid);
|
||||
set.add(booking.uid);
|
||||
return !duplicate;
|
||||
});
|
||||
set.clear();
|
||||
return unique;
|
||||
};
|
||||
|
||||
async function getBookings({
|
||||
user,
|
||||
prisma,
|
||||
passedBookingsStatusFilter,
|
||||
filters,
|
||||
orderBy,
|
||||
take,
|
||||
skip,
|
||||
}: {
|
||||
user: { id: number; email: string };
|
||||
filters: TGetInputSchema["filters"];
|
||||
prisma: PrismaClient;
|
||||
passedBookingsStatusFilter: Prisma.BookingWhereInput;
|
||||
orderBy: Prisma.BookingOrderByWithAggregationInput;
|
||||
take: number;
|
||||
skip: number;
|
||||
}) {
|
||||
// TODO: Fix record typing
|
||||
const bookingWhereInputFilters: Record<string, Prisma.BookingWhereInput> = {
|
||||
teamIds: {
|
||||
|
@ -80,7 +137,7 @@ export const getHandler = async ({ ctx, input }: GetOptions) => {
|
|||
eventType: {
|
||||
team: {
|
||||
id: {
|
||||
in: input.filters?.teamIds,
|
||||
in: filters?.teamIds,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -94,7 +151,7 @@ export const getHandler = async ({ ctx, input }: GetOptions) => {
|
|||
users: {
|
||||
some: {
|
||||
id: {
|
||||
in: input.filters?.userIds,
|
||||
in: filters?.userIds,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -106,7 +163,7 @@ export const getHandler = async ({ ctx, input }: GetOptions) => {
|
|||
AND: [
|
||||
{
|
||||
eventTypeId: {
|
||||
in: input.filters?.eventTypeIds,
|
||||
in: filters?.eventTypeIds,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
@ -114,55 +171,12 @@ export const getHandler = async ({ ctx, input }: GetOptions) => {
|
|||
};
|
||||
|
||||
const filtersCombined: Prisma.BookingWhereInput[] =
|
||||
input.filters &&
|
||||
Object.keys(input.filters).map((key) => {
|
||||
filters &&
|
||||
Object.keys(filters).map((key) => {
|
||||
return bookingWhereInputFilters[key];
|
||||
});
|
||||
|
||||
const passedBookingsStatusFilter = bookingListingFilters[bookingListingByStatus];
|
||||
const orderBy = bookingListingOrderby[bookingListingByStatus];
|
||||
|
||||
const [bookingsQuery, recurringInfoBasic, recurringInfoExtended] = await Promise.all([
|
||||
prisma.booking.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
userId: user.id,
|
||||
},
|
||||
{
|
||||
attendees: {
|
||||
some: {
|
||||
email: user.email,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
eventType: {
|
||||
team: {
|
||||
members: {
|
||||
some: {
|
||||
userId: user.id,
|
||||
role: {
|
||||
in: ["ADMIN", "OWNER"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
seatsReferences: {
|
||||
some: {
|
||||
attendee: {
|
||||
email: user.email,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
AND: [passedBookingsStatusFilter, ...(filtersCombined ?? [])],
|
||||
},
|
||||
select: {
|
||||
const bookingSelect = {
|
||||
...bookingMinimalSelect,
|
||||
uid: true,
|
||||
recurringEventId: true,
|
||||
|
@ -220,6 +234,89 @@ export const getHandler = async ({ ctx, input }: GetOptions) => {
|
|||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const [
|
||||
// Quering these in parallel to save time.
|
||||
// Note that because we are applying `take` to individual queries, we will usually get more bookings then we need. It is okay to have more bookings faster than having what we need slower
|
||||
bookingsQueryUserId,
|
||||
bookingsQueryAttendees,
|
||||
bookingsQueryTeamMember,
|
||||
bookingsQuerySeatReference,
|
||||
//////////////////////////
|
||||
|
||||
recurringInfoBasic,
|
||||
recurringInfoExtended,
|
||||
// We need all promises to be successful, so we are not using Promise.allSettled
|
||||
] = await Promise.all([
|
||||
prisma.booking.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
userId: user.id,
|
||||
},
|
||||
],
|
||||
AND: [passedBookingsStatusFilter, ...(filtersCombined ?? [])],
|
||||
},
|
||||
orderBy,
|
||||
take: take + 1,
|
||||
skip,
|
||||
}),
|
||||
prisma.booking.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
attendees: {
|
||||
some: {
|
||||
email: user.email,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
AND: [passedBookingsStatusFilter, ...(filtersCombined ?? [])],
|
||||
},
|
||||
orderBy,
|
||||
take: take + 1,
|
||||
skip,
|
||||
}),
|
||||
prisma.booking.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
eventType: {
|
||||
team: {
|
||||
members: {
|
||||
some: {
|
||||
userId: user.id,
|
||||
role: {
|
||||
in: ["ADMIN", "OWNER"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
AND: [passedBookingsStatusFilter, ...(filtersCombined ?? [])],
|
||||
},
|
||||
orderBy,
|
||||
take: take + 1,
|
||||
skip,
|
||||
}),
|
||||
prisma.booking.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
seatsReferences: {
|
||||
some: {
|
||||
attendee: {
|
||||
email: user.email,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
AND: [passedBookingsStatusFilter, ...(filtersCombined ?? [])],
|
||||
},
|
||||
orderBy,
|
||||
take: take + 1,
|
||||
|
@ -285,7 +382,25 @@ export const getHandler = async ({ ctx, input }: GetOptions) => {
|
|||
}
|
||||
);
|
||||
|
||||
const bookings = bookingsQuery.map((booking) => {
|
||||
const plainBookings = getUniqueBookings(
|
||||
bookingsQueryUserId
|
||||
.concat(bookingsQueryAttendees)
|
||||
.concat(bookingsQueryTeamMember)
|
||||
.concat(bookingsQuerySeatReference)
|
||||
);
|
||||
|
||||
// Now enrich bookings with relation data. We could have queried the relation data along with the bookings, but that would cause unnecessary queries to the database.
|
||||
// Because Prisma is also going to query the select relation data sequentially, we are fine querying it separately here as it would be just 1 query instead of 4
|
||||
const bookings = (
|
||||
await prisma.booking.findMany({
|
||||
where: {
|
||||
id: {
|
||||
in: plainBookings.map((booking) => booking.id),
|
||||
},
|
||||
},
|
||||
select: bookingSelect,
|
||||
})
|
||||
).map((booking) => {
|
||||
// If seats are enabled and the event is not set to show attendees, filter out attendees that are not the current user
|
||||
if (booking.seatsReferences.length && !booking.eventType?.seatsShowAttendees) {
|
||||
booking.attendees = booking.attendees.filter((attendee) => attendee.email === user.email);
|
||||
|
@ -303,18 +418,5 @@ export const getHandler = async ({ ctx, input }: GetOptions) => {
|
|||
endTime: booking.endTime.toISOString(),
|
||||
};
|
||||
});
|
||||
|
||||
const bookingsFetched = bookings.length;
|
||||
let nextCursor: typeof skip | null = skip;
|
||||
if (bookingsFetched > take) {
|
||||
nextCursor += bookingsFetched;
|
||||
} else {
|
||||
nextCursor = null;
|
||||
return { bookings, recurringInfo };
|
||||
}
|
||||
|
||||
return {
|
||||
bookings,
|
||||
recurringInfo,
|
||||
nextCursor,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@ import getAppKeysFromSlug from "@calcom/app-store/_utils/getAppKeysFromSlug";
|
|||
import { DailyLocationType } from "@calcom/app-store/locations";
|
||||
import getApps from "@calcom/app-store/utils";
|
||||
import { getUsersCredentials } from "@calcom/lib/server/getUsersCredentials";
|
||||
import type { PrismaClient } from "@calcom/prisma/client";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import { SchedulingType } from "@calcom/prisma/enums";
|
||||
import { userMetadata as userMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import type { PrismaClient } from "@prisma/client";
|
||||
|
||||
import getEventTypeById from "@calcom/lib/getEventTypeById";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
|
||||
import type { TrpcSessionUser } from "../../../trpc";
|
||||
import type { TGetInputSchema } from "./get.schema";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { type PrismaClient, Prisma } from "@prisma/client";
|
||||
import { Prisma } from "@prisma/client";
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { orderBy } from "lodash";
|
||||
|
||||
|
@ -7,6 +7,7 @@ import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowE
|
|||
import { CAL_URL } from "@calcom/lib/constants";
|
||||
import { markdownToSafeHTML } from "@calcom/lib/markdownToSafeHTML";
|
||||
import { getBookerUrl } from "@calcom/lib/server/getBookerUrl";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import { baseEventTypeSelect } from "@calcom/prisma";
|
||||
import { MembershipRole, SchedulingType } from "@calcom/prisma/enums";
|
||||
import { teamMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import type { PrismaClient } from "@prisma/client";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import type { NextApiResponse, GetServerSidePropsContext } from "next";
|
||||
|
||||
|
@ -8,6 +7,7 @@ import { validateIntervalLimitOrder } from "@calcom/lib";
|
|||
import logger from "@calcom/lib/logger";
|
||||
import { getTranslation } from "@calcom/lib/server";
|
||||
import { validateBookerLayouts } from "@calcom/lib/validateBookerLayouts";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import { WorkflowActions, WorkflowTriggerEvents } from "@calcom/prisma/client";
|
||||
import { SchedulingType } from "@calcom/prisma/enums";
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { PrismaClient } from "@calcom/prisma/client";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import { teamMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import appStore from "@calcom/app-store";
|
|||
import dayjs from "@calcom/dayjs";
|
||||
import { sendNoShowFeeChargedEmail } from "@calcom/emails";
|
||||
import { getTranslation } from "@calcom/lib/server/i18n";
|
||||
import type { PrismaClient } from "@calcom/prisma/client";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import type { CalendarEvent } from "@calcom/types/Calendar";
|
||||
import type { IAbstractPaymentService, PaymentApp } from "@calcom/types/PaymentService";
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ import { v4 as uuid } from "uuid";
|
|||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { MINUTES_TO_BOOK } from "@calcom/lib/constants";
|
||||
import type { PrismaClient } from "@calcom/prisma/client";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
|
||||
import { TRPCError } from "@trpc/server";
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import type { PrismaClient } from "@prisma/client";
|
||||
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
|
||||
|
||||
import type { TListMembersInputSchema } from "./listMembers.schema";
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import type { PrismaClient } from "@prisma/client";
|
||||
|
||||
import { updateQuantitySubscriptionFromStripe } from "@calcom/features/ee/teams/lib/payments";
|
||||
import { IS_TEAM_BILLING_ENABLED } from "@calcom/lib/constants";
|
||||
import { isTeamAdmin, isTeamOwner } from "@calcom/lib/server/queries/teams";
|
||||
import { closeComDeleteTeamMembership } from "@calcom/lib/sync/SyncServiceManager";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
|
||||
|
||||
import { TRPCError } from "@trpc/server";
|
||||
|
|
|
@ -3,8 +3,8 @@ import type { Workflow } from "@prisma/client";
|
|||
import emailReminderTemplate from "@calcom/ee/workflows/lib/reminders/templates/emailReminderTemplate";
|
||||
import { SENDER_NAME } from "@calcom/lib/constants";
|
||||
import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import { prisma } from "@calcom/prisma";
|
||||
import type { PrismaClient } from "@calcom/prisma/client";
|
||||
import {
|
||||
MembershipRole,
|
||||
TimeUnit,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import type { WorkflowType } from "@calcom/ee/workflows/components/WorkflowListPage";
|
||||
import { hasFilter } from "@calcom/features/filters/lib/hasFilter";
|
||||
import type { Prisma, PrismaClient } from "@calcom/prisma/client";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import type { Prisma } from "@calcom/prisma/client";
|
||||
import { MembershipRole } from "@calcom/prisma/client";
|
||||
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ import {
|
|||
import { IS_SELF_HOSTED, SENDER_ID, SENDER_NAME } from "@calcom/lib/constants";
|
||||
import hasKeyInMetadata from "@calcom/lib/hasKeyInMetadata";
|
||||
import { getTimeFormatStringFromUserTimeFormat } from "@calcom/lib/timeFormat";
|
||||
import type { PrismaClient } from "@calcom/prisma/client";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import { BookingStatus, WorkflowActions, WorkflowMethods, WorkflowTriggerEvents } from "@calcom/prisma/enums";
|
||||
import type { TrpcSessionUser } from "@calcom/trpc/server/trpc";
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import {
|
|||
} from "@calcom/features/bookings/lib/getBookingFields";
|
||||
import { removeBookingField, upsertBookingField } from "@calcom/features/eventtypes/lib/bookingFieldsManager";
|
||||
import { SENDER_ID, SENDER_NAME } from "@calcom/lib/constants";
|
||||
import type PrismaType from "@calcom/prisma";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import type { WorkflowStep } from "@calcom/prisma/client";
|
||||
import { MembershipRole } from "@calcom/prisma/enums";
|
||||
|
||||
|
@ -20,7 +20,7 @@ export function getSender(
|
|||
|
||||
export async function isAuthorized(
|
||||
workflow: Pick<Workflow, "id" | "teamId" | "userId"> | null,
|
||||
prisma: typeof PrismaType,
|
||||
prisma: PrismaClient,
|
||||
currentUserId: number,
|
||||
readOnly?: boolean
|
||||
) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { IncomingMessage } from "http";
|
||||
import type { Session } from "next-auth";
|
||||
|
||||
import type { PrismaClient } from "@calcom/prisma/client";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
|
||||
import "./next-auth";
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import type { PrismaClient } from "@prisma/client";
|
||||
import { beforeEach, vi } from "vitest";
|
||||
import { mockDeep, mockReset } from "vitest-mock-extended";
|
||||
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
|
||||
vi.mock("@calcom/prisma", () => ({
|
||||
default: prisma,
|
||||
availabilityUserSelect: vi.fn(),
|
||||
|
|
Loading…
Reference in New Issue
Block a user