Commit 102e8b47 authored by Mahmoud Aglan's avatar Mahmoud Aglan

fix: complete Swiss API integration fixes for bot tournament flow

1. Content-Type: application/json only sent when body is not null.
   Swiss API rejects bodiless POST/GET with that header.
2. Controller start() now calls Swiss API /start endpoint.
3. simulateNextRound() auto-starts Swiss tournament if local status
   is still draft/registration.
4. generateRound response parsing fixed — data is in {round:{id,...}}.
5. getPairings response wrapped in {data:[...]} — now handled.
6. Pairing field names use camelCase (whitePlayerId not white_player_id).
7. Player ratings fetched from listPlayers instead of expecting them
   embedded in pairing objects.
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent ea0e40bf
...@@ -16,8 +16,7 @@ class ApiProxy ...@@ -16,8 +16,7 @@ class ApiProxy
public static function swiss(string $method, string $path, ?array $body = null, ?string $token = null): array public static function swiss(string $method, string $path, ?array $body = null, ?string $token = null): array
{ {
$headers = []; $headers = [];
$upperMethod = strtoupper($method); if ($body !== null) {
if ($body !== null || in_array($upperMethod, ['POST', 'PATCH', 'PUT'])) {
$headers[] = 'Content-Type: application/json'; $headers[] = 'Content-Type: application/json';
} }
$authToken = $token ?? self::getSwissToken(); $authToken = $token ?? self::getSwissToken();
......
...@@ -365,6 +365,13 @@ class TournamentsController ...@@ -365,6 +365,13 @@ class TournamentsController
'fideRatingStandard' => $profile['elo_blitz'] ?? 1500, 'fideRatingStandard' => $profile['elo_blitz'] ?? 1500,
]); ]);
} }
// Start tournament in Swiss API
$startResp = ApiProxy::swiss('POST', '/tournaments/' . $tournament['swiss_api_tournament_id'] . '/start');
if (!SwissApiService::isSuccess($startResp)) {
Response::error('فشل في بدء البطولة في Swiss API: ' . SwissApiService::getError($startResp), "/tournaments/{$id}");
return;
}
} }
$this->db->update('el3ab_tournaments', ['id' => "eq.{$id}"], [ $this->db->update('el3ab_tournaments', ['id' => "eq.{$id}"], [
......
...@@ -200,12 +200,23 @@ class BotSimulationService ...@@ -200,12 +200,23 @@ class BotSimulationService
return ['success' => false, 'error' => 'الجولة غير مرتبطة بـ Swiss API']; return ['success' => false, 'error' => 'الجولة غير مرتبطة بـ Swiss API'];
} }
// Get players list for ratings lookup
$playersResp = SwissApiService::listPlayers($tournament['swiss_api_tournament_id']);
$playersBody = SwissApiService::isSuccess($playersResp) ? SwissApiService::getBody($playersResp) : [];
$playersList = $playersBody['data'] ?? $playersBody ?? [];
$ratingsMap = [];
foreach ($playersList as $p) {
$ratingsMap[$p['id']] = $p['fideRatingStandard'] ?? 1200;
}
// Get pairings
$pairingsResponse = SwissApiService::getPairings($swissRoundId); $pairingsResponse = SwissApiService::getPairings($swissRoundId);
if (!SwissApiService::isSuccess($pairingsResponse)) { if (!SwissApiService::isSuccess($pairingsResponse)) {
return ['success' => false, 'error' => 'فشل في جلب المواجهات']; return ['success' => false, 'error' => 'فشل في جلب المواجهات'];
} }
$pairings = SwissApiService::getBody($pairingsResponse); $pairingsBody = SwissApiService::getBody($pairingsResponse);
$pairings = $pairingsBody['data'] ?? $pairingsBody ?? [];
if (empty($pairings)) { if (empty($pairings)) {
return ['success' => false, 'error' => 'لا توجد مواجهات في هذه الجولة']; return ['success' => false, 'error' => 'لا توجد مواجهات في هذه الجولة'];
} }
...@@ -216,14 +227,16 @@ class BotSimulationService ...@@ -216,14 +227,16 @@ class BotSimulationService
foreach ($pairings as $pairing) { foreach ($pairings as $pairing) {
$pairingId = $pairing['id']; $pairingId = $pairing['id'];
if (!empty($pairing['is_bye']) || empty($pairing['black_player_id'])) { if (!empty($pairing['isBye']) || !empty($pairing['is_bye']) || empty($pairing['blackPlayerId'] ?? $pairing['black_player_id'])) {
$results[] = ['pairingId' => $pairingId, 'result' => 'bye_full']; $results[] = ['pairingId' => $pairingId, 'result' => 'bye_full'];
$summary['byes']++; $summary['byes']++;
continue; continue;
} }
$ratingWhite = $pairing['white_player']['fide_rating_standard'] ?? $pairing['white_player']['rating'] ?? 1200; $whiteId = $pairing['whitePlayerId'] ?? $pairing['white_player_id'] ?? '';
$ratingBlack = $pairing['black_player']['fide_rating_standard'] ?? $pairing['black_player']['rating'] ?? 1200; $blackId = $pairing['blackPlayerId'] ?? $pairing['black_player_id'] ?? '';
$ratingWhite = $ratingsMap[$whiteId] ?? 1200;
$ratingBlack = $ratingsMap[$blackId] ?? 1200;
$result = self::simulateResult($ratingWhite, $ratingBlack, $drawRate); $result = self::simulateResult($ratingWhite, $ratingBlack, $drawRate);
$results[] = ['pairingId' => $pairingId, 'result' => $result]; $results[] = ['pairingId' => $pairingId, 'result' => $result];
...@@ -275,6 +288,7 @@ class BotSimulationService ...@@ -275,6 +288,7 @@ class BotSimulationService
return ['success' => false, 'error' => 'البطولة غير موجودة أو غير مرتبطة']; return ['success' => false, 'error' => 'البطولة غير موجودة أو غير مرتبطة'];
} }
$swissTournamentId = $tournament['swiss_api_tournament_id'];
$totalRounds = $tournament['rounds_total'] ?? $tournament['swiss_rounds'] ?? 7; $totalRounds = $tournament['rounds_total'] ?? $tournament['swiss_rounds'] ?? 7;
$currentRound = $tournament['current_round'] ?? 0; $currentRound = $tournament['current_round'] ?? 0;
...@@ -282,14 +296,27 @@ class BotSimulationService ...@@ -282,14 +296,27 @@ class BotSimulationService
return ['success' => true, 'completed' => true, 'round_number' => $currentRound, 'total_rounds' => $totalRounds]; return ['success' => true, 'completed' => true, 'round_number' => $currentRound, 'total_rounds' => $totalRounds];
} }
$genResponse = SwissApiService::generateRound($tournament['swiss_api_tournament_id']); // Auto-start Swiss API tournament if local status is draft/registration
if (in_array($tournament['status'], ['draft', 'registration'])) {
$startResp = ApiProxy::swiss('POST', '/tournaments/' . $swissTournamentId . '/start');
if (!SwissApiService::isSuccess($startResp)) {
return ['success' => false, 'error' => 'فشل في بدء البطولة: ' . SwissApiService::getError($startResp)];
}
$db->update('el3ab_tournaments', ['id' => "eq.{$tournamentId}"], [
'status' => 'in_progress',
'updated_at' => date('c'),
]);
}
$genResponse = SwissApiService::generateRound($swissTournamentId);
if (!SwissApiService::isSuccess($genResponse)) { if (!SwissApiService::isSuccess($genResponse)) {
return ['success' => false, 'error' => 'فشل في إنشاء الجولة: ' . SwissApiService::getError($genResponse)]; return ['success' => false, 'error' => 'فشل في إنشاء الجولة: ' . SwissApiService::getError($genResponse)];
} }
$roundData = SwissApiService::getBody($genResponse); $roundData = SwissApiService::getBody($genResponse);
$swissRoundId = $roundData['id'] ?? $roundData['round_id'] ?? null; $roundInfo = $roundData['round'] ?? $roundData;
$roundNumber = $roundData['round_number'] ?? ($currentRound + 1); $swissRoundId = $roundInfo['id'] ?? null;
$roundNumber = $roundInfo['roundNumber'] ?? $roundInfo['round_number'] ?? ($currentRound + 1);
$roundRecord = $db->insert('el3ab_tournament_rounds', [ $roundRecord = $db->insert('el3ab_tournament_rounds', [
'tournament_id' => $tournamentId, 'tournament_id' => $tournamentId,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment