# -*- coding: utf-8 -*- """조달청 JDL TEXT 끼워 넣기 API — 묶음 내보내기(JSON · zip) · 묶음 검사(검사기 꼴). 근거: jdl_format.py · jdl_export.py 머리(ST_U_Convert Conv_ST8_Jodal · JDLCHK.Tab_33.dll) 원본 STC·폴더는 읽기만 · 서버에 쓰지 않음(zip 은 응답으로만). """ from __future__ import annotations import base64 import io import zipfile from fastapi import APIRouter, HTTPException from fastapi.responses import Response from jdl_export import export_bundle from jdl_format import COUNTS, check_lines, columns_of from pydantic import BaseModel router = APIRouter() class JdlReq(BaseModel): source_path: str series: int | None = None class JdlCheckReq(BaseModel): files: dict[str, str] = {} # 이름 → base64(또는 data: 주소) def _bundle(req: JdlReq) -> dict: try: return export_bundle(req.source_path, req.series) except FileNotFoundError: raise HTTPException(404, f"경로 없음: {req.source_path}") except (ValueError, KeyError) as e: raise HTTPException(400, str(e)) @router.post("/api/jdl/export") def jdl_export(req: JdlReq): """묶음 요약 — 파일별 줄 수 · 검사 결과 · 첫 줄 열 보기 · 못 만든 것(미확인).""" r = _bundle(req) first = {} for name, data in r["files"].items(): if name in COUNTS and data: first[name] = columns_of(name, data.split(b"\r\n", 1)[0]) ini = r["files"].get("Global.Ini", b"").decode("cp949", "replace") keep = ("series", "pclass", "counts", "checks", "missing", "warnings") return {k: r[k] for k in keep} | {"first": first, "global_ini": ini} @router.post("/api/jdl/export.zip") def jdl_export_zip(req: JdlReq): """묶음 파일 모음 zip(전송용 · 원본 .JDL 압축 형식은 미확인).""" r = _bundle(req) buf = io.BytesIO() with zipfile.ZipFile(buf, "w", zipfile.ZIP_DEFLATED) as z: for name, data in r["files"].items(): z.writestr(name, data) disp = "attachment; filename=JDL_TEXT.zip" return Response(content=buf.getvalue(), media_type="application/zip", headers={"Content-Disposition": disp}) @router.post("/api/jdl/check") def jdl_check(req: JdlCheckReq): """받은 묶음 파일마다 검사기 꼴 검사 — 열 개수 · 코드 글자.""" out = {} for name, b64 in req.files.items(): key = next((k for k in COUNTS if k.upper() == name.upper().rsplit("/", 1)[-1]), None) if not key: out[name] = ["검사 대상 아님"] continue try: data = base64.b64decode(b64.split(",", 1)[-1]) except ValueError: raise HTTPException(400, f"base64 아님: {name}") out[name] = check_lines(key, data) return {"checks": out}