chore(version): update version and changelog for release 0.8.123
All checks were successful
Deploy Development / deploy (push) Successful in 41s
Test Suite / pytest-backend (push) Successful in 36s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 12s
Test Suite / k6 /health Baseline (push) Successful in 33s
Test Suite / playwright-tests (push) Successful in 1m2s
Test Suite / pytest-backend (pull_request) Successful in 34s
Test Suite / lint-backend (pull_request) Successful in 0s
Test Suite / build-frontend (pull_request) Successful in 12s
Test Suite / k6 /health Baseline (pull_request) Successful in 33s
Test Suite / playwright-tests (pull_request) Successful in 1m1s

- Bumped APP_VERSION to 0.8.123 and updated the changelog to reflect recent changes.
- Fixed internal calls in GET /api/dashboard/kpis to use unwrap_query_default, preventing 500 errors due to FastAPI query defaults.
- Enhanced list_exercises and list_training_units functions to utilize unwrap_query_default for improved query handling.
- Added unit tests for unwrap_query_default to ensure correct behavior in various scenarios.
This commit is contained in:
Lars 2026-05-14 11:48:11 +02:00
parent 4235246cd7
commit 2e105a99b8
5 changed files with 55 additions and 2 deletions

View File

@ -0,0 +1,16 @@
"""Hilfen für direkte Python-Aufrufe von FastAPI-Route-Handlern (ohne Request-Kontext)."""
from __future__ import annotations
from typing import Any
def unwrap_query_default(value: Any) -> Any:
"""
Parameter mit Annotation ``= Query(default=)`` sind im Funktionskörper ``fastapi.params.Query``-Instanzen,
solange FastAPI sie nicht durch echte Werte ersetzt hat (interne Aufrufe, Aggregat-Endpunkte).
"""
try:
from fastapi.params import Query
except ImportError:
return value
return value.default if isinstance(value, Query) else value

View File

@ -19,6 +19,8 @@ from fastapi.responses import FileResponse, Response, StreamingResponse
from pydantic import BaseModel, Field, model_validator
from psycopg2.extras import Json
from fastapi_param_unwrap import unwrap_query_default
from db import get_db, get_cursor, r2d
from club_tenancy import (
assert_valid_governance_visibility,
@ -1773,6 +1775,11 @@ def list_exercises(
Optional include_variants für Variantenauswahl in der Trainingsplanung.
Keyset: cursor_updated_at + cursor_id ersetzt große OFFSET-Werte (Sortierung: updated_at DESC, id DESC).
"""
cursor_updated_at = unwrap_query_default(cursor_updated_at)
cursor_id = unwrap_query_default(cursor_id)
limit = unwrap_query_default(limit)
offset = unwrap_query_default(offset)
profile_id = tenant.profile_id
c_ts_raw = (cursor_updated_at or "").strip() or None

View File

@ -10,6 +10,8 @@ from typing import Any, Dict, List, Optional, Tuple
from fastapi import APIRouter, Depends, HTTPException, Query
from psycopg2.extras import Json as PsycopgJson
from fastapi_param_unwrap import unwrap_query_default
from db import get_db, get_cursor, r2d
from tenant_context import TenantContext, get_tenant_context, library_content_visibility_sql
from club_tenancy import (
@ -1341,6 +1343,19 @@ def list_training_units(
),
tenant: TenantContext = Depends(get_tenant_context),
):
group_id = unwrap_query_default(group_id)
club_id = unwrap_query_default(club_id)
start_date = unwrap_query_default(start_date)
end_date = unwrap_query_default(end_date)
status = unwrap_query_default(status)
assigned_to_me = unwrap_query_default(assigned_to_me)
debrief_pending = unwrap_query_default(debrief_pending)
sort = unwrap_query_default(sort)
limit = unwrap_query_default(limit)
cursor_planned_date = unwrap_query_default(cursor_planned_date)
cursor_planned_time = unwrap_query_default(cursor_planned_time)
cursor_id = unwrap_query_default(cursor_id)
profile_id = tenant.profile_id
role = tenant.global_role

View File

@ -1,13 +1,15 @@
"""GET /api/dashboard/kpis: Auth (kein DB nötig)."""
"""GET /api/dashboard/kpis: Auth + interne Aufruf-Hilfen."""
from __future__ import annotations
import os
import pytest
from fastapi import Query
from fastapi.testclient import TestClient
os.environ.setdefault("SKIP_DB_MIGRATE", "1")
from fastapi_param_unwrap import unwrap_query_default
from main import app
@ -16,6 +18,12 @@ def client() -> TestClient:
return TestClient(app)
def test_unwrap_query_default_for_direct_route_calls() -> None:
assert unwrap_query_default(Query(default=None)) is None
assert unwrap_query_default("2026-01-01") == "2026-01-01"
assert unwrap_query_default(7) == 7
def test_dashboard_kpis_unauthenticated_401(client: TestClient) -> None:
r = client.get("/api/dashboard/kpis")
assert r.status_code == 401

View File

@ -1,6 +1,6 @@
# Shinkan Jinkendo Version Information
APP_VERSION = "0.8.122"
APP_VERSION = "0.8.123"
BUILD_DATE = "2026-05-12"
DB_SCHEMA_VERSION = "20260514062"
@ -36,6 +36,13 @@ MODULE_VERSIONS = {
}
CHANGELOG = [
{
"version": "0.8.123",
"date": "2026-05-13",
"changes": [
"Fix: GET /api/dashboard/kpis — interne Aufrufe von list_exercises / list_training_units erhielten FastAPI-Query-Defaults statt None; .strip() auf Query-Objekt → 500. unwrap_query_default in beiden Handlern (Hilfsmodul fastapi_param_unwrap.py).",
],
},
{
"version": "0.8.122",
"date": "2026-05-13",