From 6b09c6b3b471e4ada8f0d2cf41c2ee3431310704 Mon Sep 17 00:00:00 2001 From: Hariom Balhara Date: Wed, 13 Dec 2023 07:32:38 +0530 Subject: [PATCH] fix: Allow lowercase/uppercase/mixedcase access with org team event booking page (#12721) Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com> --- .../web/pages/org/[orgSlug]/[user]/[type].tsx | 18 +++++++-- apps/web/playwright/teams.e2e.ts | 39 +++++++++++++++++++ 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/apps/web/pages/org/[orgSlug]/[user]/[type].tsx b/apps/web/pages/org/[orgSlug]/[user]/[type].tsx index c5cdf8e6d4..c95ec03fb8 100644 --- a/apps/web/pages/org/[orgSlug]/[user]/[type].tsx +++ b/apps/web/pages/org/[orgSlug]/[user]/[type].tsx @@ -1,6 +1,8 @@ import type { GetServerSidePropsContext } from "next"; +import z from "zod"; import { getSlugOrRequestedSlug } from "@calcom/features/ee/organizations/lib/orgDomains"; +import slugify from "@calcom/lib/slugify"; import prisma from "@calcom/prisma"; import PageWrapper from "@components/PageWrapper"; @@ -10,21 +12,29 @@ import UserTypePage, { getServerSideProps as GSSUserTypePage } from "../../../[u import type { PageProps as TeamTypePageProps } from "../../../team/[slug]/[type]"; import TeamTypePage, { getServerSideProps as GSSTeamTypePage } from "../../../team/[slug]/[type]"; +const paramsSchema = z.object({ + orgSlug: z.string().transform((s) => slugify(s)), + user: z.string().transform((s) => slugify(s)), + type: z.string().transform((s) => slugify(s)), +}); + export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { + const { user: teamOrUserSlug, orgSlug, type } = paramsSchema.parse(ctx.params); const team = await prisma.team.findFirst({ where: { - slug: ctx.query.user as string, + slug: teamOrUserSlug, parentId: { not: null, }, - parent: getSlugOrRequestedSlug(ctx.query.orgSlug as string), + parent: getSlugOrRequestedSlug(orgSlug), }, select: { id: true, }, }); + if (team) { - const params = { slug: ctx.query.user, type: ctx.query.type }; + const params = { slug: teamOrUserSlug, type }; return GSSTeamTypePage({ ...ctx, params: { @@ -37,7 +47,7 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { }, }); } - const params = { user: ctx.query.user, type: ctx.query.type }; + const params = { user: teamOrUserSlug, type }; return GSSUserTypePage({ ...ctx, params: { diff --git a/apps/web/playwright/teams.e2e.ts b/apps/web/playwright/teams.e2e.ts index 4c8cae0bd5..9a8010236b 100644 --- a/apps/web/playwright/teams.e2e.ts +++ b/apps/web/playwright/teams.e2e.ts @@ -418,6 +418,45 @@ test.describe("Teams - Org", () => { expect(teamMatesObj.concat([{ name: owner.name! }]).some(({ name }) => name === chosenUser)).toBe(true); // TODO: Assert whether the user received an email }); + + test("Can access booking page with event slug and team page in lowercase/uppercase/mixedcase", async ({ + page, + orgs, + users, + }) => { + const org = await orgs.create({ + name: "TestOrg", + }); + const teamMatesObj = [ + { name: "teammate-1" }, + { name: "teammate-2" }, + { name: "teammate-3" }, + { name: "teammate-4" }, + ]; + + const owner = await users.create( + { + username: "pro-user", + name: "pro-user", + organizationId: org.id, + roleInOrganization: MembershipRole.MEMBER, + }, + { + hasTeam: true, + teammates: teamMatesObj, + schedulingType: SchedulingType.COLLECTIVE, + } + ); + const { team } = await owner.getFirstTeam(); + const { slug: teamEventSlug } = await owner.getFirstTeamEvent(team.id); + + const teamSlugUpperCase = team.slug?.toUpperCase(); + const teamEventSlugUpperCase = teamEventSlug.toUpperCase(); + + // This is the most closest to the actual user flow as org1.cal.com maps to /org/orgSlug + await page.goto(`/org/${org.slug}/${teamSlugUpperCase}/${teamEventSlugUpperCase}`); + await page.waitForSelector("[data-testid=day]"); + }); }); async function doOnOrgDomain(