70 lines
2.1 KiB
Python
70 lines
2.1 KiB
Python
"""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],
|
|
}
|