"""Asset management router.""" from typing import Optional from fastapi import APIRouter, Depends, HTTPException, UploadFile, File, Query from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.database import get_db from app.dependencies import CurrentUser from app.models.asset import Asset, AssetType from app.models.world import World from pydantic import BaseModel, Field router = APIRouter() # --- Pydantic schemas --- class AssetCreate(BaseModel): """Schema for creating an asset reference.""" name: str = Field(..., min_length=1, max_length=255) description: Optional[str] = None asset_type: AssetType world_id: Optional[int] = None class AssetResponse(BaseModel): """Schema for asset responses.""" id: int name: str description: Optional[str] asset_type: AssetType file_path: str file_size: Optional[int] mime_type: Optional[str] world_id: Optional[int] owner_id: int is_public: bool created_at: str updated_at: str class Config: from_attributes = True class AssetUpdate(BaseModel): """Schema for updating an asset.""" name: Optional[str] = None description: Optional[str] = None is_public: Optional[bool] = None # --- Endpoints --- @router.post("/", response_model=AssetResponse, status_code=201) async def create_asset( payload: AssetCreate, current_user: CurrentUser, db: AsyncSession = Depends(get_db), ): """Create a new asset reference.""" # Verify world ownership if world_id is provided if payload.world_id is not None: world = await db.get(World, payload.world_id) if world is None: raise HTTPException(status_code=404, detail="World not found") if world.owner_id != current_user.id: raise HTTPException(status_code=403, detail="Not owner of this world") asset = Asset( name=payload.name, description=payload.description, asset_type=payload.asset_type, file_path="", # Will be set after upload owner_id=current_user.id, world_id=payload.world_id, is_public=False, ) db.add(asset) await db.commit() await db.refresh(asset) return asset @router.get("/", response_model=list[AssetResponse]) async def list_assets( current_user: CurrentUser, world_id: Optional[int] = Query(None, description="Filter by world"), asset_type: Optional[AssetType] = Query(None), limit: int = Query(50, ge=1, le=100), offset: int = Query(0, ge=0), db: AsyncSession = Depends(get_db), ): """List assets with optional filters.""" stmt = select(Asset).where(Asset.owner_id == current_user.id) if world_id is not None: stmt = stmt.where(Asset.world_id == world_id) if asset_type is not None: stmt = stmt.where(Asset.asset_type == asset_type) stmt = stmt.order_by(Asset.created_at.desc()).limit(limit).offset(offset) result = await db.execute(stmt) assets = result.scalars().all() return assets @router.get("/{asset_id}", response_model=AssetResponse) async def get_asset( asset_id: int, current_user: CurrentUser, db: AsyncSession = Depends(get_db), ): """Get a single asset by ID.""" asset = await db.get(Asset, asset_id) if asset is None or asset.owner_id != current_user.id: raise HTTPException(status_code=404, detail="Asset not found") return asset @router.patch("/{asset_id}", response_model=AssetResponse) async def update_asset( asset_id: int, payload: AssetUpdate, current_user: CurrentUser, db: AsyncSession = Depends(get_db), ): """Update an asset.""" asset = await db.get(Asset, asset_id) if asset is None or asset.owner_id != current_user.id: raise HTTPException(status_code=404, detail="Asset not found") update_data = payload.model_dump(exclude_unset=True) for field, value in update_data.items(): setattr(asset, field, value) await db.commit() await db.refresh(asset) return asset @router.delete("/{asset_id}", status_code=204) async def delete_asset( asset_id: int, current_user: CurrentUser, db: AsyncSession = Depends(get_db), ): """Delete an asset.""" asset = await db.get(Asset, asset_id) if asset is None or asset.owner_id != current_user.id: raise HTTPException(status_code=404, detail="Asset not found") await db.delete(asset) await db.commit() @router.post("/{asset_id}/upload") async def upload_asset_file( asset_id: int, file: UploadFile = File(...), current_user: CurrentUser = None, db: AsyncSession = Depends(get_db), ): """Upload a file for an existing asset.""" asset = await db.get(Asset, asset_id) if asset is None or asset.owner_id != current_user.id: raise HTTPException(status_code=404, detail="Asset not found") # TODO: Implement actual file upload logic (S3, local filesystem, etc.) file_path = f"uploads/{asset_id}_{file.filename}" asset.file_path = file_path asset.mime_type = file.content_type asset.file_size = 0 # Will be updated after actual write await db.commit() await db.refresh(asset) return {"message": "File upload endpoint", "asset_id": asset_id, "file_path": file_path}