Skip to content

Commit 77077dd

Browse files
authored
Merge branch 'main' into main
2 parents af7038e + 64147d3 commit 77077dd

File tree

63 files changed

+1988
-201
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1988
-201
lines changed

apps/web/components/apps/App.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import {
2929
Avatar,
3030
} from "@calcom/ui";
3131
import { BookOpen, Check, ExternalLink, File, Flag, Mail, Plus, Shield } from "@calcom/ui/components/icon";
32+
import { Spinner } from "@calcom/features/calendars/weeklyview/components/spinner/Spinner";
33+
3234

3335
/* These app slugs all require Google Cal to be installed */
3436

@@ -441,7 +443,16 @@ const InstallAppButtonChild = ({
441443
</Button>
442444
</DropdownMenuTrigger>
443445
<DropdownMenuPortal>
444-
<DropdownMenuContent>
446+
<DropdownMenuContent
447+
onInteractOutside={(event) => {
448+
if (mutation.isLoading) event.preventDefault();
449+
}}
450+
>
451+
{mutation.isLoading && (
452+
<div className="z-1 fixed inset-0 flex items-center justify-center bg-black bg-opacity-50">
453+
<Spinner />
454+
</div>
455+
)}
445456
<DropdownMenuLabel>{t("install_app_on")}</DropdownMenuLabel>
446457
{userAdminTeams.map((team) => {
447458

apps/web/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@calcom/web",
3-
"version": "3.0.16",
3+
"version": "3.1.0",
44
"private": true,
55
"scripts": {
66
"analyze": "ANALYZE=true next build",

apps/web/pages/api/auth/signup.ts

Lines changed: 82 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { hashPassword } from "@calcom/features/auth/lib/hashPassword";
66
import { sendEmailVerification } from "@calcom/features/auth/lib/verifyEmail";
77
import slugify from "@calcom/lib/slugify";
88
import { closeComUpsertTeamUser } from "@calcom/lib/sync/SyncServiceManager";
9+
import { validateUsernameInOrg } from "@calcom/lib/validateUsernameInOrg";
910
import prisma from "@calcom/prisma";
1011
import { IdentityProvider } from "@calcom/prisma/enums";
1112
import { teamMetadataSchema } from "@calcom/prisma/zod-utils";
@@ -70,6 +71,35 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
7071
return res.status(409).json({ message });
7172
}
7273

74+
let foundToken: { id: number; teamId: number | null; expires: Date } | null = null;
75+
if (token) {
76+
foundToken = await prisma.verificationToken.findFirst({
77+
where: {
78+
token,
79+
},
80+
select: {
81+
id: true,
82+
expires: true,
83+
teamId: true,
84+
},
85+
});
86+
87+
if (!foundToken) {
88+
return res.status(401).json({ message: "Invalid Token" });
89+
}
90+
91+
if (dayjs(foundToken?.expires).isBefore(dayjs())) {
92+
return res.status(401).json({ message: "Token expired" });
93+
}
94+
if (foundToken?.teamId) {
95+
const isValidUsername = await validateUsernameInOrg(username, foundToken?.teamId);
96+
97+
if (!isValidUsername) {
98+
return res.status(409).json({ message: "Username already taken" });
99+
}
100+
}
101+
}
102+
73103
const hashedPassword = await hashPassword(password);
74104

75105
const user = await prisma.user.upsert({
@@ -88,91 +118,75 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
88118
},
89119
});
90120

91-
if (token) {
92-
const foundToken = await prisma.verificationToken.findFirst({
121+
if (foundToken && foundToken?.teamId) {
122+
const team = await prisma.team.findUnique({
93123
where: {
94-
token,
124+
id: foundToken.teamId,
95125
},
96126
});
97127

98-
if (!foundToken) {
99-
return res.status(401).json({ message: "Invalid Token" });
100-
}
101-
102-
if (dayjs(foundToken?.expires).isBefore(dayjs())) {
103-
return res.status(401).json({ message: "Token expired" });
104-
}
128+
if (team) {
129+
const teamMetadata = teamMetadataSchema.parse(team?.metadata);
130+
if (teamMetadata?.isOrganization) {
131+
await prisma.user.update({
132+
where: {
133+
id: user.id,
134+
},
135+
data: {
136+
organizationId: team.id,
137+
},
138+
});
139+
}
105140

106-
if (foundToken.teamId) {
107-
const team = await prisma.team.findUnique({
141+
const membership = await prisma.membership.update({
108142
where: {
109-
id: foundToken.teamId,
143+
userId_teamId: { userId: user.id, teamId: team.id },
144+
},
145+
data: {
146+
accepted: true,
110147
},
111148
});
149+
closeComUpsertTeamUser(team, user, membership.role);
112150

113-
if (team) {
114-
const teamMetadata = teamMetadataSchema.parse(team?.metadata);
115-
if (teamMetadata?.isOrganization) {
116-
await prisma.user.update({
117-
where: {
118-
id: user.id,
119-
},
120-
data: {
121-
organizationId: team.id,
122-
},
123-
});
124-
}
151+
// Accept any child team invites for orgs.
152+
if (team.parentId) {
153+
// Join ORG
154+
await prisma.user.update({
155+
where: {
156+
id: user.id,
157+
},
158+
data: {
159+
organizationId: team.parentId,
160+
},
161+
});
125162

126-
const membership = await prisma.membership.update({
163+
/** We do a membership update twice so we can join the ORG invite if the user is invited to a team witin a ORG. */
164+
await prisma.membership.updateMany({
127165
where: {
128-
userId_teamId: { userId: user.id, teamId: team.id },
166+
userId: user.id,
167+
team: {
168+
id: team.parentId,
169+
},
170+
accepted: false,
129171
},
130172
data: {
131173
accepted: true,
132174
},
133175
});
134-
closeComUpsertTeamUser(team, user, membership.role);
135-
136-
// Accept any child team invites for orgs.
137-
if (team.parentId) {
138-
// Join ORG
139-
await prisma.user.update({
140-
where: {
141-
id: user.id,
142-
},
143-
data: {
144-
organizationId: team.parentId,
145-
},
146-
});
147-
148-
/** We do a membership update twice so we can join the ORG invite if the user is invited to a team witin a ORG. */
149-
await prisma.membership.updateMany({
150-
where: {
151-
userId: user.id,
152-
team: {
153-
id: team.parentId,
154-
},
155-
accepted: false,
156-
},
157-
data: {
158-
accepted: true,
159-
},
160-
});
161-
162-
// Join any other invites
163-
await prisma.membership.updateMany({
164-
where: {
165-
userId: user.id,
166-
team: {
167-
parentId: team.parentId,
168-
},
169-
accepted: false,
170-
},
171-
data: {
172-
accepted: true,
176+
177+
// Join any other invites
178+
await prisma.membership.updateMany({
179+
where: {
180+
userId: user.id,
181+
team: {
182+
parentId: team.parentId,
173183
},
174-
});
175-
}
184+
accepted: false,
185+
},
186+
data: {
187+
accepted: true,
188+
},
189+
});
176190
}
177191
}
178192

apps/web/pages/api/integrations/[...args].ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
5656
const handlerMap = (await import("@calcom/app-store/apps.server.generated")).apiHandlers;
5757
const handlerKey = deriveAppDictKeyFromType(appName, handlerMap);
5858
const handlers = await handlerMap[handlerKey as keyof typeof handlerMap];
59+
if (!handlers) throw new HttpError({ statusCode: 404, message: `No handlers found for ${handlerKey}` });
5960
const handler = handlers[apiEndpoint as keyof typeof handlers] as AppHandler;
6061
let redirectUrl = "/apps/installed";
6162
if (typeof handler === "undefined")

apps/web/pages/settings/organizations/[id]/about.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { WizardLayout, Meta } from "@calcom/ui";
66

77
import PageWrapper from "@components/PageWrapper";
88

9+
export { getServerSideProps } from "@calcom/features/ee/organizations/pages/organization";
10+
911
const AboutOrganizationPage = () => {
1012
const { t } = useLocale();
1113
const router = useRouter();

apps/web/pages/settings/organizations/[id]/add-teams.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { WizardLayout, Meta } from "@calcom/ui";
77

88
import PageWrapper from "@components/PageWrapper";
99

10+
export { getServerSideProps } from "@calcom/features/ee/organizations/pages/organization";
11+
1012
const AddNewTeamsPage = () => {
1113
const { t } = useLocale();
1214
const router = useRouter();

apps/web/pages/settings/organizations/[id]/onboard-admins.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { WizardLayout, Meta } from "@calcom/ui";
77

88
import PageWrapper from "@components/PageWrapper";
99

10+
export { getServerSideProps } from "@calcom/features/ee/organizations/pages/organization";
11+
1012
const OnboardTeamMembersPage = () => {
1113
const { t } = useLocale();
1214
const router = useRouter();

apps/web/pages/settings/organizations/[id]/set-password.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { WizardLayout, Meta } from "@calcom/ui";
66

77
import PageWrapper from "@components/PageWrapper";
88

9+
export { getServerSideProps } from "@calcom/features/ee/organizations/pages/organization";
10+
911
const SetPasswordPage = () => {
1012
const { t } = useLocale();
1113
const router = useRouter();

apps/web/pages/settings/organizations/new/index.tsx

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
1+
import type { GetServerSidePropsContext } from "next";
2+
13
import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
24
import { CreateANewOrganizationForm } from "@calcom/features/ee/organizations/components";
5+
import { getFeatureFlagMap } from "@calcom/features/flags/server/utils";
36
import { useLocale } from "@calcom/lib/hooks/useLocale";
47
import { WizardLayout, Meta } from "@calcom/ui";
58

9+
import type { inferSSRProps } from "@lib/types/inferSSRProps";
10+
611
import PageWrapper from "@components/PageWrapper";
712

8-
const CreateNewOrganizationPage = () => {
13+
const CreateNewOrganizationPage = ({ querySlug }: inferSSRProps<typeof getServerSideProps>) => {
914
const { t } = useLocale();
1015
return (
1116
<LicenseRequired>
1217
<Meta title={t("set_up_your_organization")} description={t("organizations_description")} />
13-
<CreateANewOrganizationForm />
18+
<CreateANewOrganizationForm slug={querySlug} />
1419
</LicenseRequired>
1520
);
1621
};
@@ -22,6 +27,25 @@ const LayoutWrapper = (page: React.ReactElement) => {
2227
);
2328
};
2429

30+
export const getServerSideProps = async (context: GetServerSidePropsContext) => {
31+
const prisma = await import("@calcom/prisma").then((mod) => mod.default);
32+
const flags = await getFeatureFlagMap(prisma);
33+
// Check if organizations are enabled
34+
if (flags["organizations"] !== true) {
35+
return {
36+
notFound: true,
37+
};
38+
}
39+
40+
const querySlug = context.query.slug as string;
41+
42+
return {
43+
props: {
44+
querySlug: querySlug ?? null,
45+
},
46+
};
47+
};
48+
2549
CreateNewOrganizationPage.getLayout = LayoutWrapper;
2650
CreateNewOrganizationPage.PageWrapper = PageWrapper;
2751

apps/web/pages/team/[slug].tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { useEffect } from "react";
77
import { sdkActionManager, useIsEmbed } from "@calcom/embed-core/embed-iframe";
88
import { orgDomainConfig } from "@calcom/features/ee/organizations/lib/orgDomains";
99
import EventTypeDescription from "@calcom/features/eventtypes/components/EventTypeDescription";
10+
import { getFeatureFlagMap } from "@calcom/features/flags/server/utils";
1011
import { getPlaceholderAvatar } from "@calcom/lib/defaultAvatarImage";
1112
import { useLocale } from "@calcom/lib/hooks/useLocale";
1213
import useTheme from "@calcom/lib/hooks/useTheme";
@@ -245,6 +246,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
245246
const ssr = await ssrInit(context);
246247
const slug = Array.isArray(context.query?.slug) ? context.query.slug.pop() : context.query.slug;
247248
const { isValidOrgDomain } = orgDomainConfig(context.req.headers.host ?? "");
249+
const flags = await getFeatureFlagMap(prisma);
248250

249251
const team = await getTeamWithMembers(undefined, slug);
250252
const metadata = teamMetadataSchema.parse(team?.metadata ?? {});
@@ -253,7 +255,8 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
253255
if (
254256
(isValidOrgDomain && team?.parent && !!metadata?.isOrganization) ||
255257
(!isValidOrgDomain && team?.parent) ||
256-
(!isValidOrgDomain && !!metadata?.isOrganization)
258+
(!isValidOrgDomain && !!metadata?.isOrganization) ||
259+
flags["organizations"] !== true
257260
) {
258261
return { notFound: true } as const;
259262
}

0 commit comments

Comments
 (0)