From 506db5ff07363b842f9fe0ba13b256081ef09ccc Mon Sep 17 00:00:00 2001 From: king Date: Tue, 2 Jun 2026 17:28:26 +0900 Subject: [PATCH] =?UTF-8?q?feat(expense):=20=EB=B6=84=EB=A5=98=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EB=A9=94=EB=89=B4=EB=A5=BC=20=EC=8A=B9=EC=9D=B8?= =?UTF-8?q?=EC=9E=90=EC=97=90=EA=B2=8C=EB=8F=84=20=EB=85=B8=EC=B6=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - /expense/settings 및 분류 CRUD 가드 관리자 → 승인자(expense_approver|admin) - index 설정 버튼 is_approver 조건으로 노출 - 미사용 _require_admin 헬퍼 제거 Co-Authored-By: Claude Opus 4.8 --- app/modules/expense/router.py | 28 ++++++------------- .../expense/templates/expense/index.html | 2 +- 2 files changed, 9 insertions(+), 21 deletions(-) diff --git a/app/modules/expense/router.py b/app/modules/expense/router.py index 8c118b1..7a5c8e0 100644 --- a/app/modules/expense/router.py +++ b/app/modules/expense/router.py @@ -109,18 +109,6 @@ def _require_approver(request: Request) -> dict[str, Any]: return user -def _require_admin(request: Request) -> dict[str, Any]: - from app.main import get_current_user_record # noqa: WPS433 - from app.store import is_admin # noqa: WPS433 - - user = get_current_user_record(request) - if user is None: - raise HTTPException(status_code=401, detail="로그인이 필요합니다.") - if not is_admin(user): - raise HTTPException(status_code=403, detail="관리자 권한이 필요합니다.") - return user - - def _require_db_store(store: Any) -> None: """워크플로/첨부/집계는 DB 모드 전용. JSON 폴백에서는 501.""" if not hasattr(store, "submit"): @@ -301,26 +289,26 @@ async def reports_page(request: Request) -> HTMLResponse: # ──────────────────────────────────────────────────────────── -# 관리자 설정 — 분류 관리 +# 승인자 설정 — 분류 관리 # ──────────────────────────────────────────────────────────── @router.get("/settings", response_class=HTMLResponse) async def settings_page(request: Request) -> HTMLResponse: - """관리자 전용 설정 — 분류 추가/삭제.""" + """승인자/관리자 설정 — 분류 추가/삭제.""" from app.main import ( # noqa: WPS433 build_erp_nav, get_current_user_record, render_template, ) - from app.store import is_admin # noqa: WPS433 + from app.store import has_module, is_admin # noqa: WPS433 user = get_current_user_record(request) if user is None: return RedirectResponse(url="/login", status_code=303) - if not is_admin(user): + if not (is_admin(user) or has_module(user, "expense_approver")): return render_template( request, "denied.html", - {"reason": "개인경비 설정은 관리자만 접근할 수 있습니다."}, + {"reason": "개인경비 설정은 승인자만 접근할 수 있습니다."}, status_code=403, ) return render_template( @@ -328,7 +316,7 @@ async def settings_page(request: Request) -> HTMLResponse: "expense/settings.html", { "user": user, - "is_admin": True, + "is_admin": is_admin(user), "categories": _categories(request), "nav_items": build_erp_nav(user, active="expense"), "page_title": "개인경비 — 설정", @@ -349,7 +337,7 @@ async def list_categories( async def add_category( request: Request, body: CategoryBody, - user: dict[str, Any] = Depends(_require_admin), + user: dict[str, Any] = Depends(_require_approver), ) -> JSONResponse: try: categories = _category_store(request).add(body.name) @@ -362,7 +350,7 @@ async def add_category( async def delete_category( request: Request, name: str, - user: dict[str, Any] = Depends(_require_admin), + user: dict[str, Any] = Depends(_require_approver), ) -> JSONResponse: try: categories = _category_store(request).delete(name) diff --git a/app/modules/expense/templates/expense/index.html b/app/modules/expense/templates/expense/index.html index 2cbb1d3..62cc4dd 100644 --- a/app/modules/expense/templates/expense/index.html +++ b/app/modules/expense/templates/expense/index.html @@ -15,7 +15,7 @@ {% if is_approver %} 엑셀(전체) {% endif %} - {% if is_admin %} + {% if is_approver %} ⚙ 설정 {% endif %}