from contextlib import asynccontextmanager from pathlib import Path from fastapi import APIRouter, Body, Depends, FastAPI, HTTPException from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from sqlalchemy import text from sqlalchemy.orm import Session from core.config import settings from core.db import get_db from core.loader import load_apps from core.redis_client import redis_client from core.security import require_admin from core.settings_service import get_setting_cached, set_setting @asynccontextmanager async def lifespan(app: FastAPI): loaded = load_apps(app) app.state.loaded_apps = loaded yield app = FastAPI(title="Shopsystem API", lifespan=lifespan) app.add_middleware( CORSMiddleware, allow_origins=settings.cors_list, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Static uploads upload_dir = Path(settings.UPLOAD_DIR) upload_dir.mkdir(parents=True, exist_ok=True) app.mount("/uploads", StaticFiles(directory=str(upload_dir)), name="uploads") @app.get("/health") def health(db: Session = Depends(get_db)): db_ok = False redis_ok = False try: db.execute(text("SELECT 1")) db_ok = True except Exception: pass try: redis_ok = bool(redis_client.ping()) except Exception: pass return { "ok": db_ok and redis_ok, "env": settings.APP_ENV, "db": db_ok, "redis": redis_ok, "apps": [m.name for m in getattr(app.state, "loaded_apps", [])], } # Core router — settings management (admin) core_router = APIRouter() @core_router.get("/settings/{key}") def read_setting(key: str): """Public read — Redis-backed.""" v = get_setting_cached(key) if v is None: raise HTTPException(404, f"Setting {key} not found") return {"key": key, "value": v} @core_router.put("/settings/{key}") def write_setting( key: str, body: dict = Body(...), _: dict = Depends(require_admin), db: Session = Depends(get_db), ): if "value" not in body: raise HTTPException(400, "Missing 'value' in body") set_setting(db, key, body["value"]) return {"key": key, "value": body["value"]} app.include_router(core_router, prefix="/api/core", tags=["core"])