DispelEvilBot/admin/app.py

99 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Создание FastAPI-приложения админки."""
from __future__ import annotations
import logging
import secrets
from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from pathlib import Path
from fastapi import FastAPI
from fastapi.templating import Jinja2Templates
from starlette.middleware.sessions import SessionMiddleware
from admin.media import ensure_media
from admin.middleware import AdminAuthMiddleware
from admin.routes import admins, auth, health, logs, messages, pages, schedules, sequences, users
from common import __version__
from common.analytics import read as analytics_read
from common.config import AdminSettings, get_admin_settings
from common.db.pool import close_pool, init_pool
from common.logging_config import setup_logging
from common.repositories import admins_repo
BASE_DIR = Path(__file__).resolve().parent
TEMPLATES_DIR = BASE_DIR / "templates"
logger = logging.getLogger(__name__)
def create_app(settings: AdminSettings | None = None, *, init_db: bool = True) -> FastAPI:
"""Собрать приложение: настройки, шаблоны, роутеры.
Настройки можно передать явно (тесты); по умолчанию читаются из окружения.
``init_db=False`` — не открывать пул Postgres (юнит-тесты без БД).
"""
setup_logging()
settings = settings or get_admin_settings()
@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncIterator[None]:
if init_db:
await init_pool(app.state.settings)
ensure_media(app.state.settings)
try:
inserted = await admins_repo.ensure_admins(app.state.settings.admin_ids)
if inserted:
logger.info("Добавлены администраторы из ADMIN_IDS: %s", inserted)
except Exception:
logger.warning(
"Не удалось засеять администраторов (применены ли миграции?)",
exc_info=True,
)
try:
yield
finally:
if init_db:
await close_pool()
await analytics_read.close_client()
app = FastAPI(
title="DispelEvilBot Admin",
version=__version__,
# Swagger/OpenAPI наружу пока не нужны: админка закрыта логином (Блок 4.2).
docs_url=None,
redoc_url=None,
openapi_url=None,
lifespan=lifespan,
)
app.state.settings = settings
app.state.templates = Jinja2Templates(directory=str(TEMPLATES_DIR))
# Порядок важен: SessionMiddleware добавляется последним и оборачивает auth,
# поэтому request.session доступен в проверке администратора.
app.add_middleware(AdminAuthMiddleware)
session_secret = settings.admin_session_secret
if not session_secret:
session_secret = secrets.token_urlsafe(32)
logger.warning("ADMIN_SESSION_SECRET не задан — сессии слетят при перезапуске")
app.add_middleware(
SessionMiddleware,
secret_key=session_secret,
session_cookie="debot_admin",
max_age=settings.admin_session_max_age,
same_site="lax",
https_only=settings.is_prod,
)
app.include_router(health.router)
app.include_router(auth.router)
app.include_router(pages.router)
app.include_router(messages.router)
app.include_router(sequences.router)
app.include_router(schedules.router)
app.include_router(users.router)
app.include_router(admins.router)
app.include_router(logs.router)
return app