311 lines
12 KiB
PHP
311 lines
12 KiB
PHP
<?php
|
||
/**
|
||
* MSIN API ChronoTrack — config par eve_id (lien event, statut, mapping épreuves).
|
||
*/
|
||
|
||
function fxChronotrackApiConfigGet($intEveId) {
|
||
global $objDatabase;
|
||
|
||
$intEveId = intval($intEveId);
|
||
if ($intEveId <= 0) {
|
||
return null;
|
||
}
|
||
|
||
$sql = "SELECT * FROM api_chronotrack_config WHERE eve_id = " . $intEveId . " LIMIT 1";
|
||
return $objDatabase->fxGetRow($sql);
|
||
}
|
||
|
||
function fxChronotrackApiConfigStatusLabel($strStatus) {
|
||
switch ($strStatus) {
|
||
case MSIN_API_CHRONOTRACK_SYNC_ACTIF:
|
||
return 'Actif';
|
||
case MSIN_API_CHRONOTRACK_SYNC_FERME:
|
||
return 'Fermé';
|
||
case MSIN_API_CHRONOTRACK_SYNC_LIE:
|
||
default:
|
||
return 'Lié';
|
||
}
|
||
}
|
||
|
||
function fxChronotrackApiConfigSaveLink($intEveId, $intCtEventId, $strCtEventName, $strCtEventDate, $intUsaId) {
|
||
global $objDatabase;
|
||
|
||
$intEveId = intval($intEveId);
|
||
$intCtEventId = intval($intCtEventId);
|
||
if ($intEveId <= 0 || $intCtEventId <= 0) {
|
||
return array('state' => 'error', 'message' => 'Identifiants invalides');
|
||
}
|
||
|
||
$arrExisting = fxChronotrackApiConfigGet($intEveId);
|
||
if ($arrExisting !== null && $arrExisting['sync_status'] === MSIN_API_CHRONOTRACK_SYNC_FERME) {
|
||
return array('state' => 'error', 'message' => 'Événement fermé — réouverture non autorisée depuis cette interface.');
|
||
}
|
||
|
||
$strName = $objDatabase->fxEscape(trim($strCtEventName));
|
||
$strDateSql = 'NULL';
|
||
if (trim($strCtEventDate) !== '') {
|
||
$intTs = strtotime($strCtEventDate);
|
||
if ($intTs !== false) {
|
||
$strDateSql = "'" . $objDatabase->fxEscape(date('Y-m-d H:i:s', $intTs)) . "'";
|
||
}
|
||
}
|
||
|
||
if ($arrExisting === null) {
|
||
$sql = "INSERT INTO api_chronotrack_config SET eve_id = " . $intEveId
|
||
. ", ct_event_id = " . $intCtEventId
|
||
. ", ct_event_name = '" . $strName . "'"
|
||
. ", ct_event_date = " . $strDateSql
|
||
. ", sync_status = '" . MSIN_API_CHRONOTRACK_SYNC_LIE . "'"
|
||
. ", linked_at = '" . fxGetDateTime() . "'"
|
||
. ", linked_by_usa_id = " . intval($intUsaId)
|
||
. ", updated_at = '" . fxGetDateTime() . "'";
|
||
} else {
|
||
$sql = "UPDATE api_chronotrack_config SET ct_event_id = " . $intCtEventId
|
||
. ", ct_event_name = '" . $strName . "'"
|
||
. ", ct_event_date = " . $strDateSql
|
||
. ", updated_at = '" . fxGetDateTime() . "'"
|
||
. " WHERE eve_id = " . $intEveId
|
||
. " AND sync_status <> '" . MSIN_API_CHRONOTRACK_SYNC_FERME . "'";
|
||
}
|
||
|
||
if (!$objDatabase->fxQuery($sql)) {
|
||
return array('state' => 'error', 'message' => 'Erreur SQL enregistrement lien');
|
||
}
|
||
|
||
return array('state' => 'ok');
|
||
}
|
||
|
||
function fxChronotrackApiConfigSetStatus($intEveId, $strStatus, $intUsaId) {
|
||
global $objDatabase;
|
||
|
||
$intEveId = intval($intEveId);
|
||
$arrExisting = fxChronotrackApiConfigGet($intEveId);
|
||
if ($arrExisting === null) {
|
||
return array('state' => 'error', 'message' => 'Aucun lien ChronoTrack pour cet événement');
|
||
}
|
||
|
||
if ($arrExisting['sync_status'] === MSIN_API_CHRONOTRACK_SYNC_FERME) {
|
||
if ($strStatus !== MSIN_API_CHRONOTRACK_SYNC_LIE) {
|
||
return array('state' => 'error', 'message' => 'Événement fermé — seule la réouverture (Lié) est permise.');
|
||
}
|
||
}
|
||
|
||
$strStatus = trim($strStatus);
|
||
if (!in_array($strStatus, array(MSIN_API_CHRONOTRACK_SYNC_LIE, MSIN_API_CHRONOTRACK_SYNC_ACTIF, MSIN_API_CHRONOTRACK_SYNC_FERME), true)) {
|
||
return array('state' => 'error', 'message' => 'Statut invalide');
|
||
}
|
||
|
||
$strExtra = '';
|
||
if ($strStatus === MSIN_API_CHRONOTRACK_SYNC_ACTIF) {
|
||
$strExtra = ", activated_at = '" . fxGetDateTime() . "'";
|
||
}
|
||
if ($strStatus === MSIN_API_CHRONOTRACK_SYNC_FERME) {
|
||
$strExtra = ", closed_at = '" . fxGetDateTime() . "', closed_by_usa_id = " . intval($intUsaId);
|
||
}
|
||
if ($strStatus === MSIN_API_CHRONOTRACK_SYNC_LIE && $arrExisting['sync_status'] === MSIN_API_CHRONOTRACK_SYNC_FERME) {
|
||
$strExtra = ", closed_at = NULL, closed_by_usa_id = NULL";
|
||
}
|
||
|
||
$sql = "UPDATE api_chronotrack_config SET sync_status = '" . $objDatabase->fxEscape($strStatus) . "'"
|
||
. $strExtra
|
||
. ", updated_at = '" . fxGetDateTime() . "'"
|
||
. " WHERE eve_id = " . $intEveId;
|
||
if (!$objDatabase->fxQuery($sql)) {
|
||
return array('state' => 'error', 'message' => 'Erreur SQL changement statut');
|
||
}
|
||
|
||
return array('state' => 'ok');
|
||
}
|
||
|
||
/**
|
||
* MSIN-4328 — mémorise la fin d’un push réussi (référence pour par_maj).
|
||
*/
|
||
function fxChronotrackApiConfigSetLastPush($intEveId, $intOkCount) {
|
||
global $objDatabase;
|
||
|
||
$intEveId = intval($intEveId);
|
||
if ($intEveId <= 0) {
|
||
return false;
|
||
}
|
||
|
||
$sql = "UPDATE api_chronotrack_config SET last_push_at = '" . fxGetDateTime() . "'"
|
||
. ", last_push_ok_count = " . max(0, intval($intOkCount))
|
||
. ", updated_at = '" . fxGetDateTime() . "'"
|
||
. " WHERE eve_id = " . $intEveId;
|
||
return (bool)$objDatabase->fxQuery($sql);
|
||
}
|
||
|
||
/**
|
||
* MSIN-4328 — fréquences autorisées (minutes), phase A.
|
||
*/
|
||
function fxChronotrackApiConfigAutoSyncIntervals() {
|
||
return array(1, 5, 15, 30, 60);
|
||
}
|
||
|
||
/**
|
||
* MSIN-4328 — enregistre la config sync auto (UI). Le cron (phase B) lira ces champs.
|
||
*/
|
||
function fxChronotrackApiConfigSaveAutoSync($intEveId, $blnEnabled, $intIntervalMin, $strUntil) {
|
||
global $objDatabase;
|
||
|
||
$intEveId = intval($intEveId);
|
||
$arrExisting = fxChronotrackApiConfigGet($intEveId);
|
||
if ($arrExisting === null) {
|
||
return array('state' => 'error', 'message' => 'Événement non lié à ChronoTrack');
|
||
}
|
||
if (($arrExisting['sync_status'] ?? '') === MSIN_API_CHRONOTRACK_SYNC_FERME) {
|
||
return array('state' => 'error', 'message' => 'Événement fermé — sync auto impossible.');
|
||
}
|
||
|
||
$blnEnabled = $blnEnabled ? 1 : 0;
|
||
$intIntervalMin = intval($intIntervalMin);
|
||
if (!in_array($intIntervalMin, fxChronotrackApiConfigAutoSyncIntervals(), true)) {
|
||
$intIntervalMin = 15;
|
||
}
|
||
|
||
$strUntilSql = 'NULL';
|
||
$strUntil = trim((string)$strUntil);
|
||
if ($strUntil !== '') {
|
||
// Accepte "YYYY-MM-DDTHH:MM" (input datetime-local) ou "YYYY-MM-DD HH:MM[:SS]"
|
||
$strUntilNorm = str_replace('T', ' ', $strUntil);
|
||
if (preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/', $strUntilNorm)) {
|
||
$strUntilNorm .= ':00';
|
||
}
|
||
$intTs = strtotime($strUntilNorm);
|
||
if ($intTs === false) {
|
||
return array('state' => 'error', 'message' => 'Date / heure de fin invalide');
|
||
}
|
||
if ($blnEnabled && $intTs <= time()) {
|
||
return array('state' => 'error', 'message' => 'La date/heure de fin doit être dans le futur');
|
||
}
|
||
$strUntilSql = "'" . $objDatabase->fxEscape(date('Y-m-d H:i:s', $intTs)) . "'";
|
||
} elseif ($blnEnabled) {
|
||
return array('state' => 'error', 'message' => 'Indiquez une date et une heure de fin pour activer la sync auto');
|
||
}
|
||
|
||
$sql = "UPDATE api_chronotrack_config SET auto_sync_enabled = " . $blnEnabled
|
||
. ", auto_sync_interval_min = " . $intIntervalMin
|
||
. ", auto_sync_until = " . $strUntilSql
|
||
. ", updated_at = '" . fxGetDateTime() . "'"
|
||
. " WHERE eve_id = " . $intEveId;
|
||
if (!$objDatabase->fxQuery($sql)) {
|
||
return array('state' => 'error', 'message' => 'Erreur SQL enregistrement sync auto');
|
||
}
|
||
|
||
$arrFresh = fxChronotrackApiConfigGet($intEveId);
|
||
return array(
|
||
'state' => 'ok',
|
||
'message' => $blnEnabled
|
||
? ('Sync auto enregistrée (toutes les ' . $intIntervalMin . ' min jusqu’au '
|
||
. trim((string)($arrFresh['auto_sync_until'] ?? '')) . '). Le cron démarrera en phase B.')
|
||
: 'Sync auto désactivée.',
|
||
'auto_sync' => array(
|
||
'enabled' => intval($arrFresh['auto_sync_enabled'] ?? 0) === 1,
|
||
'interval_min' => intval($arrFresh['auto_sync_interval_min'] ?? 15),
|
||
'until' => ($arrFresh['auto_sync_until'] ?? null),
|
||
'last_run_at' => ($arrFresh['last_auto_run_at'] ?? null),
|
||
),
|
||
);
|
||
}
|
||
|
||
function fxChronotrackApiRaceMapGetForEvent($intEveId) {
|
||
global $objDatabase;
|
||
|
||
$sql = "SELECT * FROM api_chronotrack_race_map WHERE eve_id = " . intval($intEveId);
|
||
$arrRows = $objDatabase->fxGetResults($sql);
|
||
$arrMap = array();
|
||
if ($arrRows !== null) {
|
||
for ($i = 1; $i <= count($arrRows); $i++) {
|
||
$arrMap[intval($arrRows[$i]['epr_id'])] = $arrRows[$i];
|
||
}
|
||
}
|
||
return $arrMap;
|
||
}
|
||
|
||
function fxChronotrackApiMs1EpreuvesForEvent($intEveId, $strLangue = 'fr') {
|
||
global $objDatabase;
|
||
|
||
$strLangue = ($strLangue === 'en') ? 'en' : 'fr';
|
||
$sql = "SELECT epr_id, epr_nom_" . $strLangue . " AS epr_nom, epr_type_" . $strLangue . " AS epr_type, epr_date"
|
||
. " FROM inscriptions_epreuves WHERE eve_id = " . intval($intEveId)
|
||
. " ORDER BY epr_date, epr_nom_" . $strLangue;
|
||
return $objDatabase->fxGetResults($sql);
|
||
}
|
||
|
||
function fxChronotrackApiRaceMapSave($intEveId, $arrMapInput) {
|
||
global $objDatabase;
|
||
|
||
$intEveId = intval($intEveId);
|
||
$arrExisting = fxChronotrackApiConfigGet($intEveId);
|
||
if ($arrExisting === null) {
|
||
return array('state' => 'error', 'message' => 'Lier d\'abord un événement ChronoTrack');
|
||
}
|
||
if ($arrExisting['sync_status'] === MSIN_API_CHRONOTRACK_SYNC_FERME) {
|
||
return array('state' => 'error', 'message' => 'Événement fermé — mapping en lecture seule');
|
||
}
|
||
|
||
if (!is_array($arrMapInput)) {
|
||
return array('state' => 'error', 'message' => 'Mapping invalide');
|
||
}
|
||
|
||
foreach ($arrMapInput as $intEprId => $arrRace) {
|
||
$intEprId = intval($intEprId);
|
||
$intCtRaceId = intval($arrRace['ct_race_id'] ?? 0);
|
||
$strCtRaceName = trim((string)($arrRace['ct_race_name'] ?? ''));
|
||
|
||
if ($intEprId <= 0) {
|
||
continue;
|
||
}
|
||
if ($intCtRaceId <= 0) {
|
||
$sqlDel = "DELETE FROM api_chronotrack_race_map WHERE eve_id = " . $intEveId . " AND epr_id = " . $intEprId;
|
||
$objDatabase->fxQuery($sqlDel);
|
||
continue;
|
||
}
|
||
|
||
$sqlExists = "SELECT map_id FROM api_chronotrack_race_map WHERE eve_id = " . $intEveId
|
||
. " AND epr_id = " . $intEprId . " LIMIT 1";
|
||
if ($objDatabase->fxGetRow($sqlExists) !== null) {
|
||
$sql = "UPDATE api_chronotrack_race_map SET ct_race_id = " . $intCtRaceId
|
||
. ", ct_race_name = '" . $objDatabase->fxEscape($strCtRaceName) . "'"
|
||
. ", updated_at = '" . fxGetDateTime() . "'"
|
||
. " WHERE eve_id = " . $intEveId . " AND epr_id = " . $intEprId;
|
||
} else {
|
||
$sql = "INSERT INTO api_chronotrack_race_map SET eve_id = " . $intEveId
|
||
. ", epr_id = " . $intEprId
|
||
. ", ct_race_id = " . $intCtRaceId
|
||
. ", ct_race_name = '" . $objDatabase->fxEscape($strCtRaceName) . "'"
|
||
. ", updated_at = '" . fxGetDateTime() . "'";
|
||
}
|
||
$objDatabase->fxQuery($sql);
|
||
}
|
||
|
||
return array('state' => 'ok');
|
||
}
|
||
|
||
function fxChronotrackApiMs1EventRow($intEveId, $strLangue = 'fr') {
|
||
global $objDatabase;
|
||
|
||
$strLangue = ($strLangue === 'en') ? 'en' : 'fr';
|
||
$sql = "SELECT eve_id, eve_nom_" . $strLangue . " AS eve_nom, eve_date_debut, eve_date_fin"
|
||
. " FROM inscriptions_evenements WHERE eve_id = " . intval($intEveId) . " LIMIT 1";
|
||
return $objDatabase->fxGetRow($sql);
|
||
}
|
||
|
||
function fxChronotrackApiListActiveConfigs($arrStatuses = null) {
|
||
global $objDatabase;
|
||
|
||
if ($arrStatuses === null) {
|
||
$arrStatuses = array(MSIN_API_CHRONOTRACK_SYNC_LIE, MSIN_API_CHRONOTRACK_SYNC_ACTIF);
|
||
}
|
||
$arrEsc = array();
|
||
foreach ($arrStatuses as $strStatus) {
|
||
$arrEsc[] = "'" . $objDatabase->fxEscape($strStatus) . "'";
|
||
}
|
||
$sql = "SELECT c.*, e.eve_nom_fr AS eve_nom"
|
||
. " FROM api_chronotrack_config c"
|
||
. " INNER JOIN inscriptions_evenements e ON e.eve_id = c.eve_id"
|
||
. " WHERE c.sync_status IN (" . implode(',', $arrEsc) . ")"
|
||
. " ORDER BY c.sync_status DESC, c.updated_at DESC";
|
||
return $objDatabase->fxGetResults($sql);
|
||
}
|