"""Mod management endpoints — list available mods, set enabled mods.""" from __future__ import annotations import logging from typing import Annotated from fastapi import APIRouter, Depends, HTTPException, status from pydantic import BaseModel from sqlalchemy.engine import Connection from adapters.exceptions import AdapterError from adapters.registry import GameAdapterRegistry from core.dal.config_repository import ConfigRepository from core.servers.service import ServerService from database import get_db from dependencies import get_current_user, require_admin logger = logging.getLogger(__name__) router = APIRouter(prefix="/servers/{server_id}/mods", tags=["mods"]) def _ok(data): return {"success": True, "data": data, "error": None} class SetEnabledModsRequest(BaseModel): mods: list[str] def _get_mod_manager(server_id: int, game_type: str): """Get ModManager for the server's game type.""" adapter = GameAdapterRegistry.get(game_type) if not adapter.has_capability("mod_manager"): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail={"code": "NOT_SUPPORTED", "message": f"Game type '{game_type}' does not support mod management"}, ) return adapter.get_mod_manager(server_id) @router.get("") def list_mods( server_id: int, db: Annotated[Connection, Depends(get_db)], _user: Annotated[dict, Depends(get_current_user)], ) -> dict: """List all available mods and which are enabled.""" server = ServerService(db).get_server(server_id) # raises 404 if not found mgr = _get_mod_manager(server_id, server["game_type"]) config_repo = ConfigRepository(db) try: available = mgr.list_available_mods() enabled = set(mgr.get_enabled_mods(config_repo)) except AdapterError as exc: raise HTTPException(status_code=500, detail={"code": "ADAPTER_ERROR", "message": str(exc)}) for mod in available: mod["enabled"] = mod["name"] in enabled return _ok({ "server_id": server_id, "mods": available, "enabled_count": len(enabled), }) @router.put("/enabled") def set_enabled_mods( server_id: int, body: SetEnabledModsRequest, db: Annotated[Connection, Depends(get_db)], _admin: Annotated[dict, Depends(require_admin)], ) -> dict: """ Set the list of enabled mods. Replaces the current enabled list entirely. Server must be restarted for changes to take effect. """ server = ServerService(db).get_server(server_id) # raises 404 if not found mgr = _get_mod_manager(server_id, server["game_type"]) config_repo = ConfigRepository(db) try: mgr.set_enabled_mods(body.mods, config_repo) except AdapterError as exc: raise HTTPException(status_code=400, detail={"code": "ADAPTER_ERROR", "message": str(exc)}) except ValueError as exc: if "CONFIG_VERSION_CONFLICT" in str(exc): raise HTTPException( status_code=status.HTTP_409_CONFLICT, detail={"code": "VERSION_CONFLICT", "message": "Config was modified by another request. Please retry."}, ) raise db.commit() return _ok({ "message": "Enabled mods updated. Restart the server for changes to take effect.", "enabled_mods": body.mods, })