fix: team invite signup not working (#13717)

* Fix team invite signup not working

* Add unit test

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
This commit is contained in:
Hariom Balhara
2024-02-16 12:50:07 +00:00
committed by GitHub
co-authored by Udit Takkar
parent 4fa3fdef97
commit ff6db3c572
3 changed files with 107 additions and 6 deletions
+92
View File
@@ -0,0 +1,92 @@
import prismaMock from "../../../tests/libs/__mocks__/prismaMock";
import { describe, expect, it, beforeEach } from "vitest";
import { usernameCheckForSignup } from "./username";
describe("usernameCheckForSignup ", async () => {
beforeEach(() => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
prismaMock.user.findUnique.mockImplementation(() => {
return null;
});
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
prismaMock.user.findMany.mockImplementation(() => {
return [];
});
});
it("should return available true for an email that doesn't exist", async () => {
const res = await usernameCheckForSignup({ username: "johnny", email: "johnny@example.com" });
expect(res).toEqual({
available: true,
premium: false,
suggestedUsername: "",
});
});
it("should return available false for an email that exists and a different username is provided", async () => {
mockUserInDB({
id: 1,
email: "john@example.com",
username: "john",
});
const res = await usernameCheckForSignup({ username: "johnny", email: "john@example.com" });
expect(res).toEqual({
available: false,
premium: false,
suggestedUsername: "johnny001",
});
});
it("should return available true for an email that exists but the user is signing up for an organization", async () => {
const userId = 1;
mockUserInDB({
id: userId,
email: "john@example.com",
username: "john",
});
mockMembership({ userId });
const res = await usernameCheckForSignup({ username: "john", email: "john@example.com" });
expect(res).toEqual({
available: true,
// An organization can't have premium username
premium: false,
suggestedUsername: "",
});
});
});
function mockUserInDB({ id, email, username }: { id: number; email: string; username: string }) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
prismaMock.user.findUnique.mockImplementation((arg) => {
if (arg.where.email === email) {
return {
id,
email,
username,
};
}
return null;
});
}
function mockMembership({ userId }: { userId: number }) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
prismaMock.membership.findFirst.mockImplementation((arg) => {
const isOrganizationWhereClause =
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
arg?.where?.team?.metadata?.path[0] === "isOrganization" && arg?.where?.team?.metadata?.equals === true;
if (arg?.where?.userId === userId && isOrganizationWhereClause) {
return {
userId,
teamId: 1,
};
}
});
}
+4 -2
View File
@@ -178,7 +178,7 @@ const usernameCheckForSignup = async ({
const username = slugify(usernameRaw);
const user = await prisma.user.findFirst({
const user = await prisma.user.findUnique({
where: {
email,
},
@@ -207,7 +207,9 @@ const usernameCheckForSignup = async ({
// The only way to differentiate b/w 'a new email that was invited to an Org' and 'a user that was created using regular signup' is to check if the user is a member of an org.
// If username is in global namespace
if (!userIsAMemberOfAnOrg) {
response.available = false;
const isClaimingAlreadySetUsername = user.username === username;
const isClaimingUnsetUsername = !user.username;
response.available = isClaimingUnsetUsername || isClaimingAlreadySetUsername;
// There are no premium users outside an organization only
response.premium = await isPremiumUserName(username);
}
@@ -227,22 +227,29 @@ export async function createNewUsersConnectToOrgIfExists({
}) {
// fail if we have invalid emails
usernamesOrEmails.forEach((usernameOrEmail) => checkInputEmailIsValid(usernameOrEmail));
// from this point we know usernamesOrEmails contains only emails
await prisma.$transaction(
async (tx) => {
for (let index = 0; index < usernamesOrEmails.length; index++) {
const usernameOrEmail = usernamesOrEmails[index];
// Weird but orgId is defined only if the invited user email matches orgAutoAcceptEmail
const { orgId, autoAccept } = connectionInfoMap[usernameOrEmail];
const [emailUser, emailDomain] = usernameOrEmail.split("@");
const username =
// An org member can't change username during signup, so we set the username
const orgMemberUsername =
emailDomain === autoAcceptEmailDomain
? slugify(emailUser)
: slugify(`${emailUser}-${emailDomain.split(".")[0]}`);
// As a regular team member is allowed to change username during signup, we don't set any username for him
const regularTeamMemberUsername = null;
const isBecomingAnOrgMember = parentId || input.isOrg;
const createdUser = await tx.user.create({
data: {
username,
username: isBecomingAnOrgMember ? orgMemberUsername : regularTeamMemberUsername,
email: usernameOrEmail,
verified: true,
invitedTo: input.teamId,
@@ -254,7 +261,7 @@ export async function createNewUsersConnectToOrgIfExists({
data: [
{
uid: ProfileRepository.generateProfileUid(),
username,
username: orgMemberUsername,
organizationId: orgId,
},
],