cal/packages/lib/validateUsername.ts
Hariom Balhara a28e8ff39b
fix: A user joining from invite link of a team doesn't automatically become member of the org (#12774)
* fix: Add org membership when invite link for a team in an org is generated

* Run tests sequentially till we fix emails fixture
2023-12-18 17:48:35 +05:30

132 lines
3.7 KiB
TypeScript

import { getOrgUsernameFromEmail } from "@calcom/features/auth/signup/utils/getOrgUsernameFromEmail";
import prisma from "@calcom/prisma";
import { teamMetadataSchema } from "@calcom/prisma/zod-utils";
export const getUsernameForOrgMember = async ({
email,
orgAutoAcceptEmail,
isSignup,
username,
}: {
username?: string;
email: string;
orgAutoAcceptEmail?: string;
isSignup: boolean;
}) => {
if (isSignup) {
// We ensure that the username is always derived from the email during signup.
return getOrgUsernameFromEmail(email, orgAutoAcceptEmail || "");
}
if (!username) {
throw new Error("Username is required");
}
// Right now it's not possible to change username in an org by the user but when that's allowed we would simply accept the provided username
return username;
};
export const validateAndGetCorrectedUsernameAndEmail = async ({
username,
email,
organizationId,
orgAutoAcceptEmail,
isSignup,
}: {
username: string;
email: string;
organizationId?: number;
orgAutoAcceptEmail?: string;
isSignup: boolean;
}) => {
if (username.includes("+")) {
return { isValid: false, username: undefined, email };
}
// There is an existingUser if, within an org context or not, 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: {
...(organizationId ? { organizationId } : {}),
OR: [
// When inviting to org, invited user gets created with username now, so in an org context we
// can't check for username as it will exist on signup
...(!organizationId ? [{ username }] : [{}]),
{
AND: [
{ email },
{
OR: [
{ emailVerified: { not: null } },
{
AND: [{ password: { not: null } }, { username: { not: null } }],
},
],
},
],
},
],
},
select: {
email: true,
},
});
let validatedUsername = username;
if (organizationId) {
validatedUsername = await getUsernameForOrgMember({
email,
orgAutoAcceptEmail,
isSignup,
});
}
return { isValid: !existingUser, username: validatedUsername, email: existingUser?.email };
};
export const validateAndGetCorrectedUsernameInTeam = async (
username: string,
email: string,
teamId: number,
isSignup: boolean
) => {
try {
const team = await prisma.team.findFirst({
where: {
id: teamId,
},
select: {
metadata: true,
parentId: true,
parent: {
select: {
metadata: true,
},
},
},
});
console.log("validateAndGetCorrectedUsernameInTeam", {
teamId,
team,
});
const teamData = { ...team, metadata: teamMetadataSchema.parse(team?.metadata) };
const organization = teamData.metadata?.isOrganization ? teamData : teamData.parent;
if (organization) {
const orgMetadata = teamMetadataSchema.parse(organization.metadata);
// Organization context -> org-context username check
const orgId = teamData.parentId || teamId;
return validateAndGetCorrectedUsernameAndEmail({
username,
email,
organizationId: orgId,
orgAutoAcceptEmail: orgMetadata?.orgAutoAcceptEmail || "",
isSignup,
});
} else {
// Regular team context -> regular username check
return validateAndGetCorrectedUsernameAndEmail({ username, email, isSignup });
}
} catch (error) {
console.error(error);
return { isValid: false, username: undefined, email: undefined };
}
};