""" 라이선스 제한 강제 — 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(), }