Add role management validation to prevent removal of the last admin
- Introduced a new error, `CannotRemoveLastAdmin`, to handle attempts to downgrade the last admin user in the system. - Updated `RoleService` to check the number of admin users before allowing a role change that would remove the last admin. - Enhanced unit tests to verify the new behavior, ensuring that attempts to downgrade the last admin correctly propagate the failure. - Updated API documentation to reflect the new validation logic and its implications for role management.
This commit is contained in:
@@ -281,6 +281,14 @@ UI **настойчиво напоминает** привязать его (ед
|
||||
конфигов больше новой квоты — существующие конфиги сохраняются, но **создание новых блокируется**,
|
||||
пока число активных не станет меньше квоты. Форс-отзыв лишних не делаем.
|
||||
|
||||
**Нельзя снять `admin` с последнего администратора**: `IRoleService.ChangeUserRoleAsync` перед сменой
|
||||
роли проверяет — если у пользователя сейчас `admin`, а новая роль другая, и админов в системе ровно
|
||||
один — `RoleErrors.CannotRemoveLastAdmin` (409), смены не происходит. Единая точка защиты — работает
|
||||
и при прямой смене роли из `/admin/users`, и при одобрении заявки на роль через `SupportTicket`
|
||||
(`ApproveRoleRequestCommandHandler` вызывает тот же `ChangeUserRoleAsync`), в том числе когда админ
|
||||
одобряет заявку на понижение самому себе — этот путь специально не блокируется отдельно, чтобы не
|
||||
плодить тикеты, которые некому обработать, если админ единственный.
|
||||
|
||||
### ActivationRequest — запрос активации
|
||||
Пользователь просит активацию у админа; админ одобряет/отклоняет на сайте или в Telegram.
|
||||
|
||||
@@ -355,6 +363,12 @@ UI **настойчиво напоминает** привязать его (ед
|
||||
- Доступ — только активированному пользователю (`IRequiresActivation`, как и у конфигов/новостей);
|
||||
админские действия (resolve/close/approve/reject) идут по отдельным `/api/admin/support/*` с
|
||||
ролевой проверкой, без завязки на активацию.
|
||||
- Resolve/close/reject **собственного** тикета админом разрешены — они не трогают роль, риска нет
|
||||
(запрет ломал бы самообслуживание: тикет единственного админа застревал бы в `Open` навсегда, убрать
|
||||
некому). Единственное действие с реальным риском — approve заявки на роль, потому что оно меняет
|
||||
роль заявителя; его самостоятельная защита не нужна — она уже есть на уровень ниже, см. `AppRole`
|
||||
(`RoleErrors.CannotRemoveLastAdmin`), и одинаково работает что для approve своей заявки, что для
|
||||
прямой смены роли через `/admin/users`.
|
||||
- `Closed`-тикеты не удаляются автоматически — админ может подчистить их вручную (вкладка
|
||||
«Обслуживание», `DELETE /api/admin/maintenance/tickets/closed`), это удаляет и `TicketComment`/
|
||||
`TicketAttachment` (+ файлы на диске), необратимо.
|
||||
|
||||
Reference in New Issue
Block a user