Wettlauf beim Reservieren, 500er bei unsinnigen Eingaben
Drei P3-Funde aus der Durchsicht vom 14.09.: Reservieren: Statusprüfung und Schreiben waren getrennt - zwei gleichzeitige Anfragen konnten beide passieren, die zweite überschrieb Name und Token der ersten, ohne dass die es erfuhr. Jetzt entscheidet ein UPDATE mit Status-Bedingung; der Verlierer bekommt None und die Route meldet "schon weg" (Seite) bzw. 409 (API). /?limit=abc lieferte jedem anonymen Besucher einen internen Serverfehler, limit=-1 hiess in SQLite "alles". _limit_lesen() fällt bei Unsinn auf die Seitengrösse zurück und deckelt bei 500. Erfassen/Bearbeiten: int(category_id) und die Pydantic-Prüfung warfen im Handler - 500 statt Fehlermeldung. Jetzt Meldung; ausserdem werden die Angaben VOR den Bildern geprüft, damit bei abgelehnten Angaben keine verwaisten Bilddateien liegen bleiben. Vier neue Tests, jeder einmal gegen den alten Code gelaufen und dabei rot geworden. 84 lokal grün (HEIC-Test braucht pillow-heif, Docker). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+20
-8
@@ -8,7 +8,7 @@ from __future__ import annotations
|
||||
|
||||
import secrets
|
||||
|
||||
from sqlalchemy import func, select
|
||||
from sqlalchemy import func, select, update
|
||||
from sqlalchemy.orm import Session, selectinload
|
||||
|
||||
from app.models import Groesse, Item, ItemBild, Kategorie, Status, jetzt
|
||||
@@ -135,17 +135,29 @@ def item_loeschen(db: Session, item: Item) -> list[str]:
|
||||
|
||||
# --------------------------------------------------------- Reservierung ---
|
||||
|
||||
def reservieren(db: Session, item: Item, name: str) -> str:
|
||||
def reservieren(db: Session, item: Item, name: str) -> str | None:
|
||||
"""Reserviert und gibt das Token zurück, mit dem sich das rückgängig
|
||||
machen lässt. Das Token verlässt die Anwendung nur dieses eine Mal."""
|
||||
machen lässt. Das Token verlässt die Anwendung nur dieses eine Mal.
|
||||
|
||||
Prüfen und Setzen stehen in EINEM UPDATE mit Status-Bedingung: zwei
|
||||
gleichzeitige Anfragen könnten sonst beide die Prüfung in der Route
|
||||
passieren, und die zweite überschriebe Name und Token der ersten -
|
||||
ohne dass die es je erfährt. So gewinnt genau eine; die andere
|
||||
bekommt None und der Aufrufer meldet "schon weg"."""
|
||||
token = secrets.token_urlsafe(32)
|
||||
item.status = Status.reserved.value
|
||||
item.reserved_by = name
|
||||
item.reservation_token = token
|
||||
item.updated_at = jetzt()
|
||||
betroffen = db.execute(
|
||||
update(Item)
|
||||
.where(Item.id == item.id, Item.status == Status.available.value)
|
||||
.values(
|
||||
status=Status.reserved.value,
|
||||
reserved_by=name,
|
||||
reservation_token=token,
|
||||
updated_at=jetzt(),
|
||||
)
|
||||
).rowcount
|
||||
db.commit()
|
||||
db.refresh(item)
|
||||
return token
|
||||
return token if betroffen else None
|
||||
|
||||
|
||||
def freigeben(db: Session, item: Item) -> Item:
|
||||
|
||||
Reference in New Issue
Block a user