feat(api): standardize REST contracts and auth

This commit is contained in:
2026-07-30 20:38:51 +08:00
parent ae1a657554
commit ba947b616b
86 changed files with 54193 additions and 990 deletions
+4 -113
View File
@@ -1,17 +1,13 @@
import json
from pathlib import Path
from tempfile import NamedTemporaryFile
from uuid import UUID, uuid4
from fastapi import (
APIRouter,
Body,
Depends,
File,
Header,
HTTPException,
Path as ApiPath,
Query,
Request,
UploadFile,
status,
@@ -24,7 +20,7 @@ from app.auth.metadata_dependencies import (
from app.core.audit import AuditAction, log_audit_event
from app.infra.db.metadb.repositories.metadata_repository import MetadataRepository
from app.services.network_import import network_update
from app.services.tjnetwork import ChangeSet, import_inp, run_inp
from app.services.tjnetwork import run_inp
router = APIRouter()
@@ -145,7 +141,7 @@ async def _apply_model_update(content: bytes) -> None:
@router.post(
"/admin/projects/{project_id}/model/import",
"/admin/projects/{project_id}/model-imports",
summary="导入桌面端水力模型",
)
async def import_project_model(
@@ -168,8 +164,8 @@ async def import_project_model(
return {"project_id": str(project.id), "filename": filename, "result": result}
@router.post(
"/admin/projects/{project_id}/model/update",
@router.patch(
"/admin/projects/{project_id}/model-imports",
summary="更新桌面端水力模型",
)
async def update_project_model(
@@ -190,108 +186,3 @@ async def update_project_model(
action="update",
)
return {"project_id": str(project.id), "filename": filename, "updated": True}
@router.post("/importinp/", deprecated=True)
async def legacy_import_inp(
request: Request,
network: str = Query(...),
x_project_id: UUID = Header(..., alias="X-Project-Id"),
current_user=Depends(get_current_metadata_admin),
metadata_repo: MetadataRepository = Depends(get_metadata_repository),
):
project = await _get_active_project(x_project_id, metadata_repo)
if network != project.code:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Project scope denied",
)
payload = await request.json()
inp_text = payload.get("inp") if isinstance(payload, dict) else None
if not isinstance(inp_text, str):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Missing INP content",
)
_validate_inp_bytes(inp_text.encode("utf-8"), "model.inp")
result = import_inp(network, ChangeSet({"inp": inp_text}))
await _audit_model_change(
request=request,
current_user=current_user,
metadata_repo=metadata_repo,
project_id=project.id,
action="import",
)
return result
@router.post("/uploadinp/", deprecated=True)
async def legacy_upload_inp(
request: Request,
content: bytes = Body(...),
name: str = Query(...),
x_project_id: UUID = Header(..., alias="X-Project-Id"),
current_user=Depends(get_current_metadata_admin),
metadata_repo: MetadataRepository = Depends(get_metadata_repository),
) -> bool:
project = await _get_active_project(x_project_id, metadata_repo)
safe_name = Path(name).name
if safe_name != name:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Invalid INP file name",
)
_validate_inp_bytes(content, safe_name)
target_dir = Path("data")
target_dir.mkdir(parents=True, exist_ok=True)
(target_dir / safe_name).write_bytes(content)
await _audit_model_change(
request=request,
current_user=current_user,
metadata_repo=metadata_repo,
project_id=project.id,
action="upload",
)
return True
@router.post("/network_project/", deprecated=True)
async def legacy_network_project(
request: Request,
file: UploadFile = File(...),
x_project_id: UUID = Header(..., alias="X-Project-Id"),
current_user=Depends(get_current_metadata_admin),
metadata_repo: MetadataRepository = Depends(get_metadata_repository),
):
project = await _get_active_project(x_project_id, metadata_repo)
content, _ = await _read_upload(file)
result = await _run_uploaded_inp(content)
await _audit_model_change(
request=request,
current_user=current_user,
metadata_repo=metadata_repo,
project_id=project.id,
action="import",
)
return result
@router.post("/network_update/", deprecated=True)
async def legacy_network_update(
request: Request,
file: UploadFile = File(...),
x_project_id: UUID = Header(..., alias="X-Project-Id"),
current_user=Depends(get_current_metadata_admin),
metadata_repo: MetadataRepository = Depends(get_metadata_repository),
) -> str:
project = await _get_active_project(x_project_id, metadata_repo)
content, _ = await _read_upload(file)
await _apply_model_update(content)
await _audit_model_change(
request=request,
current_user=current_user,
metadata_repo=metadata_repo,
project_id=project.id,
action="update",
)
return json.dumps({"message": "管网更新成功"})