This commit introduces a new feature to wipe all entries from ChronoTrack Live for a specific event, including user confirmation prompts and error handling. Additionally, it enhances the participant synchronization process by refining the handling of entry data and improving the reporting of synchronization results. The admin interface is updated to include a new button for the wipe action, providing clearer user feedback and control over event data management. These changes aim to streamline the management of ChronoTrack entries and improve the overall user experience within the API.
201 lines
6.9 KiB
PHP
201 lines
6.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,
|
|
);
|
|
}
|
|
|
|
function fxChronotrackApiOAuthApiDelete($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('DELETE', $strUrl, array(
|
|
'headers' => array(
|
|
'Authorization: Bearer ' . $arrToken['access_token'],
|
|
'Accept: application/json',
|
|
),
|
|
));
|
|
|
|
if ($arrHttp['state'] === 'ok') {
|
|
return array('state' => 'ok', 'json' => $arrHttp['json'], 'http' => $arrHttp);
|
|
}
|
|
|
|
return array(
|
|
'state' => 'error',
|
|
'message' => fxChronotrackApiHttpGetJsonErrorMessage($arrHttp),
|
|
'http' => $arrHttp,
|
|
);
|
|
}
|