feat(clubs): enhance co-trainer ID handling for training groups
All checks were successful
Deploy Development / deploy (push) Successful in 37s
Test Suite / pytest-backend (push) Successful in 25s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 8s
Test Suite / playwright-tests (push) Successful in 23s
Test Suite / pytest-backend (pull_request) Successful in 23s
Test Suite / lint-backend (pull_request) Successful in 0s
Test Suite / build-frontend (pull_request) Successful in 7s
Test Suite / playwright-tests (pull_request) Successful in 26s

- Introduced new functions to normalize and convert co-trainer IDs for JSONB storage.
- Updated `create_training_group` and `update_training_group` methods to utilize the new JSONB handling for co-trainer IDs.
- Ensured invalid entries are discarded and only unique, positive integers are stored.
This commit is contained in:
Lars 2026-05-08 13:37:30 +02:00
parent bab9b178a4
commit a7cecca36f

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,
),