fix(511-B /calc 경로 막기): 계산 창구가 브라우저 파일 경로를 안 씀 — 단계 격자 = {model_id · smooth · design} → 서버가 그 프로젝트 storage 안 DTM 격자 경로로 갈음(dtm_grid_npz · read_surface_grid 와 한 벌 · storage 밖 = 거절) · 경로 칸(stages.grid.path · stations.grid) = 400 · 창구 묶음 안 파일 읽기 = gridAt 하나 · 시험 test_511_b_calc_path_guard — 요구 320-4
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -199,6 +199,32 @@ def _design_grid(
|
||||
}
|
||||
|
||||
|
||||
async def dtm_grid_npz(connection, project_id: UUID, model_id: int, smooth: bool) -> Path:
|
||||
"""그 프로젝트 DTM 모델의 npz(평활 고르기 = 서버 표본기와 같음) — 없으면 LookupError(까닭).
|
||||
|
||||
경로 = 프로젝트 storage 안 DB 상대 경로만(밖으로 나가면 LookupError · 계산 창구 `/calc` 도 씀).
|
||||
"""
|
||||
stored = await get_project_storage_relative_path(connection, project_id)
|
||||
async with connection.cursor() as cursor:
|
||||
await cursor.execute(
|
||||
"SELECT model_type, model_file_path FROM surface_models"
|
||||
" WHERE id = %s AND project_id = %s",
|
||||
(model_id, str(project_id)),
|
||||
)
|
||||
row = await cursor.fetchone()
|
||||
if not stored or not row or row[0] != "dtm" or not row[1]:
|
||||
raise LookupError("DTM 격자가 없는 지표면 모델입니다.")
|
||||
root = Path(resolve_stored_project_path(stored))
|
||||
model_path = (root / str(row[1])).resolve()
|
||||
if not model_path.is_relative_to(root.resolve()):
|
||||
raise LookupError("DTM 격자가 없는 지표면 모델입니다.")
|
||||
smooth_path = model_path.with_name(f"{model_path.stem}_smooth.npz")
|
||||
npz_path = smooth_path if smooth and smooth_path.is_file() else model_path
|
||||
if not npz_path.is_file():
|
||||
raise LookupError("DTM 격자 파일이 없습니다.")
|
||||
return npz_path
|
||||
|
||||
|
||||
@router.get("/{project_id}/surface/models/{model_id}/grid", response_model=None)
|
||||
async def read_surface_grid(
|
||||
request: Request, project_id: UUID, model_id: int, smooth: bool = False
|
||||
@@ -209,26 +235,9 @@ async def read_surface_grid(
|
||||
"""
|
||||
pool = get_db_pool()
|
||||
async with pool.acquire() as connection:
|
||||
stored = await get_project_storage_relative_path(connection, project_id)
|
||||
async with connection.cursor() as cursor:
|
||||
await cursor.execute(
|
||||
"SELECT model_type, model_file_path FROM surface_models"
|
||||
" WHERE id = %s AND project_id = %s",
|
||||
(model_id, str(project_id)),
|
||||
)
|
||||
row = await cursor.fetchone()
|
||||
if not stored or not row or row[0] != "dtm" or not row[1]:
|
||||
return JSONResponse(
|
||||
status_code=404,
|
||||
content={"status": "error", "message": "DTM 격자가 없는 지표면 모델입니다."},
|
||||
)
|
||||
model_path = Path(resolve_stored_project_path(stored)) / str(row[1])
|
||||
smooth_path = model_path.with_name(f"{model_path.stem}_smooth.npz")
|
||||
npz_path = smooth_path if smooth and smooth_path.is_file() else model_path
|
||||
if not npz_path.is_file():
|
||||
return JSONResponse(
|
||||
status_code=404,
|
||||
content={"status": "error", "message": "DTM 격자 파일이 없습니다."},
|
||||
)
|
||||
try:
|
||||
npz_path = await dtm_grid_npz(connection, project_id, model_id, smooth)
|
||||
except LookupError as exc:
|
||||
return JSONResponse(status_code=404, content={"status": "error", "message": str(exc)})
|
||||
grid_path = await asyncio.to_thread(dtm_grid_file, npz_path)
|
||||
return cached_file_response(request, grid_path, "application/octet-stream")
|
||||
|
||||
Reference in New Issue
Block a user