refactor: split system and serving routes
This commit is contained in:
@@ -21,12 +21,11 @@ import ezdxf
|
||||
from ezdxf import recover
|
||||
from fastapi import FastAPI, File, Form, Header, HTTPException, Request, UploadFile
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import FileResponse, HTMLResponse, Response
|
||||
from fastapi.responses import HTMLResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from openpyxl import load_workbook
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from .admin_db_status import fetch_db_status_snapshot, fetch_db_table_preview
|
||||
from .config import BASE_DIR, LEGACY_DIR, MOCK_LOGIN_ENABLED, UPLOAD_DIR
|
||||
from .db import get_conn, init_db
|
||||
from .ledger_runtime import (
|
||||
@@ -34,6 +33,7 @@ from .ledger_runtime import (
|
||||
build_ledger_index_response,
|
||||
sync_default_business_ledger_source,
|
||||
)
|
||||
from .system_routes import register_system_routes
|
||||
|
||||
|
||||
app = FastAPI(title="MH Dashboard Organization API")
|
||||
@@ -3934,55 +3934,19 @@ def startup() -> None:
|
||||
|
||||
app.mount("/legacy/static", StaticFiles(directory=LEGACY_STATIC_DIR, check_dir=False), name="legacy-static")
|
||||
|
||||
|
||||
@app.get("/api/health")
|
||||
def health() -> dict[str, object]:
|
||||
checks = {
|
||||
"upload_dir": UPLOAD_DIR.exists(),
|
||||
}
|
||||
|
||||
try:
|
||||
member_count = get_member_count()
|
||||
checks["database"] = True
|
||||
except Exception:
|
||||
member_count = None
|
||||
checks["database"] = False
|
||||
|
||||
status = "ok" if all(checks.values()) else "degraded"
|
||||
return {
|
||||
"status": status,
|
||||
"checks": checks,
|
||||
"member_count": member_count,
|
||||
"timestamp": datetime.utcnow().isoformat() + "Z",
|
||||
}
|
||||
|
||||
|
||||
@app.get("/api/admin/db-status")
|
||||
def admin_db_status() -> dict[str, object]:
|
||||
return fetch_db_status_snapshot()
|
||||
|
||||
|
||||
@app.get("/api/admin/db-status/table")
|
||||
def admin_db_status_table(schema: str, table: str, limit: int = 50) -> dict[str, object]:
|
||||
return fetch_db_table_preview(schema, table, limit)
|
||||
|
||||
|
||||
@app.get("/admin/db-status")
|
||||
def admin_db_status_view() -> FileResponse:
|
||||
target = DB_STATUS_SERVED_DIR / "index.html"
|
||||
if not target.exists():
|
||||
raise HTTPException(status_code=404, detail="DB status dashboard file not found.")
|
||||
response = FileResponse(target)
|
||||
response.headers["Cache-Control"] = "no-store, no-cache, must-revalidate, max-age=0"
|
||||
response.headers["Pragma"] = "no-cache"
|
||||
return response
|
||||
|
||||
|
||||
@app.get("/api/integration/business-ledger-default")
|
||||
def integration_business_ledger_default() -> Response:
|
||||
with get_conn() as conn:
|
||||
with conn.cursor() as cur:
|
||||
return build_business_ledger_default_response(cur)
|
||||
register_system_routes(
|
||||
app,
|
||||
upload_dir=UPLOAD_DIR,
|
||||
legacy_dir=LEGACY_DIR,
|
||||
incoming_files_dir=INCOMING_FILES_DIR,
|
||||
incoming_served_dir=INCOMING_SERVED_DIR,
|
||||
db_status_served_dir=DB_STATUS_SERVED_DIR,
|
||||
business_ledger_index_path=BUSINESS_LEDGER_INDEX_PATH,
|
||||
get_member_count=get_member_count,
|
||||
get_conn=get_conn,
|
||||
build_business_ledger_default_response=build_business_ledger_default_response,
|
||||
build_ledger_index_response=build_ledger_index_response,
|
||||
)
|
||||
|
||||
|
||||
@app.post("/api/auth/login")
|
||||
@@ -4307,18 +4271,6 @@ def integration_mh_source() -> dict[str, object]:
|
||||
return fetch_mh_source_rows()
|
||||
|
||||
|
||||
@app.get("/api/integration/mh-workbook")
|
||||
def integration_mh_workbook() -> FileResponse:
|
||||
target = INCOMING_FILES_DIR / "MH.xlsx"
|
||||
if not target.exists():
|
||||
raise HTTPException(status_code=404, detail="MH workbook not found.")
|
||||
return FileResponse(
|
||||
target,
|
||||
media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
filename="MH.xlsx",
|
||||
)
|
||||
|
||||
|
||||
@app.post("/api/uploads/profile-photo")
|
||||
def upload_profile_photo(file: UploadFile = File(...), member_name: str = Form("")) -> dict[str, str]:
|
||||
suffix = Path(file.filename or "").suffix.lower()
|
||||
@@ -4526,52 +4478,3 @@ def get_seat_map_viewer(seat_map_id: int, as_of: str | None = None) -> HTMLRespo
|
||||
@app.put("/api/seat-maps/{seat_map_id}/layout")
|
||||
def update_seat_layout(seat_map_id: int, payload: SeatLayoutPayload) -> dict[str, list[dict[str, object]]]:
|
||||
return {"items": save_seat_layout(seat_map_id, payload)}
|
||||
|
||||
|
||||
@app.get("/legacy/organization")
|
||||
def legacy_organization() -> FileResponse:
|
||||
target = LEGACY_DIR / "DashBoard-organization.html"
|
||||
if not target.exists():
|
||||
raise HTTPException(status_code=404, detail="Legacy dashboard file not found.")
|
||||
return FileResponse(target)
|
||||
|
||||
|
||||
@app.get("/legacy/organization-backup")
|
||||
def legacy_organization_backup() -> FileResponse:
|
||||
target = LEGACY_DIR / "DashBoard-organization-backup.html"
|
||||
if not target.exists():
|
||||
raise HTTPException(status_code=404, detail="Legacy dashboard backup not found.")
|
||||
return FileResponse(target)
|
||||
|
||||
|
||||
@app.get("/integrations/payment")
|
||||
def integration_payment() -> FileResponse:
|
||||
# 8081 phase-1 cleanup: integration HTML is served only from incoming-files/served.
|
||||
target = INCOMING_SERVED_DIR / "payment.html"
|
||||
if not target.exists():
|
||||
raise HTTPException(status_code=404, detail="Payment integration file not found.")
|
||||
return FileResponse(target)
|
||||
|
||||
|
||||
@app.get("/integrations/ledger")
|
||||
def integration_ledger() -> FileResponse:
|
||||
# #21 phase-1: runtime no longer decodes reference wrapper HTML. Serve the promoted
|
||||
# ledger entry file from incoming-files/served/ledger only.
|
||||
return build_ledger_index_response(BUSINESS_LEDGER_INDEX_PATH)
|
||||
|
||||
|
||||
@app.get("/integrations/mh")
|
||||
def integration_mh() -> FileResponse:
|
||||
# Keep the served path explicit so comparison/reference copies are never picked up by accident.
|
||||
target = INCOMING_SERVED_DIR / "mh.html"
|
||||
if not target.exists():
|
||||
raise HTTPException(status_code=404, detail="MH integration file not found.")
|
||||
return FileResponse(target)
|
||||
|
||||
|
||||
@app.get("/uploads/{filename}")
|
||||
def get_upload(filename: str) -> FileResponse:
|
||||
target = UPLOAD_DIR / filename
|
||||
if not target.exists():
|
||||
raise HTTPException(status_code=404, detail="Upload not found.")
|
||||
return FileResponse(target)
|
||||
|
||||
120
backend/app/system_routes.py
Normal file
120
backend/app/system_routes.py
Normal file
@@ -0,0 +1,120 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Callable
|
||||
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from fastapi.responses import FileResponse, Response
|
||||
|
||||
from .admin_db_status import fetch_db_status_snapshot, fetch_db_table_preview
|
||||
|
||||
|
||||
def register_system_routes(
|
||||
app: FastAPI,
|
||||
*,
|
||||
upload_dir: Path,
|
||||
legacy_dir: Path,
|
||||
incoming_files_dir: Path,
|
||||
incoming_served_dir: Path,
|
||||
db_status_served_dir: Path,
|
||||
business_ledger_index_path: Path,
|
||||
get_member_count: Callable[[], int],
|
||||
get_conn,
|
||||
build_business_ledger_default_response: Callable[[object], Response],
|
||||
build_ledger_index_response: Callable[[Path], FileResponse],
|
||||
) -> None:
|
||||
@app.get("/api/health")
|
||||
def health() -> dict[str, object]:
|
||||
checks = {
|
||||
"upload_dir": upload_dir.exists(),
|
||||
}
|
||||
|
||||
try:
|
||||
member_count = get_member_count()
|
||||
checks["database"] = True
|
||||
except Exception:
|
||||
member_count = None
|
||||
checks["database"] = False
|
||||
|
||||
status = "ok" if all(checks.values()) else "degraded"
|
||||
return {
|
||||
"status": status,
|
||||
"checks": checks,
|
||||
"member_count": member_count,
|
||||
"timestamp": datetime.utcnow().isoformat() + "Z",
|
||||
}
|
||||
|
||||
@app.get("/api/admin/db-status")
|
||||
def admin_db_status() -> dict[str, object]:
|
||||
return fetch_db_status_snapshot()
|
||||
|
||||
@app.get("/api/admin/db-status/table")
|
||||
def admin_db_status_table(schema: str, table: str, limit: int = 50) -> dict[str, object]:
|
||||
return fetch_db_table_preview(schema, table, limit)
|
||||
|
||||
@app.get("/admin/db-status")
|
||||
def admin_db_status_view() -> FileResponse:
|
||||
target = db_status_served_dir / "index.html"
|
||||
if not target.exists():
|
||||
raise HTTPException(status_code=404, detail="DB status dashboard file not found.")
|
||||
response = FileResponse(target)
|
||||
response.headers["Cache-Control"] = "no-store, no-cache, must-revalidate, max-age=0"
|
||||
response.headers["Pragma"] = "no-cache"
|
||||
return response
|
||||
|
||||
@app.get("/api/integration/business-ledger-default")
|
||||
def integration_business_ledger_default() -> Response:
|
||||
with get_conn() as conn:
|
||||
with conn.cursor() as cur:
|
||||
return build_business_ledger_default_response(cur)
|
||||
|
||||
@app.get("/api/integration/mh-workbook")
|
||||
def integration_mh_workbook() -> FileResponse:
|
||||
target = incoming_files_dir / "MH.xlsx"
|
||||
if not target.exists():
|
||||
raise HTTPException(status_code=404, detail="MH workbook not found.")
|
||||
return FileResponse(
|
||||
target,
|
||||
media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
filename="MH.xlsx",
|
||||
)
|
||||
|
||||
@app.get("/legacy/organization")
|
||||
def legacy_organization() -> FileResponse:
|
||||
target = legacy_dir / "DashBoard-organization.html"
|
||||
if not target.exists():
|
||||
raise HTTPException(status_code=404, detail="Legacy dashboard file not found.")
|
||||
return FileResponse(target)
|
||||
|
||||
@app.get("/legacy/organization-backup")
|
||||
def legacy_organization_backup() -> FileResponse:
|
||||
target = legacy_dir / "DashBoard-organization-backup.html"
|
||||
if not target.exists():
|
||||
raise HTTPException(status_code=404, detail="Legacy dashboard backup not found.")
|
||||
return FileResponse(target)
|
||||
|
||||
@app.get("/integrations/payment")
|
||||
def integration_payment() -> FileResponse:
|
||||
target = incoming_served_dir / "payment.html"
|
||||
if not target.exists():
|
||||
raise HTTPException(status_code=404, detail="Payment integration file not found.")
|
||||
return FileResponse(target)
|
||||
|
||||
@app.get("/integrations/ledger")
|
||||
def integration_ledger() -> FileResponse:
|
||||
return build_ledger_index_response(business_ledger_index_path)
|
||||
|
||||
@app.get("/integrations/mh")
|
||||
def integration_mh() -> FileResponse:
|
||||
target = incoming_served_dir / "mh.html"
|
||||
if not target.exists():
|
||||
raise HTTPException(status_code=404, detail="MH integration file not found.")
|
||||
return FileResponse(target)
|
||||
|
||||
@app.get("/uploads/{filename}")
|
||||
def get_upload(filename: str) -> FileResponse:
|
||||
target = upload_dir / filename
|
||||
if not target.exists():
|
||||
raise HTTPException(status_code=404, detail="Upload not found.")
|
||||
return FileResponse(target)
|
||||
Reference in New Issue
Block a user