"""Public listing of inventory items owners marked as `available`. Read-only and unauthenticated, like the catalog. Notes are never included: the listing only reveals the owner's username, quantity and catalog details. """ import math from fastapi import APIRouter, Depends, Query from sqlalchemy import select from sqlalchemy.orm import Session as DbSession from app.db import get_db from app.inventory import SORT_KEYS, enrich_entry from app.models import InventoryEntry, User from app.schemas import AvailablePage router = APIRouter(prefix="/api/v1/available", tags=["available"]) MAX_PAGE_SIZE = 100 @router.get("", response_model=AvailablePage) def list_available( category: str | None = None, search: str | None = None, sort: str = Query(default="updated", pattern="^(name|category|quantity|updated)$"), page: int = Query(default=1, ge=1), page_size: int = Query(default=25, ge=1), db: DbSession = Depends(get_db), ): page_size = min(page_size, MAX_PAGE_SIZE) rows = db.execute( select(InventoryEntry, User.username) .join(User, User.id == InventoryEntry.user_id) .where(InventoryEntry.visibility == "available") ).all() items = [] for entry, username in rows: enriched = enrich_entry(entry) if not enriched["available"]: continue enriched["username"] = username items.append(enriched) if category is not None and category.strip(): wanted = category.strip() items = [i for i in items if i["category"] == wanted] if search is not None and search.strip(): needle = search.strip().lower() items = [ i for i in items if needle in i["name"].lower() or needle in i["class_name"].lower() or needle in i["username"].lower() ] items.sort(key=SORT_KEYS[sort]) total = len(items) total_pages = max(1, math.ceil(total / page_size)) start = (page - 1) * page_size return { "total": total, "page": page, "page_size": page_size, "total_pages": total_pages, "items": items[start : start + page_size], }