v0.1 - макет интерфейса, аутентификация через логин, аккаунт админа, создание партии в 2 этапа, базовые настройки профиля и группы, переключение между группами, статистика

This commit is contained in:
2026-06-16 17:41:06 +03:00
parent 6ab74f01aa
commit 56b5d09a4d
123 changed files with 13572 additions and 21 deletions
+65
View File
@@ -0,0 +1,65 @@
"""Идемпотентный бутстрап: справочники + учётная запись администратора.
Запуск: `python -m app.bootstrap` (вызывается из entrypoint.sh после миграций).
"""
from __future__ import annotations
from sqlmodel import Session, select
from app.core.config import settings
from app.core.security import hash_password, verify_password
from app.db.session import engine
from app.models import User
from app.seed.reference_data import seed_reference_data
def _ensure_admin(session: Session) -> None:
if not settings.admin_bootstrap_enabled:
return
password = (settings.admin_password or "").strip()
username = (settings.admin_username or "admin").strip()
existing = session.exec(select(User).where(User.role == "admin")).first()
if existing is None:
if not password:
raise RuntimeError("Отказ создавать администратора без пароля (ADMIN_PASSWORD пуст).")
# Логин администратора = его никнейм (отдельной таблицы админов нет).
session.add(
User(
nickname=username,
role="admin",
auth_provider="local",
password_hash=hash_password(password),
)
)
session.commit()
print(f"[bootstrap] Создан администратор: {username}")
return
# Администратор уже существует.
if not settings.is_development:
# В test/prod пароль НЕ перезаписываем (мог быть изменён через панель).
return
# DEV: подтягиваем логин/пароль из .env (env — источник истины в деве).
changed: list[str] = []
if password and not verify_password(password, existing.password_hash or ""):
existing.password_hash = hash_password(password)
changed.append("пароль")
if username and existing.nickname != username:
existing.nickname = username
changed.append("логин")
if changed:
session.add(existing)
session.commit()
print(f"[bootstrap] DEV: администратор обновлён из .env ({', '.join(changed)})")
def bootstrap() -> None:
with Session(engine) as session:
seed_reference_data(session) # идемпотентно
_ensure_admin(session)
if __name__ == "__main__":
bootstrap()