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
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:
parent
4235246cd7
commit
2e105a99b8
16
backend/fastapi_param_unwrap.py
Normal file
16
backend/fastapi_param_unwrap.py
Normal 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
|
||||||
|
|
@ -19,6 +19,8 @@ from fastapi.responses import FileResponse, Response, StreamingResponse
|
||||||
from pydantic import BaseModel, Field, model_validator
|
from pydantic import BaseModel, Field, model_validator
|
||||||
from psycopg2.extras import Json
|
from psycopg2.extras import Json
|
||||||
|
|
||||||
|
from fastapi_param_unwrap import unwrap_query_default
|
||||||
|
|
||||||
from db import get_db, get_cursor, r2d
|
from db import get_db, get_cursor, r2d
|
||||||
from club_tenancy import (
|
from club_tenancy import (
|
||||||
assert_valid_governance_visibility,
|
assert_valid_governance_visibility,
|
||||||
|
|
@ -1773,6 +1775,11 @@ def list_exercises(
|
||||||
Optional include_variants für Variantenauswahl in der Trainingsplanung.
|
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).
|
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
|
profile_id = tenant.profile_id
|
||||||
|
|
||||||
c_ts_raw = (cursor_updated_at or "").strip() or None
|
c_ts_raw = (cursor_updated_at or "").strip() or None
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ from typing import Any, Dict, List, Optional, Tuple
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||||
from psycopg2.extras import Json as PsycopgJson
|
from psycopg2.extras import Json as PsycopgJson
|
||||||
|
|
||||||
|
from fastapi_param_unwrap import unwrap_query_default
|
||||||
|
|
||||||
from db import get_db, get_cursor, r2d
|
from db import get_db, get_cursor, r2d
|
||||||
from tenant_context import TenantContext, get_tenant_context, library_content_visibility_sql
|
from tenant_context import TenantContext, get_tenant_context, library_content_visibility_sql
|
||||||
from club_tenancy import (
|
from club_tenancy import (
|
||||||
|
|
@ -1341,6 +1343,19 @@ def list_training_units(
|
||||||
),
|
),
|
||||||
tenant: TenantContext = Depends(get_tenant_context),
|
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
|
profile_id = tenant.profile_id
|
||||||
role = tenant.global_role
|
role = tenant.global_role
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
from __future__ import annotations
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from fastapi import Query
|
||||||
from fastapi.testclient import TestClient
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
os.environ.setdefault("SKIP_DB_MIGRATE", "1")
|
os.environ.setdefault("SKIP_DB_MIGRATE", "1")
|
||||||
|
|
||||||
|
from fastapi_param_unwrap import unwrap_query_default
|
||||||
from main import app
|
from main import app
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -16,6 +18,12 @@ def client() -> TestClient:
|
||||||
return TestClient(app)
|
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:
|
def test_dashboard_kpis_unauthenticated_401(client: TestClient) -> None:
|
||||||
r = client.get("/api/dashboard/kpis")
|
r = client.get("/api/dashboard/kpis")
|
||||||
assert r.status_code == 401
|
assert r.status_code == 401
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Shinkan Jinkendo Version Information
|
# Shinkan Jinkendo Version Information
|
||||||
|
|
||||||
APP_VERSION = "0.8.122"
|
APP_VERSION = "0.8.123"
|
||||||
BUILD_DATE = "2026-05-12"
|
BUILD_DATE = "2026-05-12"
|
||||||
DB_SCHEMA_VERSION = "20260514062"
|
DB_SCHEMA_VERSION = "20260514062"
|
||||||
|
|
||||||
|
|
@ -36,6 +36,13 @@ MODULE_VERSIONS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
CHANGELOG = [
|
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",
|
"version": "0.8.122",
|
||||||
"date": "2026-05-13",
|
"date": "2026-05-13",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user