42 lines
1.3 KiB
TypeScript
42 lines
1.3 KiB
TypeScript
import type { Prisma } from "@prisma/client";
|
|
import { UserFacingError } from "@/lib/action-error";
|
|
|
|
// Serialize role changes, account deletion and support locks for the same Kita.
|
|
export async function lockKitaAccounts(
|
|
tx: Prisma.TransactionClient,
|
|
kitaId: string,
|
|
) {
|
|
const rows = await tx.$queryRaw<
|
|
{ id: string }[]
|
|
>`SELECT id FROM kitas WHERE id = ${kitaId} FOR UPDATE`;
|
|
if (!rows.length) throw new UserFacingError("Kita wurde nicht gefunden.");
|
|
}
|
|
|
|
export async function assertKitaAdminRemains(
|
|
tx: Prisma.TransactionClient,
|
|
kitaId: string,
|
|
excludedUserIds: string[],
|
|
) {
|
|
const removesAdmin = await tx.user.count({
|
|
where: { kitaId, id: { in: excludedUserIds }, role: "ADMIN" },
|
|
});
|
|
if (!removesAdmin) return;
|
|
const now = new Date();
|
|
const remaining = await tx.user.count({
|
|
where: {
|
|
kitaId,
|
|
id: { notIn: excludedUserIds },
|
|
role: "ADMIN",
|
|
disabledAt: null,
|
|
emailVerifiedAt: { not: null },
|
|
privacyPolicyAcceptedAt: { not: null },
|
|
passwordHash: { not: "" },
|
|
OR: [{ lockedUntil: null }, { lockedUntil: { lte: now } }],
|
|
},
|
|
});
|
|
if (!remaining)
|
|
throw new UserFacingError(
|
|
"Mindestens ein aktiver Kita-Admin muss erhalten bleiben. Ernenne zuerst eine weitere Person mit aktiviertem Zugang und Datenschutzzustimmung.",
|
|
);
|
|
}
|