Files
ipam_control/docs/changes/006-users-management/SUMMARY.md
T
ayurishchevandClaude Sonnet 5 cd09ef0805 Задачи 006-010: пользователи, исправление удаления, журнал отказов, групповые операции, автовыделение префиксов
006 Пользователи: API /users (CRUD, смена своего пароля), раздел UI «Пользователи»,
    события журнала user.*, защита от отключения/удаления себя и последнего админа.
007 Исправление удаления организации: VRF удаляются явным DELETE до организации
    (без relationship() порядок DELETE не гарантирован → ложный 409).
008 Журнал фиксирует отказы в удалении (<entity>.delete_blocked) со списком
    мешающих объектов в «Данных»: организация, VRF, тип устройства, префикс, пользователь.
009 Выбор строк чекбоксами и групповые операции в UI (удаление, смена типа устройств,
    статус префиксов и адресов, доступ пользователей); цикл запросов из UI, итог и список отказов.
010 Автовыделение следующего вложенного префикса: POST/GET /prefixes/{id}/subnets/next,
    первый свободный выровненный блок; пункт «Добавить вложенный (авто)» в меню префикса.

Тесты: 14 (добавлены сценарии для 006, 007/008, 010); исправлена нестабильность
тестов журнала (IPv6-группы с ведущими нулями нормализуются PostgreSQL).
Документация: README.md, docs/changes/006-010 (планы и итоги).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 13:25:33 +03:00

5.8 KiB
Raw Blame History

Итог: раздел интерфейса «Пользователи» (изменение 006)

Что сделано

  • API /api/v1/users (app/api/v1/users.py, роутер подключён в app/main.py): GET /users (поиск по логину, limit/offset), POST /users, PATCH /users/{id}, DELETE /users/{id} — только admin; POST /users/me/password — смена своего пароля любой ролью с подтверждением текущего.
  • Схемы (app/schemas.py): UserIn, UserUpdate, PasswordChange, UserOut (id, username, role, is_active); валидатор логина (Login, 3–100 символов, [A-Za-z0-9._-]) и запрет служебных логинов system/anonymous.
  • Журнал: сущность user добавлена в словарь сообщений (app/services.py), события user.created, user.updated, user.password_reset («пароль изменён администратором» / «пароль изменён пользователем»), user.deleted; в diff — только изменённые поля, для пароля — пометка «изменён» без значения. В UI — подпись «Пользователь» и цвет бейджа для password_reset.
  • UI (web/app.js): пункт навигации «Пользователи» (только у администратора), экран со счётчиком, поиском и таблицей «Логин · Роль · Статус» (строка кликабельна, меню «⋯»: редактировать, отключить/разрешить доступ, удалить), окно создания и редактирования (логин после создания не редактируется, необязательный «Новый пароль», флажок «Доступ разрешён»), кнопка «Сменить пароль» в шапке, заглушка для не-администратора при ручном вводе #/users.
  • Тест tests/test_users.py — один сквозной сценарий.
  • Документация: обновлён README.md, план и итог в docs/changes/006-users-management/.

Поведение

Ситуация Ответ
Логин занят (в т. ч. в другом регистре) 409 «Пользователь с таким логином уже существует»
Логин system/anonymous, короче 3 символов, пароль короче 8 422 с указанием поля
viewer читает /users или что-либо изменяет 403
PATCH/DELETE своей учётной записи (роль, доступ, удаление) 409
Отключение или удаление последнего активного администратора 409
Неверный текущий пароль при смене своего пароля 403
Новый пароль совпадает с текущим 422

Действие ролей

  • admin — полный доступ, включая управление пользователями и запись данных.
  • viewer — чтение всех справочников, реестра, журнала и обзора; запись (403) и раздел «Пользователи» недоступны.
  • Отключение учётной записи действует немедленно: токен проверяется по users.is_active в current_user.
  • Смена пароля не отзывает уже выданные токены (JWT без списка отзыва) — они действуют до истечения JWT_TTL_MINUTES.

Инварианты

  • Схема БД не менялась: таблица users (миграция 0001) уже содержит username, password_hash, role, is_active.
  • Пароли хранятся только в виде argon2-хэша; значение пароля никогда не попадает в журнал.
  • Логин не меняется: он же sub в JWT; переименование = создание новой записи.
  • Логин уникален, в том числе без учёта регистра; служебные акторы журнала зарезервированы.
  • Перед каждым изменением проверяется, что в системе останется хотя бы один активный администратор.

Проверка

  • Python: python3 -m py_compile по изменённым модулям — без ошибок; автоматическая проверка после правок — успешно.
  • Интеграционный тест: docker compose up -d --build && venv/bin/python -m pytest tests/test_users.py -q (создание viewer, запреты 403/409/422, вход, отключение с немедленным отзывом токена, сброс пароля администратором, смена своего пароля, защита своей записи и последнего администратора, удаление, записи в журнале).
  • Ручной сценарий в UI: вход администратором → «Пользователи» → создание viewer → вход в другом окне → отключение (вход и текущая сессия отбиваются) → сброс пароля → вход с новым паролем → «Сменить пароль» в шапке.