Files
ms1inscription-v5/php/chronotrack_api/fx_chronotrack_oauth.php
stephan 903feebcdb Add synchronization functionality to ChronoTrack API
This commit introduces new synchronization features to the ChronoTrack API, including the ability to preview and push participant data to ChronoTrack. A new push panel is added to the admin interface, allowing users to view eligible participants and initiate synchronization. Additionally, backend functions are implemented to handle synchronization requests, enhancing the overall data management capabilities of the API. These changes aim to streamline the process of updating participant information within the ChronoTrack system.
2026-07-03 09:10:57 -04:00

171 lines
5.9 KiB
PHP

<?php
/**
* MSIN API ChronoTrack — OAuth2 Password Flow + cache token.
*/
function fxChronotrackApiOAuthGetTokenRow() {
global $objDatabase;
$sql = "SELECT * FROM api_chronotrack_token WHERE token_key = '"
. $objDatabase->fxEscape(MSIN_API_CHRONOTRACK_TOKEN_KEY) . "' LIMIT 1";
return $objDatabase->fxGetRow($sql);
}
function fxChronotrackApiOAuthSaveToken($strAccessToken, $strRefreshToken, $intExpiresEpoch) {
global $objDatabase;
$strExpires = '';
if ($intExpiresEpoch > 0) {
$strExpires = date('Y-m-d H:i:s', $intExpiresEpoch);
}
$sqlExists = "SELECT token_key FROM api_chronotrack_token WHERE token_key = '"
. $objDatabase->fxEscape(MSIN_API_CHRONOTRACK_TOKEN_KEY) . "' LIMIT 1";
if ($objDatabase->fxGetRow($sqlExists) !== null) {
$sql = "UPDATE api_chronotrack_token SET access_token = '"
. $objDatabase->fxEscape($strAccessToken) . "', refresh_token = '"
. $objDatabase->fxEscape($strRefreshToken) . "', expires_at = "
. ($strExpires !== '' ? "'" . $objDatabase->fxEscape($strExpires) . "'" : 'NULL')
. ", updated_at = '" . fxGetDateTime() . "' WHERE token_key = '"
. $objDatabase->fxEscape(MSIN_API_CHRONOTRACK_TOKEN_KEY) . "'";
} else {
$sql = "INSERT INTO api_chronotrack_token SET token_key = '"
. $objDatabase->fxEscape(MSIN_API_CHRONOTRACK_TOKEN_KEY) . "', access_token = '"
. $objDatabase->fxEscape($strAccessToken) . "', refresh_token = '"
. $objDatabase->fxEscape($strRefreshToken) . "', expires_at = "
. ($strExpires !== '' ? "'" . $objDatabase->fxEscape($strExpires) . "'" : 'NULL')
. ", updated_at = '" . fxGetDateTime() . "'";
}
$objDatabase->fxQuery($sql);
}
function fxChronotrackApiOAuthTokenValid($arrRow) {
if ($arrRow === null || trim((string)($arrRow['access_token'] ?? '')) === '') {
return false;
}
if (empty($arrRow['expires_at'])) {
return true;
}
$intExpires = strtotime($arrRow['expires_at']);
if ($intExpires === false) {
return true;
}
return ($intExpires > (time() + 120));
}
function fxChronotrackApiOAuthFetchToken($blnForceRefresh = false) {
if (!fxChronotrackApiSettingsConfigured()) {
return array('state' => 'error', 'message' => fxChronotrackApiSettingsErrorMessage());
}
if (!$blnForceRefresh) {
$arrCached = fxChronotrackApiOAuthGetTokenRow();
if (fxChronotrackApiOAuthTokenValid($arrCached)) {
return array(
'state' => 'ok',
'access_token' => $arrCached['access_token'],
'from_cache' => true,
);
}
}
$strBase = fxChronotrackApiGetBaseUrl();
$strQuery = http_build_query(array(
'grant_type' => 'password',
'username' => fxChronotrackApiGetServiceUser(),
'password' => fxChronotrackApiGetServicePass(),
));
$strUrl = $strBase . '/oauth2/token?' . $strQuery;
$arrHttp = fxChronotrackApiHttpRequest('GET', $strUrl, array(
'basic_user' => fxChronotrackApiGetClientId(),
'basic_pass' => fxChronotrackApiGetClientSecret(),
));
if ($arrHttp['state'] !== 'ok' || !is_array($arrHttp['json'])) {
return array(
'state' => 'error',
'message' => fxChronotrackApiHttpGetJsonErrorMessage($arrHttp),
);
}
$strToken = trim((string)($arrHttp['json']['access_token'] ?? ''));
if ($strToken === '') {
return array('state' => 'error', 'message' => 'access_token absent dans la réponse OAuth');
}
$strRefresh = trim((string)($arrHttp['json']['refresh_token'] ?? ''));
$intExpires = intval($arrHttp['json']['expires'] ?? 0);
fxChronotrackApiOAuthSaveToken($strToken, $strRefresh, $intExpires);
return array(
'state' => 'ok',
'access_token' => $strToken,
'from_cache' => false,
);
}
function fxChronotrackApiOAuthApiGet($strPath, $arrQuery = array()) {
$arrToken = fxChronotrackApiOAuthFetchToken(false);
if ($arrToken['state'] !== 'ok') {
return $arrToken;
}
$arrQuery['client_id'] = fxChronotrackApiGetClientId();
$strUrl = fxChronotrackApiGetApiBaseUrl() . '/' . ltrim($strPath, '/');
if (!empty($arrQuery)) {
$strUrl .= '?' . http_build_query($arrQuery);
}
$arrHttp = fxChronotrackApiHttpRequest('GET', $strUrl, array(
'headers' => array('Authorization: Bearer ' . $arrToken['access_token']),
));
if ($arrHttp['state'] === 'ok') {
return array('state' => 'ok', 'json' => $arrHttp['json'], 'http' => $arrHttp);
}
return array(
'state' => 'error',
'message' => fxChronotrackApiHttpGetJsonErrorMessage($arrHttp),
'http' => $arrHttp,
);
}
function fxChronotrackApiOAuthApiPost($strPath, $mixBody, $arrQuery = array()) {
$arrToken = fxChronotrackApiOAuthFetchToken(false);
if ($arrToken['state'] !== 'ok') {
return $arrToken;
}
$arrQuery['client_id'] = fxChronotrackApiGetClientId();
$strUrl = fxChronotrackApiGetApiBaseUrl() . '/' . ltrim($strPath, '/');
if (!empty($arrQuery)) {
$strUrl .= '?' . http_build_query($arrQuery);
}
$strBody = json_encode($mixBody, JSON_UNESCAPED_UNICODE);
if (!is_string($strBody)) {
return array('state' => 'error', 'message' => 'json_encode a échoué');
}
$arrHttp = fxChronotrackApiHttpRequest('POST', $strUrl, array(
'headers' => array(
'Authorization: Bearer ' . $arrToken['access_token'],
'Content-Type: application/json',
'Accept: application/json',
),
'body' => $strBody,
));
if ($arrHttp['state'] === 'ok') {
return array('state' => 'ok', 'json' => $arrHttp['json'], 'http' => $arrHttp);
}
return array(
'state' => 'error',
'message' => fxChronotrackApiHttpGetJsonErrorMessage($arrHttp),
'http' => $arrHttp,
);
}