zioinfo-mail/workspace/guardia-itsm/middleware/license_guard.py
DESKTOP-TKLFCPR\ython cfe2901a55 refactor(structure): consolidate all projects under workspace/
- itsm/    -> workspace/guardia-itsm/
- manager/ -> workspace/guardia-manager/
- app/     -> workspace/guardia-messenger/
- manual/  -> workspace/guardia-docs/

workspace/zioinfo-web/ unchanged.
git mv preserves full commit history.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 23:50:56 +09:00

138 lines
5.4 KiB
Python

"""
라이선스 제한 강제 — FastAPI Dependency 함수 모음.
사용법:
from middleware.license_guard import check_institution_limit, check_server_limit, require_feature
@router.post("/")
async def create_inst(
payload: ...,
db: AsyncSession = Depends(get_db),
_: None = Depends(check_institution_limit),
):
...
"""
from __future__ import annotations
from fastapi import Depends, HTTPException
from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession
from database import get_db
from routers.license import get_license_status
async def _get_status(db: AsyncSession) -> dict:
return await get_license_status(db)
# ── 기관 수 제한 ───────────────────────────────────────────────────────────────
async def check_institution_limit(db: AsyncSession = Depends(get_db)) -> None:
"""기관 수가 라이선스 한도에 도달하면 HTTP 403."""
from models import Institution
status = await _get_status(db)
max_inst = (status.get("limits") or {}).get("max_institutions", 1)
if max_inst == -1:
return # 무제한
count_r = await db.execute(select(func.count()).select_from(Institution))
count = count_r.scalar_one()
if count >= max_inst:
edition = status.get("edition", "COMMUNITY")
raise HTTPException(
status_code=403,
detail=(
f"라이선스 한도 초과: {edition} 에디션은 최대 {max_inst}개 기관까지 등록 가능합니다. "
f"현재 {count}개 등록됨. 라이선스를 업그레이드하세요."
),
)
# ── 서버 수 제한 ───────────────────────────────────────────────────────────────
async def check_server_limit(db: AsyncSession = Depends(get_db)) -> None:
"""서버 수가 라이선스 한도에 도달하면 HTTP 403."""
from models import Server
status = await _get_status(db)
max_srv = (status.get("limits") or {}).get("max_servers", 20)
if max_srv == -1:
return
count_r = await db.execute(select(func.count()).select_from(Server))
count = count_r.scalar_one()
if count >= max_srv:
edition = status.get("edition", "COMMUNITY")
raise HTTPException(
status_code=403,
detail=(
f"라이선스 한도 초과: {edition} 에디션은 최대 {max_srv}개 서버까지 등록 가능합니다. "
f"현재 {count}개 등록됨. 라이선스를 업그레이드하세요."
),
)
# ── 사용자 수 제한 ─────────────────────────────────────────────────────────────
async def check_user_limit(db: AsyncSession = Depends(get_db)) -> None:
"""사용자 수가 라이선스 한도에 도달하면 HTTP 403."""
from models import User
status = await _get_status(db)
max_usr = (status.get("limits") or {}).get("max_users", 10)
if max_usr == -1:
return
count_r = await db.execute(select(func.count()).select_from(User))
count = count_r.scalar_one()
if count >= max_usr:
edition = status.get("edition", "COMMUNITY")
raise HTTPException(
status_code=403,
detail=(
f"라이선스 한도 초과: {edition} 에디션은 최대 {max_usr}명 사용자까지 등록 가능합니다. "
f"현재 {count}명 등록됨. 라이선스를 업그레이드하세요."
),
)
# ── 기능 접근 제한 ─────────────────────────────────────────────────────────────
def require_feature(feature_name: str):
"""특정 기능이 현재 라이선스 에디션에 포함되어 있는지 검사하는 Dependency."""
async def _check(db: AsyncSession = Depends(get_db)) -> None:
status = await _get_status(db)
features: list = (status.get("limits") or {}).get("features", [])
if feature_name not in features:
edition = status.get("edition", "COMMUNITY")
raise HTTPException(
status_code=403,
detail=(
f"'{feature_name}' 기능은 현재 라이선스({edition})에서 지원되지 않습니다. "
"라이선스를 업그레이드하세요."
),
)
return _check
# ── 현재 사용량 조회 ────────────────────────────────────────────────────────────
async def get_license_usage(db: AsyncSession = Depends(get_db)) -> dict:
"""현재 기관/사용자/서버 사용량 반환."""
from models import Institution, Server, User
inst_r = await db.execute(select(func.count()).select_from(Institution))
user_r = await db.execute(select(func.count()).select_from(User))
srv_r = await db.execute(select(func.count()).select_from(Server))
return {
"institutions": inst_r.scalar_one(),
"users": user_r.scalar_one(),
"servers": srv_r.scalar_one(),
}