Dont accept invite if over the limits

This commit is contained in:
Owen
2026-02-08 11:55:24 -08:00
parent 41bab0ce0b
commit c41e8be3e8
5 changed files with 61 additions and 4 deletions

View File

@@ -18,7 +18,8 @@
"db:sqlite:generate": "drizzle-kit generate --config=./drizzle.sqlite.config.ts",
"db:pg:push": "npx tsx server/db/pg/migrate.ts",
"db:sqlite:push": "npx tsx server/db/sqlite/migrate.ts",
"db:studio": "drizzle-kit studio --config=./drizzle.config.ts",
"db:pg:studio": "drizzle-kit studio --config=./drizzle.pg.config.ts",
"db:sqlite:studio": "drizzle-kit studio --config=./drizzle.sqlite.config.ts",
"db:clear-migrations": "rm -rf server/migrations",
"set:oss": "echo 'export const build = \"oss\" as \"saas\" | \"enterprise\" | \"oss\";' > server/build.ts && cp tsconfig.oss.json tsconfig.json",
"set:saas": "echo 'export const build = \"saas\" as \"saas\" | \"enterprise\" | \"oss\";' > server/build.ts && cp tsconfig.saas.json tsconfig.json",

View File

@@ -97,7 +97,7 @@ export async function createRemoteExitNode(
return next(
createHttpError(
HttpCode.FORBIDDEN,
"Remote exit node limit exceeded. Please upgrade your plan or contact us at support@pangolin.net"
"Remote node limit exceeded. Please upgrade your plan."
)
);
}

View File

@@ -151,7 +151,7 @@ export async function createSite(
return next(
createHttpError(
HttpCode.FORBIDDEN,
"Sites limit exceeded. Please upgrade your plan."
"Site limit exceeded. Please upgrade your plan."
)
);
}

View File

@@ -13,6 +13,7 @@ import { verifySession } from "@server/auth/sessions/verifySession";
import { usageService } from "@server/lib/billing/usageService";
import { FeatureId } from "@server/lib/billing";
import { calculateUserClientsForOrgs } from "@server/lib/calculateUserClientsForOrgs";
import { build } from "@server/build";
const acceptInviteBodySchema = z.strictObject({
token: z.string(),
@@ -92,6 +93,35 @@ export async function acceptInvite(
);
}
if (build == "saas") {
const usage = await usageService.getUsage(existingInvite.orgId, FeatureId.USERS);
if (!usage) {
return next(
createHttpError(
HttpCode.NOT_FOUND,
"No usage data found for this organization"
)
);
}
const rejectUsers = await usageService.checkLimitSet(
existingInvite.orgId,
false,
FeatureId.USERS,
{
...usage,
instantaneousValue: (usage.instantaneousValue || 0) + 1
} // We need to add one to know if we are violating the limit
);
if (rejectUsers) {
return next(
createHttpError(
HttpCode.FORBIDDEN,
"Can not accept because this org's user limit is exceeded. Please contact your administrator to upgrade their plan."
)
);
}
}
let roleId: number;
let totalUsers: UserOrg[] | undefined;
// get the role to make sure it exists

View File

@@ -39,7 +39,7 @@ export default function InviteStatusCard({
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
const [type, setType] = useState<
"rejected" | "wrong_user" | "user_does_not_exist" | "not_logged_in"
"rejected" | "wrong_user" | "user_does_not_exist" | "not_logged_in" | "user_limit_exceeded"
>("rejected");
useEffect(() => {
@@ -75,6 +75,11 @@ export default function InviteStatusCard({
error.includes("You must be logged in to accept an invite")
) {
return "not_logged_in";
} else if (
error.includes("user limit is exceeded") ||
error.includes("Can not accept")
) {
return "user_limit_exceeded";
} else {
return "rejected";
}
@@ -145,6 +150,17 @@ export default function InviteStatusCard({
<p className="text-center">{t("inviteCreateUser")}</p>
</div>
);
} else if (type === "user_limit_exceeded") {
return (
<div>
<p className="text-center mb-4 font-semibold">
Cannot Accept Invite
</p>
<p className="text-center text-sm">
This organization has reached its user limit. Please contact the organization administrator to upgrade their plan before accepting this invite.
</p>
</div>
);
}
}
@@ -165,6 +181,16 @@ export default function InviteStatusCard({
);
} else if (type === "user_does_not_exist") {
return <Button onClick={goToSignup}>{t("createAnAccount")}</Button>;
} else if (type === "user_limit_exceeded") {
return (
<Button
onClick={() => {
router.push("/");
}}
>
{t("goHome")}
</Button>
);
}
}