diff --git a/backend/routers/clubs.py b/backend/routers/clubs.py index 7507709..bca67e9 100644 --- a/backend/routers/clubs.py +++ b/backend/routers/clubs.py @@ -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, ),