From ef7f76821d29b82ce0f4d3c1398f6f721ef103e5 Mon Sep 17 00:00:00 2001 From: king Date: Thu, 25 Jun 2026 12:15:51 +0900 Subject: [PATCH] =?UTF-8?q?feat(admin):=20=EC=8A=88=ED=8D=BC=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=EC=9E=90=EA=B0=80=20admin=20=EC=9D=98=20=EA=B0=9C?= =?UTF-8?q?=EB=B3=84=20=ED=94=84=EB=A1=9C=EA=B7=B8=EB=9E=A8=20=EC=A0=91?= =?UTF-8?q?=EA=B7=BC=20=EC=A0=9C=EC=96=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 기존엔 admin 역할이면 모든 모듈을 무조건 전체 ON+잠금이라 슈퍼관리자도 admin 의 특정 프로그램 접근을 끌 수 없었다. - _normalize_modules: admin 강제 전체 ON 덮어쓰기 제거 → 저장된 칩 상태 존중 - has_module: admin 단축 통과 제거, 슈퍼관리자만 항상 전체. admin 은 칩 따름 - admin.html: admin 칩 잠금 해제(슈퍼관리자만 잠금), 역할→admin 전환 시 편의상 전체 ON(잠금 아님) Co-Authored-By: Claude Opus 4.8 --- app/store.py | 10 ++++++---- app/templates/admin.html | 14 ++++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/app/store.py b/app/store.py index db9363e..63e33e4 100644 --- a/app/store.py +++ b/app/store.py @@ -82,14 +82,14 @@ class UserStore: @staticmethod def _normalize_modules(modules: dict[str, Any] | None, *, is_admin: bool) -> dict[str, bool]: + # 신규(modules 미지정) 사용자는 역할 기본값(admin=전체ON / user=전체OFF)으로 시작. + # 기존 값이 있으면 그대로 존중한다 — admin 이라도 슈퍼관리자가 개별 모듈을 + # 끌 수 있다(예전엔 admin 을 무조건 전체 ON 으로 덮어썼다). base = UserStore._default_modules(is_admin) if isinstance(modules, dict): for key in MODULE_KEYS: if key in modules: base[key] = bool(modules[key]) - if is_admin: - for key in MODULE_KEYS: - base[key] = True return base def get(self, email: str) -> dict[str, Any] | None: @@ -230,7 +230,9 @@ def is_admin(user_rec: dict[str, Any] | None) -> bool: def has_module(user_rec: dict[str, Any] | None, module: str) -> bool: if not user_rec: return False - if is_admin(user_rec): + # 슈퍼관리자는 항상 전체 접근. 일반 admin 은 칩(modules) 상태를 따른다 — + # 슈퍼관리자가 admin 의 개별 프로그램 접근을 제어할 수 있도록. + if user_rec.get("is_super_admin"): return True mods = user_rec.get("modules") or {} if mods.get(module): diff --git a/app/templates/admin.html b/app/templates/admin.html index ceadcfa..bda1c7b 100644 --- a/app/templates/admin.html +++ b/app/templates/admin.html @@ -152,7 +152,7 @@ {% if key in approver_keys %}is-approver{% endif %}" data-module="{{ key }}" aria-pressed="{{ 'true' if u.modules[key] else 'false' }}" - {% if u.is_super_admin or u.role == 'admin' %}data-locked="true"{% endif %}> + {% if u.is_super_admin %}data-locked="true"{% endif %}> {{ module_labels.get(key, key) }}{% if key in approver_keys %} 승인{% endif %} {% endfor %} @@ -175,8 +175,8 @@ @@ -204,15 +204,21 @@ } function syncPermChips(tr) { + // 슈퍼관리자만 전체 ON + 잠금. 일반 admin 은 슈퍼관리자가 개별 제어 가능. + // 역할을 admin 으로 바꾸면 편의상 전체 ON(잠금 아님 — 다시 끌 수 있음). const isSuper = tr.dataset.super === "true"; const adminRole = tr.querySelector("select[data-field='role']").value === "admin"; tr.querySelectorAll(".erp-perm-chip").forEach((chip) => { - if (isSuper || adminRole) { + if (isSuper) { chip.classList.add("is-on"); chip.setAttribute("aria-pressed", "true"); chip.setAttribute("data-locked", "true"); } else { chip.removeAttribute("data-locked"); + if (adminRole) { + chip.classList.add("is-on"); + chip.setAttribute("aria-pressed", "true"); + } } }); }