Add files via upload
This commit is contained in:
parent
8baa7c2c55
commit
6722907b74
1 changed files with 37 additions and 27 deletions
|
|
@ -936,36 +936,46 @@ export const user = new Elysia()
|
||||||
return redirect(`${WEBROOT}/account`, 302);
|
return redirect(`${WEBROOT}/account`, 302);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent demoting the last admin
|
// Atomic last-admin protection: concurrent demotions must not be able to leave zero admins.
|
||||||
if (targetUser.role === "admin" && role !== "admin") {
|
// Use a write transaction to serialize changes and a conditional UPDATE for demotion.
|
||||||
const adminCountRow = db
|
db.exec("BEGIN IMMEDIATE");
|
||||||
.query("SELECT COUNT(*) AS cnt FROM users WHERE role = 'admin'")
|
try {
|
||||||
.get() as { cnt: number };
|
// Role change
|
||||||
if (adminCountRow.cnt <= 1) {
|
if (role === "admin") {
|
||||||
set.status = 400;
|
db.query("UPDATE users SET role = 'admin' WHERE id = ?").run(targetId);
|
||||||
return { message: "You cannot demote the last remaining admin." };
|
} else if (role === "user") {
|
||||||
|
// If demoting an admin, only allow if there is more than 1 admin at the time of the update.
|
||||||
|
const demoteRes = db
|
||||||
|
.query(
|
||||||
|
`UPDATE users
|
||||||
|
SET role = 'user'
|
||||||
|
WHERE id = ?
|
||||||
|
AND role = 'admin'
|
||||||
|
AND (SELECT COUNT(*) FROM users WHERE role = 'admin') > 1`,
|
||||||
|
)
|
||||||
|
.run(targetId);
|
||||||
|
|
||||||
|
if (targetUser.role === "admin" && demoteRes.changes === 0) {
|
||||||
|
db.exec("ROLLBACK");
|
||||||
|
set.status = 400;
|
||||||
|
return { message: "You cannot demote the last remaining admin." };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const fields: string[] = [];
|
// Password change (optional)
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
if (newPassword && newPassword.trim().length > 0) {
|
||||||
const values: any[] = [];
|
const hashed = await Bun.password.hash(newPassword);
|
||||||
|
db.query("UPDATE users SET password = ? WHERE id = ?").run(hashed, targetId);
|
||||||
|
}
|
||||||
|
|
||||||
if (role === "admin" || role === "user") {
|
db.exec("COMMIT");
|
||||||
fields.push("role");
|
} catch (e) {
|
||||||
values.push(role);
|
try {
|
||||||
}
|
db.exec("ROLLBACK");
|
||||||
|
} catch (rollbackErr) {
|
||||||
if (newPassword && newPassword.trim().length > 0) {
|
console.warn("[user/edit-user] ROLLBACK failed:", rollbackErr);
|
||||||
fields.push("password");
|
}
|
||||||
values.push(await Bun.password.hash(newPassword));
|
throw e;
|
||||||
}
|
|
||||||
|
|
||||||
if (fields.length > 0) {
|
|
||||||
db.query(`UPDATE users SET ${fields.map((f) => `${f}=?`).join(", ")} WHERE id=?`).run(
|
|
||||||
...values,
|
|
||||||
targetId,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return redirect(`${WEBROOT}/account`, 302);
|
return redirect(`${WEBROOT}/account`, 302);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue