Files
bellsystems-cp/backend/builder/router.py

125 lines
4.0 KiB
Python

from fastapi import APIRouter, Depends, HTTPException
from fastapi.responses import FileResponse
from auth.models import TokenPayload
from auth.dependencies import require_permission
from builder.models import (
BuiltMelodyCreate,
BuiltMelodyUpdate,
BuiltMelodyInDB,
BuiltMelodyListResponse,
)
from builder import service
router = APIRouter(prefix="/api/builder/melodies", tags=["builder"])
@router.get("", response_model=BuiltMelodyListResponse)
async def list_built_melodies(
_user: TokenPayload = Depends(require_permission("melodies", "view")),
):
melodies = await service.list_built_melodies()
return BuiltMelodyListResponse(melodies=melodies, total=len(melodies))
@router.get("/for-melody/{firestore_melody_id}")
async def get_for_firestore_melody(
firestore_melody_id: str,
_user: TokenPayload = Depends(require_permission("melodies", "view")),
):
"""Get the built melody assigned to a given Firestore melody ID. Returns null if none found."""
result = await service.get_built_melody_for_firestore_id(firestore_melody_id)
if result is None:
return None
return result.model_dump()
@router.get("/{melody_id}", response_model=BuiltMelodyInDB)
async def get_built_melody(
melody_id: str,
_user: TokenPayload = Depends(require_permission("melodies", "view")),
):
return await service.get_built_melody(melody_id)
@router.post("", response_model=BuiltMelodyInDB, status_code=201)
async def create_built_melody(
body: BuiltMelodyCreate,
_user: TokenPayload = Depends(require_permission("melodies", "edit")),
):
return await service.create_built_melody(body)
@router.put("/{melody_id}", response_model=BuiltMelodyInDB)
async def update_built_melody(
melody_id: str,
body: BuiltMelodyUpdate,
_user: TokenPayload = Depends(require_permission("melodies", "edit")),
):
return await service.update_built_melody(melody_id, body)
@router.delete("/{melody_id}", status_code=204)
async def delete_built_melody(
melody_id: str,
_user: TokenPayload = Depends(require_permission("melodies", "delete")),
):
await service.delete_built_melody(melody_id)
@router.post("/{melody_id}/build-binary", response_model=BuiltMelodyInDB)
async def build_binary(
melody_id: str,
_user: TokenPayload = Depends(require_permission("melodies", "edit")),
):
"""Build the .bsm binary file from the stored steps."""
return await service.build_binary(melody_id)
@router.post("/{melody_id}/build-builtin", response_model=BuiltMelodyInDB)
async def build_builtin_code(
melody_id: str,
_user: TokenPayload = Depends(require_permission("melodies", "edit")),
):
"""Generate PROGMEM C code and store it in the database."""
return await service.build_builtin_code(melody_id)
@router.get("/{melody_id}/download")
async def download_binary(
melody_id: str,
_user: TokenPayload = Depends(require_permission("melodies", "view")),
):
"""Download the .bsm binary file."""
path = await service.get_binary_path(melody_id)
if not path:
raise HTTPException(status_code=404, detail="Binary not built yet for this melody")
melody = await service.get_built_melody(melody_id)
filename = f"{melody.name}.bsm"
return FileResponse(
path=str(path),
media_type="application/octet-stream",
filename=filename,
)
@router.post("/{melody_id}/assign", response_model=BuiltMelodyInDB)
async def assign_to_melody(
melody_id: str,
firestore_melody_id: str,
_user: TokenPayload = Depends(require_permission("melodies", "edit")),
):
"""Mark this built melody as assigned to a Firestore melody."""
return await service.assign_to_melody(melody_id, firestore_melody_id)
@router.post("/{melody_id}/unassign", response_model=BuiltMelodyInDB)
async def unassign_from_melody(
melody_id: str,
firestore_melody_id: str,
_user: TokenPayload = Depends(require_permission("melodies", "edit")),
):
"""Remove a Firestore melody assignment from this built melody."""
return await service.unassign_from_melody(melody_id, firestore_melody_id)