Files
webref/backend/app/api/boards.py
2025-11-02 00:36:32 -06:00

181 lines
4.6 KiB
Python

"""Board management API endpoints."""
from typing import Annotated
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy.orm import Session
from app.boards.repository import BoardRepository
from app.boards.schemas import BoardCreate, BoardDetail, BoardSummary, BoardUpdate
from app.core.deps import get_current_user, get_db
from app.database.models.user import User
router = APIRouter(prefix="/boards", tags=["boards"])
@router.post("", response_model=BoardDetail, status_code=status.HTTP_201_CREATED)
def create_board(
board_data: BoardCreate,
current_user: Annotated[User, Depends(get_current_user)],
db: Annotated[Session, Depends(get_db)],
):
"""
Create a new board.
Args:
board_data: Board creation data
current_user: Current authenticated user
db: Database session
Returns:
Created board details
"""
repo = BoardRepository(db)
board = repo.create_board(
user_id=current_user.id,
title=board_data.title,
description=board_data.description,
)
return BoardDetail.model_validate(board)
@router.get("", response_model=dict)
def list_boards(
current_user: Annotated[User, Depends(get_current_user)],
db: Annotated[Session, Depends(get_db)],
limit: Annotated[int, Query(ge=1, le=100)] = 50,
offset: Annotated[int, Query(ge=0)] = 0,
):
"""
List all boards for the current user.
Args:
current_user: Current authenticated user
db: Database session
limit: Maximum number of boards to return
offset: Number of boards to skip
Returns:
Dictionary with boards list, total count, limit, and offset
"""
repo = BoardRepository(db)
boards, total = repo.get_user_boards(user_id=current_user.id, limit=limit, offset=offset)
return {
"boards": [BoardSummary.model_validate(board) for board in boards],
"total": total,
"limit": limit,
"offset": offset,
}
@router.get("/{board_id}", response_model=BoardDetail)
def get_board(
board_id: UUID,
current_user: Annotated[User, Depends(get_current_user)],
db: Annotated[Session, Depends(get_db)],
):
"""
Get board details by ID.
Args:
board_id: Board UUID
current_user: Current authenticated user
db: Database session
Returns:
Board details
Raises:
HTTPException: 404 if board not found or not owned by user
"""
repo = BoardRepository(db)
board = repo.get_board_by_id(board_id=board_id, user_id=current_user.id)
if not board:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Board {board_id} not found",
)
return BoardDetail.model_validate(board)
@router.patch("/{board_id}", response_model=BoardDetail)
def update_board(
board_id: UUID,
board_data: BoardUpdate,
current_user: Annotated[User, Depends(get_current_user)],
db: Annotated[Session, Depends(get_db)],
):
"""
Update board metadata.
Args:
board_id: Board UUID
board_data: Board update data
current_user: Current authenticated user
db: Database session
Returns:
Updated board details
Raises:
HTTPException: 404 if board not found or not owned by user
"""
repo = BoardRepository(db)
# Convert viewport_state to dict if provided
viewport_dict = None
if board_data.viewport_state:
viewport_dict = board_data.viewport_state.model_dump()
board = repo.update_board(
board_id=board_id,
user_id=current_user.id,
title=board_data.title,
description=board_data.description,
viewport_state=viewport_dict,
)
if not board:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Board {board_id} not found",
)
return BoardDetail.model_validate(board)
@router.delete("/{board_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_board(
board_id: UUID,
current_user: Annotated[User, Depends(get_current_user)],
db: Annotated[Session, Depends(get_db)],
):
"""
Delete a board (soft delete).
Args:
board_id: Board UUID
current_user: Current authenticated user
db: Database session
Raises:
HTTPException: 404 if board not found or not owned by user
"""
repo = BoardRepository(db)
success = repo.delete_board(board_id=board_id, user_id=current_user.id)
if not success:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Board {board_id} not found",
)