Merge pull request 'feat(clubs): enhance co-trainer ID handling for training groups' (#26) from develop into main
All checks were successful
Deploy Production / deploy (push) Successful in 35s
Test Suite / pytest-backend (push) Successful in 24s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 6s
Test Suite / playwright-tests (push) Successful in 23s

Reviewed-on: #26
This commit is contained in:
Lars 2026-05-08 13:39:58 +02:00
commit 6136813f60

View File

@ -5,6 +5,7 @@ Handles CRUD operations for clubs, divisions, and training groups.
"""
from typing import Any, List, Optional
from fastapi import APIRouter, HTTPException, Depends, Query
from psycopg2.extras import Json
from db import get_db, get_cursor, r2d
from tenant_context import TenantContext, get_tenant_context
@ -39,6 +40,33 @@ def _optional_int(value: Any) -> Optional[int]:
return i if i > 0 else None
def _normalize_co_trainer_ids(val: Any) -> List[int]:
"""Listen von Profil-IDs für JSONB; ungültige Einträge werden verworfen."""
if val is None:
raw: List[Any] = []
elif isinstance(val, list):
raw = val
else:
raw = []
out: List[int] = []
seen = set()
for x in raw:
try:
i = int(x)
except (TypeError, ValueError):
continue
if i <= 0 or i in seen:
continue
seen.add(i)
out.append(i)
return out
def _co_trainer_ids_jsonb(val: Any) -> Json:
"""psycopg2: reine list/dict für JSONB → ProgrammingError ohne Json()."""
return Json(_normalize_co_trainer_ids(val))
# ── List Clubs ────────────────────────────────────────────────────────
@router.get("/clubs")
def list_clubs(
@ -609,8 +637,7 @@ def create_training_group(data: dict, tenant: TenantContext = Depends(get_tenant
trainer_id = _optional_int(raw_tid)
division_id = _optional_int(data.get("division_id"))
co_raw = data.get("co_trainer_ids")
co_trainer_ids = [] if co_raw is None else co_raw
co_json = _co_trainer_ids_jsonb(data.get("co_trainer_ids"))
with get_db() as conn:
cur = get_cursor(conn)
@ -633,7 +660,7 @@ def create_training_group(data: dict, tenant: TenantContext = Depends(get_tenant
) VALUES (
%s, %s, %s, %s, %s, %s,
%s, %s, %s, %s,
%s, %s, %s
%s, %s::jsonb, %s
) RETURNING id
""",
(
@ -648,7 +675,7 @@ def create_training_group(data: dict, tenant: TenantContext = Depends(get_tenant
_blank_to_none(data.get("time_end")),
_blank_to_none(data.get("location")),
trainer_id,
co_trainer_ids,
co_json,
data.get("status") or "active",
),
)
@ -689,9 +716,7 @@ def update_training_group(group_id: int, data: dict, tenant: TenantContext = Dep
if not allowed:
raise HTTPException(403, "Keine Berechtigung")
co_upd = data.get("co_trainer_ids")
if co_upd is None:
co_upd = []
co_json = _co_trainer_ids_jsonb(data.get("co_trainer_ids"))
cur.execute(
"""
@ -706,7 +731,7 @@ def update_training_group(group_id: int, data: dict, tenant: TenantContext = Dep
time_end = %s,
location = %s,
trainer_id = %s,
co_trainer_ids = %s,
co_trainer_ids = %s::jsonb,
status = %s,
updated_at = NOW()
WHERE id = %s
@ -722,7 +747,7 @@ def update_training_group(group_id: int, data: dict, tenant: TenantContext = Dep
_blank_to_none(data.get("time_end")),
_blank_to_none(data.get("location")),
_optional_int(data.get("trainer_id")),
co_upd,
co_json,
data.get("status") or "active",
group_id,
),