query( "SELECT c.coachID, c.username, c.supervisorID, sv.username AS supervisorUsername FROM coach c LEFT JOIN supervisor sv ON sv.supervisorID = c.supervisorID ORDER BY sv.username, c.username" )->fetchAll(PDO::FETCH_ASSOC); } else { $stmt = $pdo->prepare( "SELECT c.coachID, c.username, c.supervisorID, sv.username AS supervisorUsername FROM coach c LEFT JOIN supervisor sv ON sv.supervisorID = c.supervisorID WHERE c.supervisorID = :sid ORDER BY c.username" ); $stmt->execute([':sid' => $callerEntityID]); $coaches = $stmt->fetchAll(PDO::FETCH_ASSOC); } [$clause, $params] = rbac_client_filter($tokenRec); $clientStmt = $pdo->prepare( "SELECT cl.clientCode, cl.coachID, co.username AS coachUsername FROM client cl LEFT JOIN coach co ON co.coachID = cl.coachID WHERE $clause ORDER BY cl.coachID, cl.clientCode" ); foreach ($params as $k => $v) $clientStmt->bindValue($k, $v); $clientStmt->execute(); $clients = $clientStmt->fetchAll(PDO::FETCH_ASSOC); qdb_discard($tmpDb, $lockFp); echo json_encode(["success" => true, "coaches" => $coaches, "clients" => $clients]); } catch (Throwable $e) { if (isset($tmpDb, $lockFp)) qdb_discard($tmpDb, $lockFp); http_response_code(500); error_log($e->getMessage()); echo json_encode(["error" => "Server error"]); } exit; } // ── POST: assign clients to a coach ────────────────────────────────────── if ($method === 'POST') { $in = json_decode(file_get_contents('php://input'), true) ?: []; $clientCodes = $in['clientCodes'] ?? []; $coachID = trim($in['coachID'] ?? ''); if (empty($clientCodes) || $coachID === '') { http_response_code(400); echo json_encode(["error" => "clientCodes and coachID required"]); exit; } if (!is_array($clientCodes)) $clientCodes = [$clientCodes]; try { [$pdo, $tmpDb, $lockFp] = qdb_open(true); if ($callerRole === 'supervisor') { $chk = $pdo->prepare("SELECT coachID FROM coach WHERE coachID = :cid AND supervisorID = :sid"); $chk->execute([':cid' => $coachID, ':sid' => $callerEntityID]); } else { $chk = $pdo->prepare("SELECT coachID FROM coach WHERE coachID = :cid"); $chk->execute([':cid' => $coachID]); } if (!$chk->fetch()) { qdb_discard($tmpDb, $lockFp); http_response_code(400); echo json_encode(["error" => "Coach not found or not authorized"]); exit; } // Only allow reassignment of clients the caller can already see [$rbacClause, $rbacParams] = rbac_client_filter($tokenRec); $pdo->beginTransaction(); $updStmt = $pdo->prepare( "UPDATE client SET coachID = :cid WHERE clientCode = :cc AND ($rbacClause)" ); $count = 0; foreach ($clientCodes as $cc) { $cc = trim($cc); if ($cc === '') continue; $updStmt->execute(array_merge([':cid' => $coachID, ':cc' => $cc], $rbacParams)); $count += $updStmt->rowCount(); } $pdo->commit(); qdb_save($tmpDb, $lockFp); echo json_encode(["success" => true, "assigned" => $count]); } catch (Throwable $e) { if (isset($tmpDb, $lockFp)) qdb_discard($tmpDb, $lockFp); http_response_code(500); error_log($e->getMessage()); echo json_encode(["error" => "Server error"]); } exit; } http_response_code(405); echo json_encode(["error" => "Method not allowed"]);