From a37f1d9798c98ce741070b70396876e56837b792 Mon Sep 17 00:00:00 2001 From: Benny Joo Date: Mon, 23 Jun 2025 18:01:06 -0400 Subject: [PATCH] perf: Refactor `getPublicEvent` to fetch org data using DB index key (#21850) * wip * fix * fix naming * fix typecheck --- .../services/event-types-atom.service.ts | 5 +- .../d/[link]/[slug]/getServerSideProps.tsx | 9 +- .../team/[slug]/[type]/getServerSideProps.ts | 7 +- .../lib/[user]/[type]/getServerSideProps.ts | 13 +-- .../features/bookings/Booker/utils/event.ts | 4 +- .../features/eventtypes/lib/getPublicEvent.ts | 83 ++++++++++++------- packages/lib/server/repository/event.ts | 6 +- .../routers/publicViewer/event.schema.ts | 3 +- 8 files changed, 79 insertions(+), 51 deletions(-) diff --git a/apps/api/v2/src/modules/atoms/services/event-types-atom.service.ts b/apps/api/v2/src/modules/atoms/services/event-types-atom.service.ts index d5613afabd..c2fcf060a5 100644 --- a/apps/api/v2/src/modules/atoms/services/event-types-atom.service.ts +++ b/apps/api/v2/src/modules/atoms/services/event-types-atom.service.ts @@ -424,7 +424,10 @@ export class EventTypesAtomService { isTeamEvent, orgSlug, this.dbRead.prisma as unknown as PrismaClient, - true + true, + undefined, + false, + orgId ); if (!event) { diff --git a/apps/web/lib/d/[link]/[slug]/getServerSideProps.tsx b/apps/web/lib/d/[link]/[slug]/getServerSideProps.tsx index 9d0d01a2cb..8b6617905c 100644 --- a/apps/web/lib/d/[link]/[slug]/getServerSideProps.tsx +++ b/apps/web/lib/d/[link]/[slug]/getServerSideProps.tsx @@ -23,7 +23,7 @@ async function getUserPageProps(context: GetServerSidePropsContext) { const { link, slug } = paramsSchema.parse(context.params); const { rescheduleUid, duration: queryDuration } = context.query; const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig(context.req); - const org = isValidOrgDomain ? currentOrgDomain : null; + const orgSlug = isValidOrgDomain ? currentOrgDomain : null; const hashedLink = await prisma.hashedLink.findUnique({ where: { @@ -86,7 +86,7 @@ async function getUserPageProps(context: GetServerSidePropsContext) { return notFound; } - if (!org) { + if (!orgSlug) { const redirect = await getTemporaryOrgRedirect({ slugs: [username], redirectType: RedirectType.User, @@ -103,7 +103,7 @@ async function getUserPageProps(context: GetServerSidePropsContext) { const [user] = await UserRepository.findUsersByUsername({ usernameList: [name], - orgSlug: org, + orgSlug: orgSlug, }); if (!user) { @@ -128,8 +128,9 @@ async function getUserPageProps(context: GetServerSidePropsContext) { username: name, eventSlug: slug, isTeamEvent, - org, + orgSlug, fromRedirectOfNonOrgLink: context.query.orgRedirection === "true", + orgId: session?.user?.org?.id ?? session?.user?.profile?.organizationId ?? undefined, }, session?.user?.id ); diff --git a/apps/web/lib/org/[orgSlug]/instant-meeting/team/[slug]/[type]/getServerSideProps.ts b/apps/web/lib/org/[orgSlug]/instant-meeting/team/[slug]/[type]/getServerSideProps.ts index a7d8c256aa..6e573f7a3b 100644 --- a/apps/web/lib/org/[orgSlug]/instant-meeting/team/[slug]/[type]/getServerSideProps.ts +++ b/apps/web/lib/org/[orgSlug]/instant-meeting/team/[slug]/[type]/getServerSideProps.ts @@ -43,8 +43,8 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) => } as const; } - const org = isValidOrgDomain ? currentOrgDomain : null; - if (!org) { + const orgSlug = isValidOrgDomain ? currentOrgDomain : null; + if (!orgSlug) { return { notFound: true, } as const; @@ -55,8 +55,9 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) => username: teamSlug, eventSlug: meetingSlug, isTeamEvent: true, - org, + orgSlug, fromRedirectOfNonOrgLink: context.query.orgRedirection === "true", + orgId: session?.user?.org?.id ?? session?.user?.profile?.organizationId ?? undefined, }, session?.user?.id ); diff --git a/apps/web/server/lib/[user]/[type]/getServerSideProps.ts b/apps/web/server/lib/[user]/[type]/getServerSideProps.ts index 12400d547d..65b301cd89 100644 --- a/apps/web/server/lib/[user]/[type]/getServerSideProps.ts +++ b/apps/web/server/lib/[user]/[type]/getServerSideProps.ts @@ -121,8 +121,8 @@ async function getDynamicGroupPageProps(context: GetServerSidePropsContext) { const { rescheduleUid, bookingUid } = context.query; const allowRescheduleForCancelledBooking = context.query.allowRescheduleForCancelledBooking === "true"; const { currentOrgDomain, isValidOrgDomain } = orgDomainConfig(context.req, context.params?.orgSlug); - const org = isValidOrgDomain ? currentOrgDomain : null; - if (!org) { + const orgSlug = isValidOrgDomain ? currentOrgDomain : null; + if (!orgSlug) { const redirect = await getTemporaryOrgRedirect({ slugs: usernames, redirectType: RedirectType.User, @@ -155,8 +155,9 @@ async function getDynamicGroupPageProps(context: GetServerSidePropsContext) { { username: usernames.join("+"), eventSlug: slug, - org, + orgSlug, fromRedirectOfNonOrgLink: context.query.orgRedirection === "true", + orgId: session?.user?.org?.id ?? session?.user?.profile?.organizationId ?? undefined, }, session?.user?.id ); @@ -241,7 +242,7 @@ async function getUserPageProps(context: GetServerSidePropsContext) { } as const; } - const org = isValidOrgDomain ? currentOrgDomain : null; + const orgSlug = isValidOrgDomain ? currentOrgDomain : null; // We use this to both prefetch the query on the server, // as well as to check if the event exist, so we can show a 404 otherwise. @@ -249,7 +250,7 @@ async function getUserPageProps(context: GetServerSidePropsContext) { { username, eventSlug: slug, - org, + orgSlug, fromRedirectOfNonOrgLink: context.query.orgRedirection === "true", }, session?.user?.id @@ -261,7 +262,7 @@ async function getUserPageProps(context: GetServerSidePropsContext) { } as const; } - const allowSEOIndexing = org + const allowSEOIndexing = orgSlug ? user?.profile?.organization?.organizationSettings?.allowSEOIndexing ? user?.allowSEOIndexing : false diff --git a/packages/features/bookings/Booker/utils/event.ts b/packages/features/bookings/Booker/utils/event.ts index 5a69e6926e..60c4260811 100644 --- a/packages/features/bookings/Booker/utils/event.ts +++ b/packages/features/bookings/Booker/utils/event.ts @@ -19,7 +19,7 @@ export type useScheduleForEventReturnType = ReturnType { - const [username, eventSlug, isTeamEvent, org] = useBookerStore( + const [username, eventSlug, isTeamEvent, orgSlug] = useBookerStore( (state) => [state.username, state.eventSlug, state.isTeamEvent, state.org], shallow ); @@ -29,7 +29,7 @@ export const useEvent = (props?: { fromRedirectOfNonOrgLink?: boolean; disabled? username: username ?? "", eventSlug: eventSlug ?? "", isTeamEvent, - org: org ?? null, + orgSlug: orgSlug ?? null, fromRedirectOfNonOrgLink: props?.fromRedirectOfNonOrgLink, }, { diff --git a/packages/features/eventtypes/lib/getPublicEvent.ts b/packages/features/eventtypes/lib/getPublicEvent.ts index 7bb8ad760b..3c17dcf2ff 100644 --- a/packages/features/eventtypes/lib/getPublicEvent.ts +++ b/packages/features/eventtypes/lib/getPublicEvent.ts @@ -227,19 +227,20 @@ export const getPublicEvent = async ( username: string, eventSlug: string, isTeamEvent: boolean | undefined, - org: string | null, + orgSlug: string | null, prisma: PrismaClient, fromRedirectOfNonOrgLink: boolean, currentUserId?: number, - fetchAllUsers = false + fetchAllUsers = false, + orgId?: number ) => { const usernameList = getUsernameList(username); - const orgQuery = org ? getSlugOrRequestedSlug(org) : null; + const orgQuery = orgSlug ? getSlugOrRequestedSlug(orgSlug) : null; // In case of dynamic group event, we fetch user's data and use the default event. if (usernameList.length > 1) { const usersInOrgContext = await UserRepository.findUsersByUsername({ usernameList, - orgSlug: org, + orgSlug: orgSlug, }); const users = usersInOrgContext; @@ -267,18 +268,27 @@ export const getPublicEvent = async ( const disableBookingTitle = !defaultEvent.isDynamic; const unPublishedOrgUser = users.find((user) => user.profile?.organization?.slug === null); - let orgDetails: Pick | undefined; - if (org) { - orgDetails = await prisma.team.findFirstOrThrow({ - where: { - slug: org, - }, - select: { - logoUrl: true, - name: true, - }, - }); - } + const orgDetails: Pick | undefined = orgId + ? await prisma.team.findUniqueOrThrow({ + where: { + id: orgId, + }, + select: { + logoUrl: true, + name: true, + }, + }) + : orgSlug + ? await prisma.team.findFirstOrThrow({ + where: { + slug: orgSlug, + }, + select: { + logoUrl: true, + name: true, + }, + }) + : undefined; return { ...defaultEvent, @@ -309,14 +319,14 @@ export const getPublicEvent = async ( ? { image: getPlaceholderAvatar(orgDetails?.logoUrl, orgDetails?.name), name: orgDetails?.name, - username: org, + username: orgSlug, } : {}), }, entity: { considerUnpublished: !fromRedirectOfNonOrgLink && unPublishedOrgUser !== undefined, fromRedirectOfNonOrgLink, - orgSlug: org, + orgSlug: orgSlug, name: unPublishedOrgUser?.profile?.organization?.name ?? null, teamSlug: null, logoUrl: null, @@ -437,19 +447,28 @@ export const getPublicEvent = async ( eventWithUserProfiles.schedule = eventOwnerDefaultSchedule; } - let orgDetails: Pick | undefined | null; - if (org) { - orgDetails = await prisma.team.findFirst({ - where: { - slug: org, - parentId: null, - }, - select: { - logoUrl: true, - name: true, - }, - }); - } + const orgDetails: Pick | undefined | null = orgId + ? await prisma.team.findUnique({ + where: { + id: orgId, + }, + select: { + logoUrl: true, + name: true, + }, + }) + : orgSlug + ? await prisma.team.findFirst({ + where: { + slug: orgSlug, + parentId: null, + }, + select: { + logoUrl: true, + name: true, + }, + }) + : undefined; let showInstantEventConnectNowModal = eventWithUserProfiles.isInstantEvent; @@ -507,7 +526,7 @@ export const getPublicEvent = async ( (eventWithUserProfiles.team?.slug === null || eventWithUserProfiles.owner?.profile?.organization?.slug === null || eventWithUserProfiles.team?.parent?.slug === null), - orgSlug: org, + orgSlug: orgSlug, teamSlug: (eventWithUserProfiles.team?.slug || teamMetadata?.requestedSlug) ?? null, name: (eventWithUserProfiles.owner?.profile?.organization?.name || diff --git a/packages/lib/server/repository/event.ts b/packages/lib/server/repository/event.ts index e1d2fa2223..59e7bc7633 100644 --- a/packages/lib/server/repository/event.ts +++ b/packages/lib/server/repository/event.ts @@ -8,10 +8,12 @@ export class EventRepository { input.username, input.eventSlug, input.isTeamEvent, - input.org, + input.orgSlug, prisma, input.fromRedirectOfNonOrgLink, - userId + userId, + false, + input.orgId ); return event; } diff --git a/packages/trpc/server/routers/publicViewer/event.schema.ts b/packages/trpc/server/routers/publicViewer/event.schema.ts index d10a5965cc..20befc3716 100644 --- a/packages/trpc/server/routers/publicViewer/event.schema.ts +++ b/packages/trpc/server/routers/publicViewer/event.schema.ts @@ -4,7 +4,8 @@ export const ZEventInputSchema = z.object({ username: z.string(), eventSlug: z.string(), isTeamEvent: z.boolean().optional(), - org: z.string().nullable(), + orgSlug: z.string().nullable(), + orgId: z.number().optional(), /** * Informs that the event request has been sent from a page that was reached by a redirect from non-org link(i.e. app.cal.com/username redirected to acme.cal.com/username) * Based on this decision like whether to allow unpublished organization's event to be served or not can be made.