import logging from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from app.config import settings from app.db.database import create_tables from app.api import auth, users, classes, directory, timeline, schedule, upload logging.basicConfig( level=logging.DEBUG if settings.debug else logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s", ) logger = logging.getLogger(__name__) async def ensure_super_admin(): """Seed super admin on first run.""" from sqlalchemy import select from app.db.database import async_session from app.db.models import User from app.core.auth import hash_password async with async_session() as db: result = await db.execute(select(User).where(User.role == "super_admin")) if result.scalar_one_or_none() is None: admin = User( email=settings.super_admin_email, password_hash=hash_password(settings.super_admin_password), name="Super Admin", role="super_admin", status="approved", ) db.add(admin) await db.commit() logger.info("Super admin seeded: %s", settings.super_admin_email) async def ensure_sample_class(): """Seed a sample class if none exists.""" from sqlalchemy import select, func from app.db.database import async_session from app.db.models import Class_ async with async_session() as db: result = await db.execute(select(func.count(Class_.id))) count = result.scalar() if count == 0: sample = Class_( name="HKU ICB Sample Class", cohort_year=2025, description="Sample class for testing", ) db.add(sample) await db.commit() logger.info("Sample class seeded") @asynccontextmanager async def lifespan(app: FastAPI): await create_tables() await ensure_super_admin() await ensure_sample_class() yield app = FastAPI( title="ClassHub", description="HKU ICB Graduate Class Resource Platform", version="1.0.0", lifespan=lifespan, ) app.add_middleware( CORSMiddleware, allow_origins=[settings.frontend_url, "http://localhost:3000"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) app.include_router(auth.router) app.include_router(users.router) app.include_router(classes.router) app.include_router(directory.router) app.include_router(timeline.router) app.include_router(schedule.router) app.include_router(upload.router) @app.get("/api/health") async def health(): return {"status": "ok", "service": "classhub"}