feat: invites bypass disabled signup (#12626)
* invites bypass disabled signup * nit:remove new line * add tests * chore: spelling --------- Co-authored-by: Udit Takkar <udit222001@gmail.com>
This commit is contained in:
parent
80b92b5f11
commit
d185d7f7d8
|
@ -6,8 +6,18 @@ import { type RequestWithUsernameStatus } from "@calcom/features/auth/signup/use
|
||||||
import { IS_PREMIUM_USERNAME_ENABLED } from "@calcom/lib/constants";
|
import { IS_PREMIUM_USERNAME_ENABLED } from "@calcom/lib/constants";
|
||||||
import { HttpError } from "@calcom/lib/http-error";
|
import { HttpError } from "@calcom/lib/http-error";
|
||||||
import logger from "@calcom/lib/logger";
|
import logger from "@calcom/lib/logger";
|
||||||
|
import { signupSchema } from "@calcom/prisma/zod-utils";
|
||||||
|
|
||||||
|
function ensureSignupIsEnabled(req: RequestWithUsernameStatus) {
|
||||||
|
const { token } = signupSchema
|
||||||
|
.pick({
|
||||||
|
token: true,
|
||||||
|
})
|
||||||
|
.parse(req.body);
|
||||||
|
|
||||||
|
// Stil allow signups if there is a team invite
|
||||||
|
if (token) return;
|
||||||
|
|
||||||
function ensureSignupIsEnabled() {
|
|
||||||
if (process.env.NEXT_PUBLIC_DISABLE_SIGNUP === "true") {
|
if (process.env.NEXT_PUBLIC_DISABLE_SIGNUP === "true") {
|
||||||
throw new HttpError({
|
throw new HttpError({
|
||||||
statusCode: 403,
|
statusCode: 403,
|
||||||
|
@ -29,7 +39,7 @@ export default async function handler(req: RequestWithUsernameStatus, res: NextA
|
||||||
// Use a try catch instead of returning res every time
|
// Use a try catch instead of returning res every time
|
||||||
try {
|
try {
|
||||||
ensureReqIsPost(req);
|
ensureReqIsPost(req);
|
||||||
ensureSignupIsEnabled();
|
ensureSignupIsEnabled(req);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Im not sure its worth merging these two handlers. They are different enough to be separate.
|
* Im not sure its worth merging these two handlers. They are different enough to be separate.
|
||||||
|
|
|
@ -525,7 +525,7 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => {
|
||||||
// username + email prepopulated from query params
|
// username + email prepopulated from query params
|
||||||
const { username: preFillusername, email: prefilEmail } = querySchema.parse(ctx.query);
|
const { username: preFillusername, email: prefilEmail } = querySchema.parse(ctx.query);
|
||||||
|
|
||||||
if (process.env.NEXT_PUBLIC_DISABLE_SIGNUP === "true" || flags["disable-signup"]) {
|
if ((process.env.NEXT_PUBLIC_DISABLE_SIGNUP === "true" && !token) || flags["disable-signup"]) {
|
||||||
return {
|
return {
|
||||||
notFound: true,
|
notFound: true,
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,7 +4,8 @@ import { randomBytes } from "crypto";
|
||||||
import { APP_NAME, IS_PREMIUM_USERNAME_ENABLED, IS_MAILHOG_ENABLED } from "@calcom/lib/constants";
|
import { APP_NAME, IS_PREMIUM_USERNAME_ENABLED, IS_MAILHOG_ENABLED } from "@calcom/lib/constants";
|
||||||
|
|
||||||
import { test } from "./lib/fixtures";
|
import { test } from "./lib/fixtures";
|
||||||
import { getEmailsReceivedByUser } from "./lib/testUtils";
|
import { getEmailsReceivedByUser, localize } from "./lib/testUtils";
|
||||||
|
import { expectInvitationEmailToBeReceived } from "./team/expects";
|
||||||
|
|
||||||
test.describe.configure({ mode: "parallel" });
|
test.describe.configure({ mode: "parallel" });
|
||||||
|
|
||||||
|
@ -12,8 +13,9 @@ test.describe("Signup Flow Test", async () => {
|
||||||
test.beforeEach(async ({ features }) => {
|
test.beforeEach(async ({ features }) => {
|
||||||
features.reset(); // This resets to the inital state not an empt yarray
|
features.reset(); // This resets to the inital state not an empt yarray
|
||||||
});
|
});
|
||||||
test.afterAll(async ({ users }) => {
|
test.afterAll(async ({ users, emails }) => {
|
||||||
await users.deleteAll();
|
await users.deleteAll();
|
||||||
|
emails?.deleteAll();
|
||||||
});
|
});
|
||||||
test("Username is taken", async ({ page, users }) => {
|
test("Username is taken", async ({ page, users }) => {
|
||||||
// log in trail user
|
// log in trail user
|
||||||
|
@ -228,4 +230,55 @@ test.describe("Signup Flow Test", async () => {
|
||||||
const verifyEmail = receivedEmails?.items[0];
|
const verifyEmail = receivedEmails?.items[0];
|
||||||
expect(verifyEmail?.subject).toBe(`${APP_NAME}: Verify your account`);
|
expect(verifyEmail?.subject).toBe(`${APP_NAME}: Verify your account`);
|
||||||
});
|
});
|
||||||
|
test("If signup is disabled allow team invites", async ({ browser, page, users, emails }) => {
|
||||||
|
// eslint-disable-next-line playwright/no-skipped-test
|
||||||
|
test.skip(process.env.NEXT_PUBLIC_DISABLE_SIGNUP !== "true", "Skipping due to signup being enabled");
|
||||||
|
|
||||||
|
const t = await localize("en");
|
||||||
|
const teamOwner = await users.create(undefined, { hasTeam: true });
|
||||||
|
const { team } = await teamOwner.getFirstTeam();
|
||||||
|
await teamOwner.apiLogin();
|
||||||
|
await page.goto(`/settings/teams/${team.id}/members`);
|
||||||
|
await page.waitForLoadState("networkidle");
|
||||||
|
|
||||||
|
await test.step("Invite User to team", async () => {
|
||||||
|
// TODO: This invite logic should live in a fixture - its used in team and orgs invites (Duplicated from team/org invites)
|
||||||
|
const invitedUserEmail = `rick_${Date.now()}@domain-${Date.now()}.com`;
|
||||||
|
await page.locator(`button:text("${t("add")}")`).click();
|
||||||
|
await page.locator('input[name="inviteUser"]').fill(invitedUserEmail);
|
||||||
|
await page.locator(`button:text("${t("send_invite")}")`).click();
|
||||||
|
await page.waitForLoadState("networkidle");
|
||||||
|
const inviteLink = await expectInvitationEmailToBeReceived(
|
||||||
|
page,
|
||||||
|
emails,
|
||||||
|
invitedUserEmail,
|
||||||
|
`${team.name}'s admin invited you to join the team ${team.name} on Cal.com`,
|
||||||
|
"signup?token"
|
||||||
|
);
|
||||||
|
|
||||||
|
//Check newly invited member exists and is pending
|
||||||
|
await expect(
|
||||||
|
page.locator(`[data-testid="email-${invitedUserEmail.replace("@", "")}-pending"]`)
|
||||||
|
).toHaveCount(1);
|
||||||
|
|
||||||
|
// eslint-disable-next-line playwright/no-conditional-in-test
|
||||||
|
if (!inviteLink) return;
|
||||||
|
|
||||||
|
// Follow invite link to new window
|
||||||
|
const context = await browser.newContext();
|
||||||
|
const newPage = await context.newPage();
|
||||||
|
await newPage.goto(inviteLink);
|
||||||
|
await newPage.waitForLoadState("networkidle");
|
||||||
|
|
||||||
|
const url = new URL(newPage.url());
|
||||||
|
expect(url.pathname).toBe("/signup");
|
||||||
|
|
||||||
|
// Check required fields
|
||||||
|
await newPage.locator("input[name=password]").fill(`P4ssw0rd!`);
|
||||||
|
await newPage.locator("button[type=submit]").click();
|
||||||
|
await newPage.waitForURL("/getting-started?from=signup");
|
||||||
|
await newPage.close();
|
||||||
|
await context.close();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue
Block a user