Compare commits

...

2 Commits

Author SHA1 Message Date
6136813f60 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
2026-05-08 13:39:58 +02:00
a7cecca36f 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.
2026-05-08 13:37:30 +02:00

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