91 lines
3.4 KiB
Python
91 lines
3.4 KiB
Python
"""Точка входа FastAPI."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
from alembic import command
|
|
from alembic.config import Config
|
|
from alembic.script import ScriptDirectory
|
|
from fastapi import FastAPI
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from sqlalchemy import inspect, text
|
|
|
|
from app.api.routes import admin, auth, journal, missions, onboarding, store, users
|
|
from app.core.config import settings
|
|
from app.db.session import engine
|
|
|
|
ALEMBIC_CONFIG = Path(__file__).resolve().parents[1] / "alembic.ini"
|
|
|
|
app = FastAPI(title=settings.project_name)
|
|
|
|
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=settings.backend_cors_origins,
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
|
|
def run_migrations() -> None:
|
|
"""Гарантируем, что база обновлена до последней схемы Alembic."""
|
|
|
|
config = Config(str(ALEMBIC_CONFIG))
|
|
config.set_main_option("sqlalchemy.url", str(settings.database_url))
|
|
inspector = inspect(engine)
|
|
script = ScriptDirectory.from_config(config)
|
|
head_revision = script.get_current_head()
|
|
|
|
tables = inspector.get_table_names()
|
|
current_revision: str | None = None
|
|
|
|
if "alembic_version" in tables:
|
|
with engine.begin() as conn:
|
|
row = conn.execute(text("SELECT version_num FROM alembic_version LIMIT 1")).fetchone()
|
|
current_revision = row[0] if row else None
|
|
|
|
if "alembic_version" not in tables or current_revision is None:
|
|
if tables:
|
|
# База создана через Base.metadata.create_all. Добавляем отсутствующие поля вручную
|
|
# и фиксируем версию как актуальную, чтобы последующие миграции применялись штатно.
|
|
user_columns = {col["name"] for col in inspector.get_columns("users")}
|
|
with engine.begin() as conn:
|
|
if "preferred_branch" not in user_columns:
|
|
conn.execute(text("ALTER TABLE users ADD COLUMN preferred_branch VARCHAR(160)"))
|
|
if "motivation" not in user_columns:
|
|
conn.execute(text("ALTER TABLE users ADD COLUMN motivation TEXT"))
|
|
conn.execute(text("CREATE TABLE IF NOT EXISTS alembic_version (version_num VARCHAR(32) NOT NULL)"))
|
|
conn.execute(text("DELETE FROM alembic_version"))
|
|
conn.execute(text("INSERT INTO alembic_version (version_num) VALUES (:rev)"), {"rev": head_revision})
|
|
return
|
|
# Таблиц ещё нет — создадим их миграциями.
|
|
command.upgrade(config, "head")
|
|
return
|
|
|
|
command.upgrade(config, "head")
|
|
|
|
|
|
@app.on_event("startup")
|
|
def on_startup() -> None:
|
|
"""Прогоняем миграции перед обработкой запросов."""
|
|
|
|
run_migrations()
|
|
|
|
|
|
app.include_router(auth.router)
|
|
app.include_router(users.router)
|
|
app.include_router(missions.router)
|
|
app.include_router(journal.router)
|
|
app.include_router(onboarding.router)
|
|
app.include_router(store.router)
|
|
app.include_router(admin.router)
|
|
|
|
|
|
@app.get("/", summary="Проверка работоспособности")
|
|
def healthcheck() -> dict[str, str]:
|
|
"""Простой ответ для Docker healthcheck."""
|
|
|
|
return {"status": "ok", "environment": settings.environment}
|