From 899ba89a2b781fe3a6de683935c278a98673c3dd Mon Sep 17 00:00:00 2001 From: stephan Date: Mon, 13 Jul 2026 19:23:36 -0400 Subject: [PATCH] Update version code to 4.72.821, enhance error handling in JavaScript and PHP for better user feedback, and improve access control for report preferences in super admin actions. Refactor alert messages and database insert logic to provide clearer error messages and ensure proper session handling. --- inc_footer_scripts.php | 2 +- js/v2/bib-assignments.js | 16 ++-- php/inc_fx_bib_global_generated.php | 36 +++++++- php/inc_fx_promoteur.php | 5 ++ php/inc_settings.php | 2 +- sql/MSIN-4443-bib-gen-create-error-msg.sql | 15 ++++ superadm/enregistrer.php | 95 +++++++++++++++++++--- 7 files changed, 148 insertions(+), 23 deletions(-) create mode 100644 sql/MSIN-4443-bib-gen-create-error-msg.sql diff --git a/inc_footer_scripts.php b/inc_footer_scripts.php index df8786a..4936e92 100644 --- a/inc_footer_scripts.php +++ b/inc_footer_scripts.php @@ -359,7 +359,7 @@ if ($strLangue == 'fr') { $link.html(''); } } else { - alert($result.state); + alert(($result && ($result.message || $result.state)) || 'Erreur'); } $preloader.fadeOut(); diff --git a/js/v2/bib-assignments.js b/js/v2/bib-assignments.js index f670751..4816fa3 100644 --- a/js/v2/bib-assignments.js +++ b/js/v2/bib-assignments.js @@ -1080,13 +1080,15 @@ }) .then(function (res) { if (!res.ok) { - throw new Error(bibJs('jsErrGeneric')); + throw new Error(bibJs('jsErrGeneric') || 'Erreur'); } - return res.json(); + return res.json().catch(function () { + throw new Error(bibJs('jsServerError') || bibJs('jsErrGeneric') || 'Erreur serveur'); + }); }) .then(function (createData) { - if (!createData || !createData.success || !createData.plans) { - throw new Error((createData && createData.message) || bibJs('jsErrGeneric')); + if (!createData || !createData.success || !Array.isArray(createData.plans) || createData.plans.length === 0) { + throw new Error((createData && createData.message) || bibJs('jsErrGeneric') || 'Erreur'); } var plans = createData.plans; @@ -1104,7 +1106,11 @@ chain = chain.then(function () { var row = moduleBib.querySelector('.epr-row[data-epr-id="' + plan.epr_id + '"]'); if (!row) { - throw new Error(bibJs('jsErrGeneric')); + throw new Error( + bibJs('jsGlobalGenEprMissing') + || bibJs('jsErrGeneric') + || 'Épreuve introuvable — rechargez la page.' + ); } var pendingBefore = bibRowPendingBibs(row); diff --git a/php/inc_fx_bib_global_generated.php b/php/inc_fx_bib_global_generated.php index a7533bc..84d8a9e 100644 --- a/php/inc_fx_bib_global_generated.php +++ b/php/inc_fx_bib_global_generated.php @@ -297,18 +297,46 @@ function fxBibCreateGeneratedRanges($int_eve_id, $tabPlan, $strLangue = 'fr') { ]; } - $objDatabase->fxQuery(" + // MSIN-4443 — Création séquence : vérifier INSERT + last_id (évite le message générique « Erreur »). + $sqlInsert = " INSERT INTO inscriptions_epreuves_bib (epr_id, epr_bib_start, epr_bib_finish, update_date, update_qui, eve_id) VALUES ($epr_id, $intStart, $intEnd, NOW(), 'admin', $int_eve_id) - "); + "; + $qryInsert = $objDatabase->fxQuery($sqlInsert); + if ($qryInsert === false) { + return [ + 'success' => false, + 'message' => fxBibMsg('bib_v4_global_batch_gen_insert_failed'), + ]; + } + + $intBibId = 0; + if (method_exists($objDatabase, 'fxGetLastId')) { + $intBibId = (int)$objDatabase->fxGetLastId(); + } elseif (isset($objDatabase->last_id)) { + $intBibId = (int)$objDatabase->last_id; + } + + // Repli : si insert_id absent, retrouver la ligne fraîchement créée. + if ($intBibId <= 0) { + $intBibId = (int)$objDatabase->fxGetVar(" + SELECT epr_bib_id + FROM inscriptions_epreuves_bib + WHERE epr_id = $epr_id + AND epr_bib_start = $intStart + AND epr_bib_finish = $intEnd + AND eve_id = $int_eve_id + ORDER BY epr_bib_id DESC + LIMIT 1 + "); + } - $intBibId = (int)($objDatabase->last_id ?? 0); if ($intBibId <= 0) { return [ 'success' => false, - 'message' => fxBibMsg('bib_v4_ajax_error'), + 'message' => fxBibMsg('bib_v4_global_batch_gen_insert_failed'), ]; } diff --git a/php/inc_fx_promoteur.php b/php/inc_fx_promoteur.php index 59eb0d4..42e2da6 100644 --- a/php/inc_fx_promoteur.php +++ b/php/inc_fx_promoteur.php @@ -3331,6 +3331,9 @@ function fxBibStaticFallback($clef) { 'bib_v4_global_batch_gen_no_pending' => ['fr' => 'Aucune inscription à assigner dans les épreuves sélectionnées.', 'en' => 'No registrations to assign in the selected races.'], 'bib_v4_global_batch_gen_has_seq' => ['fr' => 'Une épreuve sélectionnée a déjà une séquence — rechargez le panneau.', 'en' => 'A selected race already has a sequence — reload the panel.'], 'bib_v4_global_batch_gen_no_start' => ['fr' => 'Indiquez le numéro du premier dossard.', 'en' => 'Enter the first bib number.'], + 'bib_v4_global_batch_gen_insert_failed' => ['fr' => 'Impossible de créer la séquence de dossards. Réessayez ou rechargez la page.', 'en' => 'Could not create the bib sequence. Try again or reload the page.'], + 'bib_v4_js_global_gen_epr_missing' => ['fr' => 'Épreuve introuvable sur la page après création des séquences. Rechargez la page puis réessayez.', 'en' => 'Race not found on the page after creating sequences. Reload the page and try again.'], + 'bib_v4_ajax_error' => ['fr' => 'Erreur', 'en' => 'Error'], 'bib_v4_global_batch_unavailable' => ['fr' => 'Aucune assignation globale disponible pour cet événement.', 'en' => 'No global assignment available for this event.'], 'bib_v4_ajax_global_gen_sim_summary' => ['fr' => '%d épreuve(s) · %d dossards · %d à assigner', 'en' => '%d race(s) · %d bibs · %d to assign'], 'bib_v4_ajax_global_gen_analysis' => ['fr' => '%d épreuve(s) · plage %d → %d · %d à assigner', 'en' => '%d race(s) · range %d → %d · %d to assign'], @@ -3589,6 +3592,7 @@ function fxBibModuleJsDataAttrs() { 'global-no-epr' => 'bib_v4_js_global_no_epr', 'global-no-seq' => 'bib_v4_js_global_no_seq', 'global-gen-no-start' => 'bib_v4_global_batch_gen_no_start', + 'global-gen-epr-missing' => 'bib_v4_js_global_gen_epr_missing', 'global-gen-no-epr' => 'bib_v4_js_global_no_epr', 'global-batch-finalizing' => 'bib_v4_js_global_batch_finalizing', 'global-batch-complete-title' => 'bib_v4_global_batch_go_complete_title', @@ -4775,6 +4779,7 @@ function renderBibGlobalBatchPanelGenerated($int_eve_id, $tabEpreuves, $strLangu class="form-control form-control-sm bib-global-gen-start-bib" min="1" step="1" + value="1" inputmode="numeric" placeholder="1"> diff --git a/php/inc_settings.php b/php/inc_settings.php index b0d1a1d..2a6aac1 100644 --- a/php/inc_settings.php +++ b/php/inc_settings.php @@ -7,7 +7,7 @@ * Constantes * * **************/ -define('_VERSION_CODE', '4.72.819'); +define('_VERSION_CODE', '4.72.821'); define('_DATE_CODE', '2026-07-13'); //MSIN-4290 define('QR_SECRET_KEY', 'ms1_qr_2026_cle_secrete_longue_et_fixe'); diff --git a/sql/MSIN-4443-bib-gen-create-error-msg.sql b/sql/MSIN-4443-bib-gen-create-error-msg.sql new file mode 100644 index 0000000..80f6689 --- /dev/null +++ b/sql/MSIN-4443-bib-gen-create-error-msg.sql @@ -0,0 +1,15 @@ +-- MSIN-4443 — Message d'erreur création séquences (assignation globale sans séquence) +-- Contexte : remplace le message trop vague « Erreur » (bib_v4_ajax_error) sur échec INSERT +-- Notes prod : idempotent + +DELETE FROM info +WHERE info_clef IN ( + 'bib_v4_global_batch_gen_insert_failed', + 'bib_v4_js_global_gen_epr_missing' +) AND info_prg = 'compte.php'; + +INSERT INTO info (info_clef, info_langue, info_texte, info_aide, info_prg, info_description, info_trie, info_actif, info_option1, info_option2, info_option3, info_creation) VALUES +('bib_v4_global_batch_gen_insert_failed', 'fr', 'Impossible de créer la séquence de dossards. Réessayez ou rechargez la page.', '', 'compte.php', '', 0, 1, '', '', '', NOW()), +('bib_v4_global_batch_gen_insert_failed', 'en', 'Could not create the bib sequence. Try again or reload the page.', '', 'compte.php', '', 0, 1, '', '', '', NOW()), +('bib_v4_js_global_gen_epr_missing', 'fr', 'Épreuve introuvable sur la page après création des séquences. Rechargez la page puis réessayez.', '', 'compte.php', '', 0, 1, '', '', '', NOW()), +('bib_v4_js_global_gen_epr_missing', 'en', 'Race not found on the page after creating sequences. Reload the page and try again.', '', 'compte.php', '', 0, 1, '', '', '', NOW()); diff --git a/superadm/enregistrer.php b/superadm/enregistrer.php index 1e19f76..544fec3 100644 --- a/superadm/enregistrer.php +++ b/superadm/enregistrer.php @@ -13,24 +13,95 @@ elseif (isset($_POST['action'])) else $action = 'Aucune action définie'; -// MSIN-4401 — Préférences rapport chrono (colonnes / ordre / tri) : mêmes droits -// que rapport_new.php (session promoteur com_info). Les autres actions restent -// réservées au canal superadm (usa_id). +// MSIN-4401 — Actions autorisées en session compte promoteur (com_info), sans usa_id : +// - prefs rapport chrono (chksave / trie / groupe) +// - bascule « dossard récupéré » (remis) depuis le site promoteur / gestion V2 +// Les autres actions restent réservées au canal superadm (usa_id). if (session_status() !== PHP_SESSION_ACTIVE) { session_start(); } -$tabRapportCompteActions = array('chksave', 'triechange', 'triecheckall', 'groupechange'); -$blnRapportCompte = in_array($action, $tabRapportCompteActions, true) - && !empty($_SESSION['com_info']['com_id']) + +$intComCompte = intval($_SESSION['com_info']['com_id'] ?? ($_SESSION['com_id'] ?? 0)); +$tabCompteActions = array('chksave', 'triechange', 'triecheckall', 'groupechange', 'remis'); +$blnComptePromoteur = in_array($action, $tabCompteActions, true) + && $intComCompte > 0 && empty($_SESSION['usa_id']); -if ($blnRapportCompte) { - // Ne jamais laisser le promoteur écrire les prefs d'un autre com_id - $_REQUEST['key'] = intval($_SESSION['com_info']['com_id']); - if (isset($_POST['key'])) { - $_POST['key'] = $_REQUEST['key']; - } +if ($blnComptePromoteur) { header('Content-Type: application/json; charset=utf-8'); + + if ($action === 'remis') { + // Forcer l'identité + cibles (évite spoofing POST). + $strParNom = trim( + (string)($_SESSION['com_info']['com_prenom'] ?? '') + . ' ' + . (string)($_SESSION['com_info']['com_nom'] ?? '') + ); + if ($strParNom === '') { + $strParNom = 'compte#' . $intComCompte; + } + $_REQUEST['par_id'] = $intComCompte; + $_REQUEST['par'] = $strParNom; + $_REQUEST['table'] = urlencode(base64_encode('resultats_participants')); + $_REQUEST['field'] = 'no_bib_remis'; + $_REQUEST['key'] = 'par_id'; + if (isset($_POST['par_id'])) { + $_POST['par_id'] = $_REQUEST['par_id']; + } + if (isset($_POST['par'])) { + $_POST['par'] = $_REQUEST['par']; + } + if (isset($_POST['table'])) { + $_POST['table'] = $_REQUEST['table']; + } + if (isset($_POST['field'])) { + $_POST['field'] = $_REQUEST['field']; + } + if (isset($_POST['key'])) { + $_POST['key'] = $_REQUEST['key']; + } + + // Droit sur l'événement du participant (Legacy com_eve_promoteur OU V2 bib_remis). + $intParCible = intval($_REQUEST['id'] ?? 0); + $blnOkRemis = false; + if ($intParCible > 0) { + $intEveCible = intval($db->fxGetVar( + 'SELECT eve_id FROM resultats_participants WHERE par_id = ' . $intParCible . ' LIMIT 1' + )); + if ($intEveCible > 0) { + $strEvePromoteur = (string)$db->fxGetVar( + 'SELECT com_eve_promoteur FROM inscriptions_comptes WHERE com_id = ' . $intComCompte . ' LIMIT 1' + ); + $arrEvePromo = array_filter(array_map('intval', explode(',', $strEvePromoteur))); + if (in_array($intEveCible, $arrEvePromo, true)) { + $blnOkRemis = true; + } else { + if (!function_exists('fxEveAccesHasPermission')) { + require_once dirname(__DIR__) . '/php/inc_fx_eve_acces.php'; + } + $blnOkRemis = fxEveAccesHasPermission( + $intComCompte, + $intEveCible, + 'inscriptions_gestion.bib_remis' + ); + } + } + } + if (!$blnOkRemis) { + echo json_encode(array( + 'state' => 'error', + 'message' => 'Accès refusé pour ce dossard récupéré.', + 'code' => 'forbidden', + )); + exit; + } + } else { + // Prefs rapport : ne jamais laisser le promoteur écrire un autre com_id + $_REQUEST['key'] = $intComCompte; + if (isset($_POST['key'])) { + $_POST['key'] = $_REQUEST['key']; + } + } } else { fxSuperadmAjaxAuthOrJsonExit(); }