Files
mtgonline/backend/app/routers/admin.py
T

221 lines
6.2 KiB
Python

"""Admin router endpoints."""
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, update
from typing import Optional, List
from datetime import datetime
from app.core.database import get_db
from app.core.security import get_current_user
from app.models.models import User, Ban, GameLog, AuditLog
from app.schemas.schemas import BanCreate, BanResponse
router = APIRouter()
@router.get("/users", response_model=List[dict])
async def list_users(
page: int = 1,
page_size: int = 50,
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user),
):
"""List all users (admin only)."""
# Check if current user is admin
if current_user.get("privlevel") not in ["Admin", "Judge"]:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Admin privileges required",
)
stmt = (
select(User)
.order_by(User.id)
.offset((page - 1) * page_size)
.limit(page_size)
)
result = await db.execute(stmt)
users = result.scalars().all()
return [
{
"id": user.id,
"username": user.username,
"email": user.email,
"privlevel": user.privlevel,
"is_active": user.is_active,
"is_banned": user.is_banned,
"vip_status": user.vip_status,
"creation_date": user.creation_date,
}
for user in users
]
@router.get("/bans", response_model=List[BanResponse])
async def list_bans(
active_only: bool = True,
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user),
):
"""List all bans (admin only)."""
# Check if current user is admin
if current_user.get("privlevel") not in ["Admin", "Judge"]:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Admin privileges required",
)
stmt = select(Ban).order_by(Ban.id)
if active_only:
stmt = stmt.where(Ban.active == True)
result = await db.execute(stmt)
bans = result.scalars().all()
return [BanResponse.model_validate(ban) for ban in bans]
@router.post("/bans", response_model=BanResponse)
async def create_ban(
request: BanCreate,
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user),
):
"""Create a ban (admin only)."""
# Check if current user is admin
if current_user.get("privlevel") not in ["Admin", "Judge"]:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Admin privileges required",
)
new_ban = Ban(
user_id=request.user_id,
reason=request.reason,
expiration_time=request.expiration_time,
moderators=current_user.get("username"),
ip_address=None, # Would get from request
)
db.add(new_ban)
await db.flush()
return BanResponse.model_validate(new_ban)
@router.post("/bans/{ban_id}/unban")
async def unban(
ban_id: int,
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user),
):
"""Unban a user (admin only)."""
# Check if current user is admin
if current_user.get("privlevel") not in ["Admin", "Judge"]:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Admin privileges required",
)
stmt = select(Ban).where(Ban.id == ban_id)
result = await db.execute(stmt)
ban = result.scalar_one_or_none()
if not ban:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Ban not found",
)
# Deactivate ban
stmt = (
update(Ban)
.where(Ban.id == ban_id)
.values(active=False)
)
await db.execute(stmt)
# Also unban the user
stmt = (
update(User)
.where(User.id == ban.user_id)
.values(
is_banned=False,
ban_reason=None,
ban_ends=None,
)
)
await db.execute(stmt)
return {"message": "User unbanned successfully"}
@router.get("/logs", response_model=List[dict])
async def list_logs(
room_id: Optional[int] = None,
limit: int = 100,
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user),
):
"""List game logs (admin only)."""
# Check if current user is admin
if current_user.get("privlevel") not in ["Admin", "Judge"]:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Admin privileges required",
)
stmt = select(GameLog).order_by(GameLog.id.desc()).limit(limit)
if room_id:
stmt = stmt.where(GameLog.room_id == room_id)
result = await db.execute(stmt)
logs = result.scalars().all()
return [
{
"id": log.id,
"room_id": log.room_id,
"player_id": log.player_id,
"message": log.message,
"timestamp": log.timestamp,
}
for log in logs
]
@router.post("/audit", response_model=dict)
async def log_audit(
action_type: str,
target_user_id: Optional[int] = None,
details: Optional[str] = None,
db: AsyncSession = Depends(get_db),
current_user: dict = Depends(get_current_user),
):
"""Create an audit log entry (admin only)."""
# Check if current user is admin
if current_user.get("privlevel") not in ["Admin", "Judge"]:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Admin privileges required",
)
new_audit = AuditLog(
admin_id=int(current_user["user_id"]),
action_type=action_type,
target_user_id=target_user_id,
details=details,
ip_address=None, # Would get from request
)
db.add(new_audit)
await db.flush()
return {
"id": new_audit.id,
"admin_id": new_audit.admin_id,
"action_type": new_audit.action_type,
"target_user_id": new_audit.target_user_id,
"details": new_audit.details,
"timestamp": new_audit.timestamp,
}