034 Публикация стенда как https://rxipam.rxmsk.ru через общий Caddy хоста (Caddyfile вне репозитория): UI и /api/v1 доступны из интернета, /docs, /redoc, /openapi.json — только из частных сетей (RFC 1918/4193, loopback). Caddy проксирует на опубликованный порт приложения — общая Docker-сеть отклонена из-за коллизии имён app/db с Nextcloud. TRUSTED_PROXIES=172.16.0.0/12: реальный IP клиента из X-Forwarded-For. Интеграционный тест журнала больше не проверяет подделку XFF с хоста (хост за Caddy доверенный), логику покрывает unit-тест. 035 Дата и IP последнего входа в разделе «Пользователи»: users.last_login_at / last_login_ip (миграция 0014 с заполнением из журнала), запись при успешном входе, UserOut, колонка в UI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3.1 KiB
3.1 KiB
Итог: последний вход пользователя — дата и IP (изменение 035)
План: PLAN.md. В разделе «Пользователи» появилась колонка «Последний вход»: дата (UTC) и IP последнего успешного входа.
Что сделано
| Файл | Изменение |
|---|---|
app/models.py |
User.last_login_at (timestamptz), User.last_login_ip (INET), nullable |
alembic/versions/0014_users_last_login.py |
Колонки и перенос данных из журнала: последнее событие session.login на логин. Если журнал ротирован или очищен — NULL |
app/api/v1/auth.py |
Успешный вход записывает last_login_at = now() и last_login_ip в той же транзакции, что и session.login. IP — тот же, что в журнале (реальный клиент за Caddy, изменение 034). Неудачные попытки поля не трогают |
app/schemas.py |
UserOut.last_login_at, UserOut.last_login_ip. INET приводится к строке через field_validator с существующей ip_text(). Поля видны в /users (только superadmin) и в /auth/me (свои) |
web/app.js |
Колонка «Последний вход» после «Статус»: дата и IP моноширинным шрифтом, «—», если входа не было |
tests/test_users.py |
В test_users_management: после входа созданного пользователя поля заполнены в GET /users |
README.md |
«Интерфейс», миграции 0001–0014, строка 035 в истории |
Проверки
- Стенд пересобран:
alembic current—0014,alembic check— чисто, откат до 0013 и повторный upgrade — без ошибок. - Перенос данных: у
tstarkдата и IP (192.168.5.253) совпадают с последнимsession.loginв журнале; уsbas-saвходов не было —NULL. - Временный
viewer(создан и удалён через SQL): вход через Caddy с LAN-адреса хоста далlast_login_ip = 192.168.5.9и дату входа, в JSON — строки. Неудачная попытка поля не изменила. node --check web/app.js,import app.main— чисто.pytest -q— 15 passed. Перед прогоном учётная записьadminиз.env(удалена через UI в 08:54, фикстураclientбез неё не работает) создана заново через SQL какsuperadminс паролем из.env; попытки входа под удалённымadmin(блокировка «логин + IP») очищены. Создание через SQL в журнал не попало.
Не проверено
- Колонка в браузере — не просматривалась.