Protect user role from deletion and use action sound asset
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
// Maintainer-controlled web client version.
|
// Maintainer-controlled web client version.
|
||||||
// Format: YYYY.MM.DD Rn (example: 2026.02.20 R2)
|
// Format: YYYY.MM.DD Rn (example: 2026.02.20 R2)
|
||||||
window.CHGRID_WEB_VERSION = "2026.02.27 R294";
|
window.CHGRID_WEB_VERSION = "2026.02.27 R295";
|
||||||
// Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid.
|
// Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid.
|
||||||
window.CHGRID_TIME_ZONE = "America/Detroit";
|
window.CHGRID_TIME_ZONE = "America/Detroit";
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ const SYSTEM_SOUND_URLS = {
|
|||||||
logout: withBase('sounds/logout.ogg'),
|
logout: withBase('sounds/logout.ogg'),
|
||||||
notify: withBase('sounds/notify.ogg'),
|
notify: withBase('sounds/notify.ogg'),
|
||||||
} as const;
|
} as const;
|
||||||
const ACTION_SOUND_URL = SYSTEM_SOUND_URLS.notify;
|
const ACTION_SOUND_URL = withBase('sounds/action.ogg');
|
||||||
const FOOTSTEP_SOUND_URLS = Array.from({ length: 11 }, (_, index) => withBase(`sounds/step-${index + 1}.ogg`));
|
const FOOTSTEP_SOUND_URLS = Array.from({ length: 11 }, (_, index) => withBase(`sounds/step-${index + 1}.ogg`));
|
||||||
const FOOTSTEP_GAIN = 0.7;
|
const FOOTSTEP_GAIN = 0.7;
|
||||||
const TELEPORT_START_SOUND_URL = withBase('sounds/teleport_start.ogg');
|
const TELEPORT_START_SOUND_URL = withBase('sounds/teleport_start.ogg');
|
||||||
@@ -2803,8 +2803,8 @@ function handleAdminRolePermissionListModeInput(code: string, key: string): void
|
|||||||
if (control.type === 'select') {
|
if (control.type === 'select') {
|
||||||
const value = entries[adminRolePermissionIndex];
|
const value = entries[adminRolePermissionIndex];
|
||||||
if (value === '__delete_role__') {
|
if (value === '__delete_role__') {
|
||||||
if (role.name === 'admin') {
|
if (role.name === 'admin' || role.name === 'user') {
|
||||||
updateStatus('Admin role cannot be deleted.');
|
updateStatus('Admin and user roles cannot be deleted.');
|
||||||
audio.sfxUiCancel();
|
audio.sfxUiCancel();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -330,8 +330,8 @@ class AuthService:
|
|||||||
|
|
||||||
normalized_role = self._normalize_role_name(role_name)
|
normalized_role = self._normalize_role_name(role_name)
|
||||||
normalized_replacement = self._normalize_role_name(replacement_role_name)
|
normalized_replacement = self._normalize_role_name(replacement_role_name)
|
||||||
if normalized_role == "admin":
|
if normalized_role in {"admin", "user"}:
|
||||||
raise AuthError("Admin role cannot be deleted.")
|
raise AuthError("Admin and user roles cannot be deleted.")
|
||||||
if normalized_role == normalized_replacement:
|
if normalized_role == normalized_replacement:
|
||||||
raise AuthError("Replacement role must differ from deleted role.")
|
raise AuthError("Replacement role must differ from deleted role.")
|
||||||
|
|
||||||
|
|||||||
@@ -67,3 +67,14 @@ def test_login_missing_user_runs_dummy_verify(monkeypatch: pytest.MonkeyPatch, t
|
|||||||
assert calls[0][0] == "password99"
|
assert calls[0][0] == "password99"
|
||||||
finally:
|
finally:
|
||||||
service.close()
|
service.close()
|
||||||
|
|
||||||
|
|
||||||
|
def test_delete_role_rejects_admin_and_user(tmp_path: Path) -> None:
|
||||||
|
service = make_auth_service(tmp_path)
|
||||||
|
try:
|
||||||
|
with pytest.raises(AuthError):
|
||||||
|
service.delete_role("admin", "editor")
|
||||||
|
with pytest.raises(AuthError):
|
||||||
|
service.delete_role("user", "editor")
|
||||||
|
finally:
|
||||||
|
service.close()
|
||||||
|
|||||||
Reference in New Issue
Block a user