from __future__ import annotations from datetime import timedelta from fastapi import FastAPI, Request from fastapi.staticfiles import StaticFiles from starlette.middleware.sessions import SessionMiddleware from app.auth import get_current_admin, get_current_user from app.config import ROOT_DIR, settings from app.database import SessionLocal from app.routes import admin, auth, media, user from app.services.bootstrap import initialize_database, seed_super_admin from app.web import redirect, templates app = FastAPI(title=settings.app_name) app.add_middleware(SessionMiddleware, secret_key=settings.session_secret, same_site="lax") app.mount("/static", StaticFiles(directory=str(ROOT_DIR / "app" / "static")), name="static") @app.on_event("startup") def on_startup() -> None: initialize_database() db = SessionLocal() try: seed_super_admin(db) finally: db.close() @app.middleware("http") async def apply_response_policies(request: Request, call_next): response = await call_next(request) if request.url.path.startswith("/static"): response.headers["Cache-Control"] = "no-store" return response @app.get("/") def index(request: Request): db = SessionLocal() try: if get_current_admin(request, db): return redirect("/admin/dashboard") if get_current_user(request, db): return redirect("/dashboard") finally: db.close() return redirect("/login") @app.get("/health") def health(): return {"status": "ok"} @app.get("/favicon.ico", include_in_schema=False) def favicon(): return redirect("/static/favicon.ico", status_code=307) app.include_router(auth.router) app.include_router(user.router) app.include_router(admin.router) app.include_router(media.router) def format_datetime(value): if not value: return "-" return value.strftime("%Y-%m-%d %H:%M") def format_timedelta(value): if value is None: return "-" if isinstance(value, int): minutes = value elif isinstance(value, timedelta): minutes = int(value.total_seconds() // 60) else: return str(value) hours, mins = divmod(minutes, 60) if hours: return f"{hours}小时 {mins}分钟" return f"{mins}分钟" templates.env.filters["datetime_local"] = format_datetime templates.env.filters["duration_human"] = format_timedelta