Files
Gov-chat-bot/backend/app/routers/admin_moderation.py
2026-03-26 12:49:43 +09:00

107 lines
3.2 KiB
Python

"""
악성 유저 관리 API — 편집장(editor) 이상.
GET /api/admin/moderation — 제한 유저 목록
POST /api/admin/moderation/{user_key}/release — 수동 해제
POST /api/admin/moderation/{user_key}/escalate — 수동 레벨 상승
"""
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.database import get_db
from app.core.deps import require_editor, require_admin
from app.models.admin import AdminUser
from app.models.moderation import UserRestriction
from app.services.moderation import ModerationService
from app.services.audit import log_action
router = APIRouter(prefix="/api/admin/moderation", tags=["admin-moderation"])
class RestrictionOut(BaseModel):
id: str
user_key: str
level: int
reason: str | None = None
auto_applied: bool
expires_at: str | None = None
class Config:
from_attributes = True
class EscalateRequest(BaseModel):
reason: str = "수동 조치"
@router.get("", response_model=list[RestrictionOut])
async def list_restrictions(
db: AsyncSession = Depends(get_db),
current_user: AdminUser = Depends(require_editor),
):
"""제한(level ≥ 1) 유저 목록."""
result = await db.execute(
select(UserRestriction).where(
UserRestriction.tenant_id == current_user.tenant_id,
UserRestriction.level > 0,
)
)
restrictions = result.scalars().all()
return [
RestrictionOut(
id=r.id,
user_key=r.user_key,
level=r.level,
reason=r.reason,
auto_applied=r.auto_applied,
expires_at=r.expires_at.isoformat() if r.expires_at else None,
)
for r in restrictions
]
@router.post("/{user_key}/release")
async def release_restriction(
user_key: str,
db: AsyncSession = Depends(get_db),
current_user: AdminUser = Depends(require_editor),
):
"""수동 해제 (Level 4+ 포함)."""
service = ModerationService(db)
await service.release(current_user.tenant_id, user_key, current_user.id)
await log_action(
db=db,
tenant_id=current_user.tenant_id,
actor_id=current_user.id,
actor_type="admin_user",
action="user.unblock",
target_type="user_restriction",
diff={"user_key": user_key},
)
return {"user_key": user_key, "released": True}
@router.post("/{user_key}/escalate")
async def escalate_restriction(
user_key: str,
body: EscalateRequest,
db: AsyncSession = Depends(get_db),
current_user: AdminUser = Depends(require_editor),
):
"""수동 레벨 상승."""
service = ModerationService(db)
new_level = await service.escalate(current_user.tenant_id, user_key, body.reason)
await log_action(
db=db,
tenant_id=current_user.tenant_id,
actor_id=current_user.id,
actor_type="admin_user",
action="user.restrict",
target_type="user_restriction",
diff={"user_key": user_key, "new_level": new_level, "reason": body.reason},
)
return {"user_key": user_key, "new_level": new_level}