* Initial commit * Adding feature flag * Desktop first banner, mobile pending * Removing dead code and img * AppInstallButtonBase * WIP * Adds Email verification template+translations for organizations (#9202) * feat: Orgs Schema Changing `scopedMembers` to `orgUsers` (#9209) * Change scopedMembers to orgMembers * Change to orgUsers * First step done * Merge branch 'feat/organizations-onboarding' of github.com:calcom/cal.com into feat/organizations-onboarding * Session logic to show org label * Step 2 done, avatar not working * List orgs and list teams specific if orgs exist * Conditionally show org - fix settings layout - add labels for all pages * Profile Page + update * Org specific team creation * appearance page * Ensure members cant of org cant update settings in UI * Fix update handler imports * hide billing on sub teams * Update profile slug page * Letting duplicate slugs for teams to support orgs * Add slug coliisions for org * Covering null on unique clauses * Covering null on unique clauses * Extract to utils * Update settings to use subdomain path in team url , team + org * Supporting having the orgId in the session cookie * Onboarding admins step * Last step to create teams * Update handler comments * Upgrade ORG banner - disabled team banner for child teams * Handle publishing ORGS * Fix licenese issue * Update packages/trpc/server/routers/viewer/teams/create.handler.ts * Split into function calls to make this file more explisit * Update parents stripe sub not teamID * Moving change password handler, improving verifying code flow * Clearing error before submitting * Reverting email testing api changes * Reverting having the banner for now * Consistent exported components * Remove unneeded files from banner * Removing uneeded code * Fixing avatar selector * Using meta component for head/descr * Missing i18n strings * Create org membership also - billing portal page * A11ly * Hide create team if no valid permisisons * Get Org members router * Handle updating subscription if orgId * Fix double upgrade banner * Update constants * Feedback * Copy change * Making an org avatar (temp) * Add slug colission detection for user and team name * Fix Import * Remove update password func * Fix module import over relative * feat: organization event type filter (#9253) Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in> * Missing changes to support orgs schema changes * Fix import again * Throw no team found before auth error * Check if invited found user is already in differnt org * Move to for of loop to throw errors in usenamelist * Remove app install button sa its in 9337 * Remove i18n key not being used * feat: Onboarding process to create an organization (#9184) * Desktop first banner, mobile pending * Removing dead code and img * WIP * Adds Email verification template+translations for organizations (#9202) * First step done * Merge branch 'feat/organizations-onboarding' of github.com:calcom/cal.com into feat/organizations-onboarding * Step 2 done, avatar not working * Covering null on unique clauses * Onboarding admins step * Last step to create teams * Moving change password handler, improving verifying code flow * Clearing error before submitting * Reverting email testing api changes * Reverting having the banner for now * Consistent exported components * Remove unneeded files from banner * Removing uneeded code * Fixing avatar selector * Using meta component for head/descr * Missing i18n strings * Feedback * Making an org avatar (temp) * Check for subteams slug clashes with usernames * Fixing create teams onsuccess * feedback * Making sure we check requestedSlug now --------- Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com> * feat: [CAL-1816] Organization subdomain support (#9345) * Desktop first banner, mobile pending * Removing dead code and img * WIP * Adds Email verification template+translations for organizations (#9202) * First step done * Merge branch 'feat/organizations-onboarding' of github.com:calcom/cal.com into feat/organizations-onboarding * Step 2 done, avatar not working * Covering null on unique clauses * Onboarding admins step * Last step to create teams * Moving change password handler, improving verifying code flow * Clearing error before submitting * Reverting email testing api changes * Reverting having the banner for now * Consistent exported components * Remove unneeded files from banner * Removing uneeded code * Fixing avatar selector * Using meta component for head/descr * Missing i18n strings * Feedback * Making an org avatar (temp) * Check for subteams slug clashes with usernames * Fixing create teams onsuccess * Covering users and subteams, excluding non-org users * Unpublished teams shows correctly * Create subdomain in Vercel * feedback * Renaming Vercel env vars * Vercel domain check before creation * Supporting cal-staging.com * Change to have vercel detect it * vercel domain check data message error * Remove check domain * Making sure we check requestedSlug now * Feedback and unneeded code * Reverting unneeded changes * Unneeded changes --------- Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com> * Vercel subdomain creation in PROD only * Fix router * feat: organization settings general and members page (#9266) * feat: organization settings general page Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in> * feat: add members page Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in> * chore: remove Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in> * fix: use invalidate Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in> * fix: delete mutation Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in> * fix: remove organization id Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in> * chore Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in> * fix: use zod schema Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in> --------- Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in> * Type fixes * Use org Stripe product when upgrading * Removed unused code * Reverting changes * Update UsernameTextfield.tsx * More reverts * Update next-auth-options.ts * Update common.json * Type fixes * Include invite token for orgs * Update org schema * Make token settings optional as it isnt used in orgs yet * Reverts * remove yarn.lock from commit * Fix types * feat: orgs unverified (#9415) Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com> Co-authored-by: Udit Takkar <udit.07814802719@cse.mait.ac.in> Co-authored-by: Keith Williams <keithwillcode@gmail.com> * Fix wrong banner being displayed * Type fix * Fix type issues * Update packages/trpc/server/routers/viewer/teams/inviteMember.handler.ts Co-authored-by: alannnc <alannnc@gmail.com> * fix missing input on trpc query * Fix for parentId value for createProvisionalMembership --------- Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in> Co-authored-by: Leo Giovanetti <hello@leog.me> Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com> Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com> Co-authored-by: zomars <zomars@me.com> Co-authored-by: Joe Au-Yeung <j.auyeung419@gmail.com> Co-authored-by: Udit Takkar <udit.07814802719@cse.mait.ac.in> Co-authored-by: Keith Williams <keithwillcode@gmail.com> Co-authored-by: alannnc <alannnc@gmail.com>
195 lines
4.9 KiB
TypeScript
195 lines
4.9 KiB
TypeScript
import type { NextApiRequest, NextApiResponse } from "next";
|
|
import { z } from "zod";
|
|
|
|
import dayjs from "@calcom/dayjs";
|
|
import { hashPassword } from "@calcom/features/auth/lib/hashPassword";
|
|
import { sendEmailVerification } from "@calcom/features/auth/lib/verifyEmail";
|
|
import slugify from "@calcom/lib/slugify";
|
|
import { closeComUpsertTeamUser } from "@calcom/lib/sync/SyncServiceManager";
|
|
import prisma from "@calcom/prisma";
|
|
import { IdentityProvider } from "@calcom/prisma/enums";
|
|
import { teamMetadataSchema } from "@calcom/prisma/zod-utils";
|
|
|
|
const signupSchema = z.object({
|
|
username: z.string(),
|
|
email: z.string().email(),
|
|
password: z.string().min(7),
|
|
language: z.string().optional(),
|
|
token: z.string().optional(),
|
|
});
|
|
|
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|
if (req.method !== "POST") {
|
|
return;
|
|
}
|
|
|
|
if (process.env.NEXT_PUBLIC_DISABLE_SIGNUP === "true") {
|
|
res.status(403).json({ message: "Signup is disabled" });
|
|
return;
|
|
}
|
|
|
|
const data = req.body;
|
|
const { email, password, language, token } = signupSchema.parse(data);
|
|
|
|
const username = slugify(data.username);
|
|
const userEmail = email.toLowerCase();
|
|
|
|
if (!username) {
|
|
res.status(422).json({ message: "Invalid username" });
|
|
return;
|
|
}
|
|
|
|
// There is an existingUser if the username matches
|
|
// OR if the email matches AND either the email is verified
|
|
// or both username and password are set
|
|
const existingUser = await prisma.user.findFirst({
|
|
where: {
|
|
OR: [
|
|
{ username },
|
|
{
|
|
AND: [
|
|
{ email: userEmail },
|
|
{
|
|
OR: [
|
|
{ emailVerified: { not: null } },
|
|
{
|
|
AND: [{ password: { not: null } }, { username: { not: null } }],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
});
|
|
|
|
if (existingUser) {
|
|
const message: string =
|
|
existingUser.email !== userEmail ? "Username already taken" : "Email address is already registered";
|
|
|
|
return res.status(409).json({ message });
|
|
}
|
|
|
|
const hashedPassword = await hashPassword(password);
|
|
|
|
const user = await prisma.user.upsert({
|
|
where: { email: userEmail },
|
|
update: {
|
|
username,
|
|
password: hashedPassword,
|
|
emailVerified: new Date(Date.now()),
|
|
identityProvider: IdentityProvider.CAL,
|
|
},
|
|
create: {
|
|
username,
|
|
email: userEmail,
|
|
password: hashedPassword,
|
|
identityProvider: IdentityProvider.CAL,
|
|
},
|
|
});
|
|
|
|
if (token) {
|
|
const foundToken = await prisma.verificationToken.findFirst({
|
|
where: {
|
|
token,
|
|
},
|
|
});
|
|
|
|
if (!foundToken) {
|
|
return res.status(401).json({ message: "Invalid Token" });
|
|
}
|
|
|
|
if (dayjs(foundToken?.expires).isBefore(dayjs())) {
|
|
return res.status(401).json({ message: "Token expired" });
|
|
}
|
|
|
|
if (foundToken.teamId) {
|
|
const team = await prisma.team.findUnique({
|
|
where: {
|
|
id: foundToken.teamId,
|
|
},
|
|
});
|
|
|
|
if (team) {
|
|
const teamMetadata = teamMetadataSchema.parse(team?.metadata);
|
|
if (teamMetadata?.isOrganization) {
|
|
await prisma.user.update({
|
|
where: {
|
|
id: user.id,
|
|
},
|
|
data: {
|
|
organizationId: team.id,
|
|
},
|
|
});
|
|
}
|
|
|
|
const membership = await prisma.membership.update({
|
|
where: {
|
|
userId_teamId: { userId: user.id, teamId: team.id },
|
|
},
|
|
data: {
|
|
accepted: true,
|
|
},
|
|
});
|
|
closeComUpsertTeamUser(team, user, membership.role);
|
|
|
|
// Accept any child team invites for orgs.
|
|
if (team.parentId) {
|
|
// Join ORG
|
|
await prisma.user.update({
|
|
where: {
|
|
id: user.id,
|
|
},
|
|
data: {
|
|
organizationId: team.parentId,
|
|
},
|
|
});
|
|
|
|
/** We do a membership update twice so we can join the ORG invite if the user is invited to a team witin a ORG. */
|
|
await prisma.membership.updateMany({
|
|
where: {
|
|
userId: user.id,
|
|
team: {
|
|
id: team.parentId,
|
|
},
|
|
accepted: false,
|
|
},
|
|
data: {
|
|
accepted: true,
|
|
},
|
|
});
|
|
|
|
// Join any other invites
|
|
await prisma.membership.updateMany({
|
|
where: {
|
|
userId: user.id,
|
|
team: {
|
|
parentId: team.parentId,
|
|
},
|
|
accepted: false,
|
|
},
|
|
data: {
|
|
accepted: true,
|
|
},
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
// Cleanup token after use
|
|
await prisma.verificationToken.delete({
|
|
where: {
|
|
id: foundToken.id,
|
|
},
|
|
});
|
|
}
|
|
|
|
await sendEmailVerification({
|
|
email: userEmail,
|
|
username,
|
|
language,
|
|
});
|
|
|
|
res.status(201).json({ message: "Created user" });
|
|
}
|