| 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
|
|
|