feat: add invitation link limits
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { randomBytes, scryptSync, timingSafeEqual } from "node:crypto";
|
||||
|
||||
import { and, eq, gt, isNull } from "drizzle-orm";
|
||||
import { and, eq, gt, gte, isNull, lt, sql } from "drizzle-orm";
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
import { jsonFailure } from "@/modules/core/server/api";
|
||||
@@ -324,12 +324,21 @@ export async function createRegistration(input: {
|
||||
.limit(1)
|
||||
: [];
|
||||
const invitation = invitationRows[0];
|
||||
const now = new Date();
|
||||
if (input.invitationToken && !invitation) {
|
||||
throw new Error("邀请链接无效");
|
||||
}
|
||||
if (invitation && (invitation.invitation.status !== "active" || invitation.invitation.expiresAt < new Date())) {
|
||||
if (
|
||||
invitation &&
|
||||
(invitation.invitation.status !== "active" ||
|
||||
invitation.invitation.expiresAt < now ||
|
||||
invitation.invitation.usedCount >= invitation.invitation.maxUses)
|
||||
) {
|
||||
throw new Error("邀请链接已失效");
|
||||
}
|
||||
if (invitation?.invitation.email && normalizeEmail(invitation.invitation.email) !== normalizedEmail) {
|
||||
throw new Error("邀请邮箱与注册邮箱不一致");
|
||||
}
|
||||
if (!invitation && !settings.registrationEnabled) {
|
||||
throw new Error("系统暂未开放注册");
|
||||
}
|
||||
@@ -372,15 +381,40 @@ export async function createRegistration(input: {
|
||||
roleId: invitation.invitation.roleId,
|
||||
status: "active",
|
||||
});
|
||||
await transaction
|
||||
const consumedRows = await transaction
|
||||
.update(organizationInvitations)
|
||||
.set({
|
||||
status: "accepted",
|
||||
acceptedByAccountId: account.id,
|
||||
acceptedAt: new Date(),
|
||||
usedCount: sql`${organizationInvitations.usedCount} + 1`,
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
.where(eq(organizationInvitations.id, invitation.invitation.id));
|
||||
.where(
|
||||
and(
|
||||
eq(organizationInvitations.id, invitation.invitation.id),
|
||||
eq(organizationInvitations.status, "active"),
|
||||
gte(organizationInvitations.expiresAt, now),
|
||||
lt(organizationInvitations.usedCount, organizationInvitations.maxUses),
|
||||
),
|
||||
)
|
||||
.returning({
|
||||
id: organizationInvitations.id,
|
||||
maxUses: organizationInvitations.maxUses,
|
||||
usedCount: organizationInvitations.usedCount,
|
||||
});
|
||||
const consumed = consumedRows[0];
|
||||
if (!consumed) {
|
||||
throw new Error("邀请链接已失效");
|
||||
}
|
||||
if (consumed.usedCount >= consumed.maxUses) {
|
||||
await transaction
|
||||
.update(organizationInvitations)
|
||||
.set({
|
||||
status: "accepted",
|
||||
acceptedByAccountId: account.id,
|
||||
acceptedAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
.where(eq(organizationInvitations.id, consumed.id));
|
||||
}
|
||||
}
|
||||
|
||||
const sessionRows = await transaction
|
||||
|
||||
Reference in New Issue
Block a user