"""Presets API — CRUD for world presets.""" from __future__ import annotations import uuid from fastapi import APIRouter, Depends, HTTPException, Response, status from sqlalchemy import or_, select from sqlalchemy.ext.asyncio import AsyncSession from app.api.deps import get_current_user from app.db import get_db from app.models import User, WorldPreset from app.schemas import PresetCreateRequest, PresetFull, PresetSummary router = APIRouter(prefix="/api/presets", tags=["presets"]) @router.get("", response_model=dict) async def list_presets( db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user), ) -> dict: """List public presets + current user's presets.""" rows = ( await db.execute( select(WorldPreset).where( or_( WorldPreset.is_public.is_(True), WorldPreset.owner_id == user.id, ) ).order_by(WorldPreset.created_at.desc()) ) ).scalars().all() return {"items": [PresetSummary.model_validate(r).model_dump() for r in rows]} @router.post("", response_model=PresetFull, status_code=status.HTTP_201_CREATED) async def create_preset( body: PresetCreateRequest, db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user), ) -> WorldPreset: if not user.is_admin: raise HTTPException(403, "admin_only") preset = WorldPreset( owner_id=user.id, name=body.name, description=body.description, language=body.language, rules=body.rules, time_schema=body.time_schema, schemas=body.schemas, environment_schema=body.environment_schema, environment_initial=body.environment_initial, is_public=body.is_public, status="ready", ) db.add(preset) await db.commit() await db.refresh(preset) return preset @router.get("/{preset_id}", response_model=PresetFull) async def get_preset( preset_id: uuid.UUID, db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user), ) -> WorldPreset: preset = ( await db.execute(select(WorldPreset).where(WorldPreset.id == preset_id)) ).scalar_one_or_none() if preset is None: raise HTTPException(404, "not_found") if not preset.is_public and preset.owner_id != user.id and not user.is_admin: raise HTTPException(403, "not_accessible") return preset @router.patch("/{preset_id}", response_model=PresetFull) async def update_preset( preset_id: uuid.UUID, body: PresetCreateRequest, db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user), ) -> WorldPreset: preset = ( await db.execute(select(WorldPreset).where(WorldPreset.id == preset_id)) ).scalar_one_or_none() if preset is None: raise HTTPException(404, "not_found") if preset.owner_id != user.id and not user.is_admin: raise HTTPException(403, "not_owner") preset.name = body.name preset.description = body.description preset.language = body.language preset.rules = body.rules preset.time_schema = body.time_schema preset.schemas = body.schemas preset.environment_schema = body.environment_schema preset.environment_initial = body.environment_initial preset.is_public = body.is_public preset.version += 1 await db.commit() await db.refresh(preset) return preset @router.delete("/{preset_id}", status_code=status.HTTP_204_NO_CONTENT, response_class=Response) async def delete_preset( preset_id: uuid.UUID, db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user), ) -> Response: preset = ( await db.execute(select(WorldPreset).where(WorldPreset.id == preset_id)) ).scalar_one_or_none() if preset is None: raise HTTPException(404, "not_found") if preset.owner_id != user.id and not user.is_admin: raise HTTPException(403, "not_owner") preset.status = "archived" await db.commit() return Response(status_code=status.HTTP_204_NO_CONTENT)