fix(simulation): use current user for stored schemes
Server CI/CD / docker-image (push) Successful in 23s
Server CI/CD / deploy-fallback-log (push) Has been skipped

This commit is contained in:
2026-07-17 16:49:20 +08:00
parent db6032bd84
commit 045d6c5b49
4 changed files with 92 additions and 7 deletions
+15 -3
View File
@@ -72,6 +72,7 @@ def burst_analysis(
modify_variable_pump_pattern: dict[str, list] = None,
modify_valve_opening: dict[str, float] = None,
scheme_name: str = None,
username: str | None = None,
) -> None:
"""
爆管模拟
@@ -86,6 +87,9 @@ def burst_analysis(
:param scheme_name: 方案名称
:return:
"""
if not username:
raise ValueError("username is required when storing burst analysis scheme")
scheme_detail: dict = {
"burst_ID": burst_ID,
"burst_size": burst_size,
@@ -211,7 +215,7 @@ def burst_analysis(
name=name,
scheme_name=scheme_name,
scheme_type="burst_analysis",
username="admin",
username=username,
scheme_start_time=modify_pattern_start_time,
scheme_detail=scheme_detail,
)
@@ -311,6 +315,7 @@ def flushing_analysis(
drainage_node_ID: str = None,
flushing_flow: float = 0,
scheme_name: str = None,
username: str | None = None,
) -> None:
"""
管道冲洗模拟
@@ -323,6 +328,9 @@ def flushing_analysis(
:param scheme_name: 方案名称
:return:
"""
if not username:
raise ValueError("username is required when storing flushing analysis scheme")
scheme_detail: dict = {
"duration": modify_total_duration,
"valve_opening": modify_valve_opening,
@@ -455,7 +463,7 @@ def flushing_analysis(
name=name,
scheme_name=scheme_name,
scheme_type="flushing_analysis",
username="admin",
username=username,
scheme_start_time=modify_pattern_start_time,
scheme_detail=scheme_detail,
)
@@ -473,6 +481,7 @@ def contaminant_simulation(
concentration: float, # 污染源浓度,单位mg/L
scheme_name: str = None,
source_pattern: str = None, # 污染源时间变化模式名称
username: str | None = None,
) -> None:
"""
污染模拟
@@ -486,6 +495,9 @@ def contaminant_simulation(
:param scheme_name: 方案名称
:return:
"""
if not username:
raise ValueError("username is required when storing contaminant analysis scheme")
scheme_detail: dict = {
"source": source,
"concentration": concentration,
@@ -608,7 +620,7 @@ def contaminant_simulation(
name=name,
scheme_name=scheme_name,
scheme_type="contaminant_analysis",
username="admin",
username=username,
scheme_start_time=modify_pattern_start_time,
scheme_detail=scheme_detail,
)
+8 -1
View File
@@ -4,8 +4,9 @@ import json
import os
import shutil
import threading
from fastapi import APIRouter, HTTPException, File, UploadFile, Query, Path, Body
from fastapi import APIRouter, Depends, HTTPException, File, UploadFile, Query, Path, Body
from fastapi.responses import PlainTextResponse
from app.auth.keycloak_dependencies import get_current_keycloak_username
import app.services.simulation as simulation
import app.services.globals as globals
from app.services.tjnetwork import (
@@ -209,6 +210,7 @@ async def fastapi_burst_analysis(
burst_size: list[float] = Query(..., description="对应各爆管点的爆管流量大小列表(L/s)"),
modify_total_duration: int = Query(..., description="模拟总时长(秒)"),
scheme_name: str = Query(..., description="分析方案名称"),
username: str = Depends(get_current_keycloak_username),
) -> str:
"""
爆管分析(高级版本)
@@ -229,6 +231,7 @@ async def fastapi_burst_analysis(
burst_size=burst_size,
modify_total_duration=modify_total_duration,
scheme_name=scheme_name,
username=username,
)
return "success"
@@ -314,6 +317,7 @@ async def fastapi_flushing_analysis(
flush_flow: float = Query(0, description="冲洗流量(L/s),0表示自动计算"),
duration: int | None = Query(None, description="模拟持续时间(秒),默认900秒"),
scheme_name: str = Query(..., description="冲洗方案名称"),
username: str = Depends(get_current_keycloak_username),
) -> str:
"""
冲洗分析(高级版本)
@@ -340,6 +344,7 @@ async def fastapi_flushing_analysis(
drainage_node_ID=drainage_node_ID,
flushing_flow=flush_flow,
scheme_name=scheme_name,
username=username,
)
return result or "success"
@@ -354,6 +359,7 @@ async def fastapi_contaminant_simulation(
duration: int = Query(..., description="模拟持续时间(秒)"),
scheme_name: str = Query(..., description="模拟方案名称"),
pattern: str | None = Query(None, description="污染源模式ID(可选)"),
username: str = Depends(get_current_keycloak_username),
) -> str:
"""
污染物模拟
@@ -376,6 +382,7 @@ async def fastapi_contaminant_simulation(
source=source,
concentration=concentration,
source_pattern=pattern,
username=username,
)
return result or "success"
+5 -1
View File
@@ -87,6 +87,7 @@ def burst_analysis(
modify_variable_pump_pattern: dict[str, list] = None,
modify_valve_opening: dict[str, float] = None,
scheme_name: str = None,
username: str | None = None,
) -> None:
"""
爆管模拟
@@ -101,6 +102,9 @@ def burst_analysis(
:param scheme_name: 方案名称
:return:
"""
if not username:
raise ValueError("username is required when storing burst analysis scheme")
scheme_detail: dict = {
"burst_ID": burst_ID,
"burst_size": burst_size,
@@ -225,7 +229,7 @@ def burst_analysis(
name=name,
scheme_name=scheme_name,
scheme_type="burst_Analysis",
username="admin",
username=username,
scheme_start_time=modify_pattern_start_time,
scheme_detail=scheme_detail,
)
+64 -2
View File
@@ -108,6 +108,12 @@ def _load_simulation_module(monkeypatch):
)
def _build_authenticated_client(module) -> TestClient:
app = build_test_app(module.router, "/api/v1")
app.dependency_overrides[module.get_current_keycloak_username] = lambda: "alice"
return TestClient(app)
def test_run_project_endpoint_returns_plain_text(monkeypatch):
module = _load_simulation_module(monkeypatch)
monkeypatch.setattr(module, "run_project", lambda network: f"report::{network}")
@@ -339,6 +345,33 @@ def test_valve_close_endpoint_passes_scheme_name(monkeypatch):
}
def test_burst_endpoint_passes_current_username(monkeypatch):
module = _load_simulation_module(monkeypatch)
captured = {}
def fake_burst_analysis(**kwargs):
captured.update(kwargs)
monkeypatch.setattr(module, "burst_analysis", fake_burst_analysis)
client = _build_authenticated_client(module)
response = client.get(
"/api/v1/burst_analysis/",
params={
"network": "demo",
"modify_pattern_start_time": "2025-01-02T03:04:05+08:00",
"burst_ID": ["P1"],
"burst_size": [10.0],
"modify_total_duration": 900,
"scheme_name": "burst_case_01",
},
)
assert response.status_code == 200
assert response.text == '"success"'
assert captured["username"] == "alice"
def test_flushing_endpoint_passes_required_scheme_name(monkeypatch):
module = _load_simulation_module(monkeypatch)
captured = {}
@@ -348,7 +381,7 @@ def test_flushing_endpoint_passes_required_scheme_name(monkeypatch):
return "ok"
monkeypatch.setattr(module, "flushing_analysis", fake_flushing_analysis)
client = TestClient(build_test_app(module.router, "/api/v1"))
client = _build_authenticated_client(module)
response = client.get(
"/api/v1/flushing_analysis/",
@@ -374,12 +407,41 @@ def test_flushing_endpoint_passes_required_scheme_name(monkeypatch):
"drainage_node_ID": "N1",
"flushing_flow": 100.0,
"scheme_name": "flush_case_01",
"username": "alice",
}
def test_contaminant_endpoint_passes_current_username(monkeypatch):
module = _load_simulation_module(monkeypatch)
captured = {}
def fake_contaminant_simulation(**kwargs):
captured.update(kwargs)
return "ok"
monkeypatch.setattr(module, "contaminant_simulation", fake_contaminant_simulation)
client = _build_authenticated_client(module)
response = client.get(
"/api/v1/contaminant_simulation/",
params={
"network": "demo",
"start_time": "2025-01-02T03:04:05+08:00",
"source": "N1",
"concentration": 10.0,
"duration": 900,
"scheme_name": "contaminant_case_01",
},
)
assert response.status_code == 200
assert response.text == "ok"
assert captured["username"] == "alice"
def test_contaminant_endpoint_requires_scheme_name(monkeypatch):
module = _load_simulation_module(monkeypatch)
client = TestClient(build_test_app(module.router, "/api/v1"))
client = _build_authenticated_client(module)
response = client.get(
"/api/v1/contaminant_simulation/",