Skip to content

Commit 6c6cf04

Browse files
fix: handle TempOrgRedirect when NEXT_PUBLIC_SINGLE_ORG_SLUG forces org context (#23009)
* fix: rename getTemporaryOrgRedirect to handleOrgRedirect and prevent duplicate orgRedirection query parameter * refactor: improve handleOrgRedirect test robustness with scenario-based mocking - Replace brittle mockResolvedValue with mockImplementation that derives behavior from input - Create createRedirectScenario function that sets up mocks based on actual query parameters - Add expectRedirectUsesData helper to verify redirects use the correct data - Add comprehensive mock verification tests to ensure different inputs return different outputs - Ensure tests verify the actual usage of Prisma results, not just that Prisma was called This prevents false positives where tests pass even if the code doesn't use the database results correctly. * Fix bug with Private links redirecting an exposing users booking page URL * Narrow the type to what is being used --------- Co-authored-by: Udit Takkar <[email protected]>
1 parent 211b958 commit 6c6cf04

File tree

11 files changed

+991
-487
lines changed

11 files changed

+991
-487
lines changed

apps/web/app/(booking-page-wrapper)/team/[slug]/[type]/pageWithCachedData.tsx

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import slugify from "@calcom/lib/slugify";
1616
import { BookingStatus, RedirectType } from "@calcom/prisma/enums";
1717

1818
import { buildLegacyCtx, buildLegacyRequest } from "@lib/buildLegacyCtx";
19-
import { getTemporaryOrgRedirect } from "@lib/getTemporaryOrgRedirect";
19+
import { handleOrgRedirect } from "@lib/handleOrgRedirect";
2020

2121
import CachedClientView, { type TeamBookingPageProps } from "~/team/type-view-cached";
2222

@@ -124,19 +124,17 @@ export const generateMetadata = async ({ params, searchParams }: PageProps) => {
124124

125125
const CachedTeamBooker = async ({ params, searchParams }: PageProps) => {
126126
const { currentOrgDomain, isValidOrgDomain, teamSlug, meetingSlug } = await _getOrgContext(await params);
127-
const isOrgContext = currentOrgDomain && isValidOrgDomain;
128127
const legacyCtx = buildLegacyCtx(await headers(), await cookies(), await params, await searchParams);
129128

130-
// Handle org redirects for non-org contexts
131-
if (!isOrgContext) {
132-
const redirectResult = await getTemporaryOrgRedirect({
133-
slugs: teamSlug,
134-
redirectType: RedirectType.Team,
135-
eventTypeSlug: meetingSlug,
136-
currentQuery: legacyCtx.query,
137-
});
138-
if (redirectResult) return redirect(redirectResult.redirect.destination);
139-
}
129+
// Handle org redirects
130+
const redirectResult = await handleOrgRedirect({
131+
slugs: [teamSlug],
132+
redirectType: RedirectType.Team,
133+
eventTypeSlug: meetingSlug,
134+
context: legacyCtx,
135+
currentOrgDomain: isValidOrgDomain ? currentOrgDomain : null,
136+
});
137+
if (redirectResult) return redirect(redirectResult.redirect.destination);
140138

141139
const teamData = await getCachedTeamData(teamSlug, currentOrgDomain);
142140

apps/web/lib/d/[link]/[slug]/getServerSideProps.tsx

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import slugify from "@calcom/lib/slugify";
1515
import prisma from "@calcom/prisma";
1616
import { RedirectType } from "@calcom/prisma/enums";
1717

18-
import { getTemporaryOrgRedirect } from "@lib/getTemporaryOrgRedirect";
18+
import { getRedirectWithOriginAndSearchString } from "@lib/handleOrgRedirect";
1919
import type { inferSSRProps } from "@lib/types/inferSSRProps";
2020

2121
export type PageProps = inferSSRProps<typeof getServerSideProps> & EmbedProps;
@@ -64,17 +64,26 @@ async function getUserPageProps(context: GetServerSidePropsContext) {
6464
return notFound;
6565
}
6666

67-
if (!org) {
68-
const redirect = await getTemporaryOrgRedirect({
69-
slugs: [username],
70-
redirectType: RedirectType.User,
71-
eventTypeSlug: slug,
72-
currentQuery: context.query,
73-
});
74-
75-
if (redirect) {
76-
return redirect;
77-
}
67+
// Get just the origin and searchString from the redirect to ensure that we don't redirect to a URL that exposes the real path to book the user for any other events \
68+
// This is important for a private booking link
69+
// e.g. http://app.cal.com/d/sgdthj8mu4nsLNTYi3fW2p/demo -> should redirect to -> http://acme.cal.com/d/sgdthj8mu4nsLNTYi3fW2p/demo and not to http://acme.cal.com/john/demo(which exposes the real path to book the user for any other events)
70+
const redirectWithOriginAndSearchString = await getRedirectWithOriginAndSearchString({
71+
slugs: [username],
72+
redirectType: RedirectType.User,
73+
context,
74+
currentOrgDomain: isValidOrgDomain ? currentOrgDomain : null,
75+
});
76+
77+
if (redirectWithOriginAndSearchString) {
78+
return {
79+
redirect: {
80+
permanent: false,
81+
// App Router doesn't have access to the current path directly, so we build it manually
82+
destination: `${redirectWithOriginAndSearchString.origin ?? ""}/d/${link}/${slug}${
83+
redirectWithOriginAndSearchString.searchString
84+
}`,
85+
},
86+
};
7887
}
7988

8089
name = profileUsername || username;

0 commit comments

Comments
 (0)