126 lines
4.0 KiB
Python
126 lines
4.0 KiB
Python
|
|
"""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)
|