"""M02 일위대가 조합 층 API(PLAN 27-2a) — `/api/m02/layers/{layer}/combos`(옛 `/api/m01/combo*`). ⚠ 등록은 `main.py`(로그인만) · 층 권한은 `M02_Layer_Access`(`Router_Items._root`) 한 규칙 · 읽기만(목록 · 키 하나) + 실무문서 통째 지우기 — 갈라 내기 · 키 적기 · 만들기 · 고치기 · 지우기 · 알약 길은 은퇴(39-1d · 정본 = 열마다 `labor/<열>.json`). 저장소 = `M02_MasterTemplete_Combo_Store`. 담을 로직 고르기 · 일위대가 입력 모달이 읽는 단가산출 로직(M01 길은 시스템 관리자 전용)은 `/api/m02/logic-lib/…` 읽기만(로그인) — 모양은 M01 길과 같음. 39-6 — 일위대가 조합 = 실무문서 · 조합 길 전부 시스템 관리자만(`_door` · 담을 로직 읽기 뺌). """ from __future__ import annotations from fastapi import APIRouter, Depends, HTTPException, Request from common_util.common_util_auth import verify_session from M01_MasterData import M01_MasterData_Store as m01 from M02_MasterTemplete import M02_Labor_Inputs as labor_inputs from M02_MasterTemplete import M02_Layer_Access as access from M02_MasterTemplete import M02_MasterTemplete_Combo_Store as combos from M02_MasterTemplete.M02_MasterTemplete_Router_Items import Layer, Session, _call, _root def _door(request: Request, session: Session = Depends(verify_session)) -> None: """일위대가 조합 = 실무문서(39-6) — 조합 길 전부 시스템 관리자만 · 담을 로직 읽기는 로그인만.""" if "/logic-lib/" not in request.url.path and not access.is_system_admin(session): raise HTTPException(status_code=403, detail="실무문서(일위대가 조합)는 시스템 관리자만 봄.") router = APIRouter( prefix="/api/m02", tags=["M02 MasterTemplete Combos"], dependencies=[Depends(_door)] ) def _where(key: str) -> tuple[str, str | None]: got = combos.where(key) if got is None: raise HTTPException(status_code=404, detail=f"없는 조합 「{key}」") return got @router.get("/combos/key/{key}") def get_by_key(key: str, session: Session = Depends(verify_session)) -> dict: """키 하나(어느 층이든 · 그 층 읽기 권한) — `{layer, owner, 판, combo, 줄, …}`.""" layer, owner = _where(key) return {"layer": layer, "owner": owner, **_call(_root(session, layer, owner), combos.one, key)} @router.get("/layers/{layer}/combos") def get_combos(layer: Layer, owner: str | None = None, session: Session = Depends(verify_session)): return _call(_root(session, layer, owner), combos.listing) @router.get("/layers/{layer}/combos/{key}") def get_combo( layer: Layer, key: str, owner: str | None = None, session: Session = Depends(verify_session) ): return _call(_root(session, layer, owner), combos.one, key) @router.delete("/practice") def delete_practice(판: str = "", session: Session = Depends(verify_session)) -> dict: """실무문서 통째 지우기(PLAN 39-2) — 시스템 관리자만 · 마스터 조합 표 줄을 모두 비움 · 구조물이 쓰는 조합이 있으면 409.""" if not access.is_system_admin(session): raise HTTPException(status_code=403, detail="실무문서는 시스템 관리자만") return _call(_root(session, "system", None, write=True), combos.drop_practice, 판) # ── 담을 로직(읽기만) — M01 `/logics` · `/subs?group=로직` · `/logic` · `/logic/auto` 모양 ── def _read(fn, *args): try: return fn(*args) except m01.StoreError as e: raise HTTPException(status_code=e.status, detail=e.detail) from e @router.get("/logic-lib/logics", dependencies=[Depends(verify_session)]) def get_logics() -> dict: return {"logics": _read(m01.logics, "", "", "", None)} @router.get("/logic-lib/subs", dependencies=[Depends(verify_session)]) def get_logic_subs() -> dict: return _read(m01.subs, "", "로직") @router.get("/logic-lib/logic", dependencies=[Depends(verify_session)]) def get_logic(key: str) -> dict: return _read(m01.logic, key) @router.get("/logic-lib/auto", dependencies=[Depends(verify_session)]) def get_logic_auto(key: str) -> dict: """견본 입력 — 미리 보기용 자동값.""" return _read(m01.auto, key) @router.get("/logic-lib/inputs", dependencies=[Depends(verify_session)]) def get_logic_inputs(keys: str = "") -> dict: """일위대가 입력 모달 — 로직 키들(쉼표)의 입력 목록 + 자동값(`M02_Labor_Inputs`).""" return _read(labor_inputs.logic_inputs, keys.split(","))