Plugin neuheiten: Bearer-Token-Pflicht der BGG-XML-API2 (Fix für HTTP 401)
BoardGameGeek verlangt für die XML API2 jetzt Bearer-Authentifizierung
(Thread 3602374); ohne Token antwortet die API mit 401.
- BggClient: neuer Parameter token, sendet Authorization: Bearer … auf
allen Requests; Token kommt aus SPIELE_BGG_TOKEN (vor jedem Sync gelesen)
- HTTP 401 → klarer BggAuthFehler ('BGG hat die Anfrage abgelehnt (401) —
bitte gültigen API-Token in SPIELE_BGG_TOKEN hinterlegen.') statt
generischer Meldung, kein Retry
- Ohne konfigurierten Token wird der Sync übersprungen ('Kein BGG-API-Token
konfiguriert (SPIELE_BGG_TOKEN) — Sync übersprungen.'), statt Requests zu
feuern; Meldung erscheint im Sync-Ergebnis, UI-Banner und Protokoll
- SyncService: BggAuthFehler bricht den Lauf ab (weitere Suchbegriffe
scheitern zwangsläufig gleich), Teilergebnisse bleiben erhalten
- Tests: Bearer-Header, 401-Fall (Client/Sync/UI), Skip ohne Token;
bestehende Sync-UI-Tests setzen Test-Token
- README: neue Env-Variable SPIELE_BGG_TOKEN + Hinweis auf Token-Pflicht
This commit is contained in:
@@ -11,6 +11,13 @@ Eigenschaften:
|
||||
beschränkt; Erweiterungen (`boardgameexpansion`) werden zusätzlich auf
|
||||
Elementebene herausgefiltert.
|
||||
|
||||
Authentifizierung: Die XML API2 verlangt einen Bearer-Token
|
||||
(Authorization-Header, siehe https://boardgamegeek.com/thread/3602374);
|
||||
der Token wird dem Client über den Parameter `token` übergeben (im Betrieb
|
||||
aus `SPIELE_BGG_TOKEN`). Ohne Token lehnt BGG Anfragen mit HTTP 401 ab —
|
||||
der Client wandelt das in eine klare `BggAuthFehler`-Meldung um und versucht
|
||||
es nicht erneut.
|
||||
|
||||
Für Tests sind HTTP-Transport, Uhr und Schlaf-Funktion injizierbar —
|
||||
es gibt keine echten Netzwerk-Aufrufe in der Testsuite.
|
||||
"""
|
||||
@@ -35,6 +42,16 @@ class BggFehler(Exception):
|
||||
"""Fehler bei der Kommunikation mit oder dem Parsen der BGG-API."""
|
||||
|
||||
|
||||
class BggAuthFehler(BggFehler):
|
||||
"""BGG hat die Anfrage wegen fehlender/unültiger Authentifizierung abgelehnt."""
|
||||
|
||||
|
||||
MELDUNG_401 = (
|
||||
"BGG hat die Anfrage abgelehnt (401) — bitte gültigen API-Token "
|
||||
"in SPIELE_BGG_TOKEN hinterlegen."
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SuchTreffer:
|
||||
"""Ein Treffer aus der BGG-Suche."""
|
||||
@@ -161,6 +178,7 @@ class BggClient:
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
token: str | None = None,
|
||||
transport: httpx.BaseTransport | None = None,
|
||||
mindestabstand_sekunden: float = 1.0,
|
||||
max_versuche: int = 4,
|
||||
@@ -174,14 +192,20 @@ class BggClient:
|
||||
self.max_versuche = max_versuche
|
||||
self.backoff_basis_sekunden = backoff_basis_sekunden
|
||||
self.backoff_maximum_sekunden = backoff_maximum_sekunden
|
||||
# Bearer-Token für die XML API2 (Pflicht seit BGG-Umstellung,
|
||||
# https://boardgamegeek.com/thread/3602374); leer/None = nicht gesetzt.
|
||||
self.token = token.strip() if isinstance(token, str) and token.strip() else None
|
||||
self._schlaf = schlaf
|
||||
self._uhr = uhr
|
||||
self._letzter_request_um: float | None = None
|
||||
headers: dict[str, str] = {"User-Agent": USER_AGENT}
|
||||
if self.token:
|
||||
headers["Authorization"] = f"Bearer {self.token}"
|
||||
self._http = httpx.Client(
|
||||
base_url=BASIS_URL,
|
||||
timeout=timeout_sekunden,
|
||||
transport=transport,
|
||||
headers={"User-Agent": USER_AGENT},
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
def schliessen(self) -> None:
|
||||
@@ -214,6 +238,11 @@ class BggClient:
|
||||
if antwort.status_code == 200:
|
||||
return antwort.content
|
||||
|
||||
if antwort.status_code == 401:
|
||||
# Fehlender oder ungültiger Token — dauerhaft, ein Retry
|
||||
# hilft nicht (Token-Pflicht, siehe Thread 3602374).
|
||||
raise BggAuthFehler(MELDUNG_401)
|
||||
|
||||
if antwort.status_code in (202, 429) or antwort.status_code >= 500:
|
||||
# 202: BGG stellt die Anfrage in eine Warteschlange;
|
||||
# 429/5xx: temporär nicht bedienbar → Backoff und erneut.
|
||||
|
||||
Reference in New Issue
Block a user