.
This commit is contained in:
@@ -439,7 +439,18 @@ function EditUserDialog({ user, onClose, onSaved }: { user: User | null; onClose
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
try {
|
try {
|
||||||
await api.adminPatch(user.id, { username: username.trim().toLowerCase(), displayName: displayName.trim(), avatarUrl: avatarUrl.trim(), email: email.trim(), theme });
|
const patch: { username?: string; displayName?: string; avatarUrl?: string; theme?: string; email?: string } = {};
|
||||||
|
const normalizedUsername = username.trim().toLowerCase();
|
||||||
|
if (normalizedUsername !== (user.username ?? "").toLowerCase()) patch.username = normalizedUsername;
|
||||||
|
if (displayName.trim() !== (user.displayName ?? "")) patch.displayName = displayName.trim();
|
||||||
|
if (avatarUrl.trim() !== (user.avatarUrl ?? "")) patch.avatarUrl = avatarUrl.trim();
|
||||||
|
if (email.trim() !== (user.email ?? "")) patch.email = email.trim();
|
||||||
|
if (theme !== (user.theme ?? "auto")) patch.theme = theme;
|
||||||
|
if (Object.keys(patch).length === 0) {
|
||||||
|
onClose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await api.adminPatch(user.id, patch);
|
||||||
onSaved();
|
onSaved();
|
||||||
onClose();
|
onClose();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -388,7 +388,21 @@ export function SettingsModal({
|
|||||||
}
|
}
|
||||||
discardStaged();
|
discardStaged();
|
||||||
}
|
}
|
||||||
const res = await api.updateMe({ username: username.trim().toLowerCase(), displayName: displayName.trim(), avatarUrl: url, email: email.trim(), theme });
|
const normalizedUsername = username.trim().toLowerCase();
|
||||||
|
// Only send fields that actually changed: this isolates a
|
||||||
|
// username error (e.g. admin rename guard) from the rest of the
|
||||||
|
// profile so one rejected field can't block the whole save.
|
||||||
|
const patch: { username?: string; displayName?: string; avatarUrl?: string; email?: string; theme?: string } = {};
|
||||||
|
if (normalizedUsername !== (user.username ?? "").toLowerCase()) patch.username = normalizedUsername;
|
||||||
|
if (displayName.trim() !== (user.displayName ?? "")) patch.displayName = displayName.trim();
|
||||||
|
if (url !== (user.avatarUrl ?? "")) patch.avatarUrl = url;
|
||||||
|
if (email.trim() !== (user.email ?? "")) patch.email = email.trim();
|
||||||
|
if (theme !== (user.theme ?? "auto")) patch.theme = theme;
|
||||||
|
if (Object.keys(patch).length === 0) {
|
||||||
|
onClose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const res = await api.updateMe(patch);
|
||||||
onSaved(res.user);
|
onSaved(res.user);
|
||||||
onClose();
|
onClose();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
+22
-13
@@ -628,13 +628,19 @@ const server = Bun.serve<{ ticketId: string | null; isAdmin: boolean }>({
|
|||||||
if (!ok) return json({ error: "invalid JSON" }, 400);
|
if (!ok) return json({ error: "invalid JSON" }, 400);
|
||||||
const patch: { username?: string; displayName?: string; avatarUrl?: string; theme?: string; email?: string } = {};
|
const patch: { username?: string; displayName?: string; avatarUrl?: string; theme?: string; email?: string } = {};
|
||||||
if (body.username !== undefined) {
|
if (body.username !== undefined) {
|
||||||
if (user.username === "admin") return json({ error: "the admin account cannot be renamed" }, 403);
|
// No-op when unchanged (settings forms send the whole profile):
|
||||||
if (!await isUsernameChangeEnabled()) return json({ error: "username changes are disabled" }, 403);
|
// don't fail the entire save for the admin account when the
|
||||||
const u = validUsername(body.username);
|
// username field just echoes the current value.
|
||||||
if (!u) return json({ error: "username: 2-32 chars [a-z0-9._-], 'admin' reserved" }, 400);
|
const raw = typeof body.username === "string" ? body.username.trim().toLowerCase() : "";
|
||||||
const taken = await getUserByUsername(u);
|
if (raw !== user.username) {
|
||||||
if (taken && taken.id !== user.id) return json({ error: "username taken" }, 409);
|
if (user.username === "admin") return json({ error: "the admin account cannot be renamed" }, 403);
|
||||||
patch.username = u;
|
if (!await isUsernameChangeEnabled()) return json({ error: "username changes are disabled" }, 403);
|
||||||
|
const u = validUsername(body.username);
|
||||||
|
if (!u) return json({ error: "username: 2-32 chars [a-z0-9._-], 'admin' reserved" }, 400);
|
||||||
|
const taken = await getUserByUsername(u);
|
||||||
|
if (taken && taken.id !== user.id) return json({ error: "username taken" }, 409);
|
||||||
|
patch.username = u;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (body.displayName !== undefined) {
|
if (body.displayName !== undefined) {
|
||||||
const d = cleanStr(body.displayName, 60);
|
const d = cleanStr(body.displayName, 60);
|
||||||
@@ -813,12 +819,15 @@ const server = Bun.serve<{ ticketId: string | null; isAdmin: boolean }>({
|
|||||||
if (!ok) return json({ error: "invalid JSON" }, 400);
|
if (!ok) return json({ error: "invalid JSON" }, 400);
|
||||||
const patch: { username?: string; displayName?: string; avatarUrl?: string; theme?: string; email?: string } = {};
|
const patch: { username?: string; displayName?: string; avatarUrl?: string; theme?: string; email?: string } = {};
|
||||||
if (body.username !== undefined) {
|
if (body.username !== undefined) {
|
||||||
if (target.username === "admin") return json({ error: "the admin account cannot be renamed" }, 403);
|
const raw = typeof body.username === "string" ? body.username.trim().toLowerCase() : "";
|
||||||
const u = validUsername(body.username);
|
if (raw !== target.username) {
|
||||||
if (!u) return json({ error: "username: 2-32 chars [a-z0-9._-], 'admin' reserved" }, 400);
|
if (target.username === "admin") return json({ error: "the admin account cannot be renamed" }, 403);
|
||||||
const taken = await getUserByUsername(u);
|
const u = validUsername(body.username);
|
||||||
if (taken && taken.id !== target.id) return json({ error: "username taken" }, 409);
|
if (!u) return json({ error: "username: 2-32 chars [a-z0-9._-], 'admin' reserved" }, 400);
|
||||||
patch.username = u;
|
const taken = await getUserByUsername(u);
|
||||||
|
if (taken && taken.id !== target.id) return json({ error: "username taken" }, 409);
|
||||||
|
patch.username = u;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (body.displayName !== undefined) {
|
if (body.displayName !== undefined) {
|
||||||
const d = cleanStr(body.displayName, 60);
|
const d = cleanStr(body.displayName, 60);
|
||||||
|
|||||||
Reference in New Issue
Block a user