From 7bd586b619a4330b91a3845178b10500cb8ada7a Mon Sep 17 00:00:00 2001 From: stephan Date: Wed, 1 Jul 2026 12:00:22 -0400 Subject: [PATCH] Implement permission inspection features and enhance admin interface This commit introduces new functions for permission inspection, allowing super admins to toggle and manage access rights more effectively. It adds visual elements for permission badges in the admin interface and updates the sidebar navigation to include a migration section for legacy accounts. Additionally, CSS styles are enhanced for better user experience and clarity. The version code is updated to reflect these changes. --- css/style.css | 23 + inc_header.php | 1 + inc_tableau_gestion_epreuves.php | 3 + php/inc_fonctions_sl.php | 69 ++- php/inc_fx_eve_acces.php | 503 +++++++++++++++++- ...IN-eve-acces-v2-phase4-role-grants-all.sql | 38 ++ superadm/css/style_blue.css | 47 ++ superadm/eve_acces.php | 6 + superadm/inc_droite.php | 6 + superadm/inc_header.php | 8 + superadm/index.php | 42 ++ superadm/php/inc_fx_eve_acces_admin.php | 188 ++++++- 12 files changed, 919 insertions(+), 15 deletions(-) create mode 100644 sql/MSIN-eve-acces-v2-phase4-role-grants-all.sql diff --git a/css/style.css b/css/style.css index 24c2158..08593f3 100644 --- a/css/style.css +++ b/css/style.css @@ -1046,6 +1046,29 @@ ul.ms1-menu-compte li a:hover, ul.ms1-menu-compte li a:active { box-shadow:0 0 0 2px rgba(114,28,36,.35); } +.ms1-perm-inspect-badge{ + display:inline-block; + font-size:11px; + line-height:1.3; + padding:2px 6px; + margin:2px 4px 2px 0; + border-radius:3px; + background:#fff3cd; + border:1px solid #e0a800; + color:#856404; + vertical-align:middle; +} +.ms1-perm-inspect-badge code{ + font-size:10px; + color:inherit; + background:transparent; + padding:0; +} +.ms1-perm-inspect-zone{ + outline:2px dashed rgba(224,168,0,.55); + outline-offset:4px; +} + .epr-wrapper{ display:flex; flex-direction:column; diff --git a/inc_header.php b/inc_header.php index 03493a4..0d238f5 100644 --- a/inc_header.php +++ b/inc_header.php @@ -3,6 +3,7 @@ global $vPaypal_devise,$vblnEnvironementDev,$vDomaine, $vClient, $strCode, $strLangue, $vRepertoireFichiers,$vPaypaladv_SANDBOX,$favicon; fxAdminTextEditModeHandleRequest(); +fxAdminPermInspectModeHandleRequest(); $strQueryString = ""; diff --git a/inc_tableau_gestion_epreuves.php b/inc_tableau_gestion_epreuves.php index 935f2d7..171ad95 100644 --- a/inc_tableau_gestion_epreuves.php +++ b/inc_tableau_gestion_epreuves.php @@ -64,6 +64,9 @@ if (isset($_POST['btn_cancel_event_promo'])) { diff --git a/php/inc_fonctions_sl.php b/php/inc_fonctions_sl.php index 6becb81..6a51829 100644 --- a/php/inc_fonctions_sl.php +++ b/php/inc_fonctions_sl.php @@ -177,6 +177,62 @@ function fxAdminTextEditModeActive() { return fxAdminCanUseTextEditTools() && !empty($_SESSION['ms1_text_edit_mode']); } +/** Mode inspecteur droits v2 (cadenas) — super admin connecte uniquement. */ +function fxAdminCanUsePermInspectTools() { + return !empty($_SESSION['usa_id']); +} + +function fxAdminPermInspectModeActive() { + return fxAdminCanUsePermInspectTools() && !empty($_SESSION['ms1_perm_inspect_mode']); +} + +function fxAdminPermInspectModeHandleRequest() { + if (!fxAdminCanUsePermInspectTools() || !isset($_GET['ms1_perm_inspect'])) { + return; + } + + $_SESSION['ms1_perm_inspect_mode'] = ($_GET['ms1_perm_inspect'] === '1') ? 1 : 0; + + $strPath = strtok($_SERVER['REQUEST_URI'], '?'); + $tabParams = $_GET; + unset($tabParams['ms1_perm_inspect']); + $strQuery = http_build_query($tabParams); + + header('Location: ' . $strPath . ($strQuery !== '' ? '?' . $strQuery : '')); + exit; +} + +function fxAdminPermInspectSwitchHtml() { + $blnOn = fxAdminPermInspectModeActive(); + + return ' + + + + '; +} + /** Échappement HTML — outils admin traduction. */ function fxAdminEsc($str) { return htmlspecialchars((string)$str, ENT_QUOTES, 'UTF-8'); @@ -424,16 +480,27 @@ function fxAdminTextEditSwitchHtml() { function fxRenderEnvNoticeBar() { global $vEnvNotice; + $strExtraSwitches = ''; + if (function_exists('fxAdminCanUsePermInspectTools') && fxAdminCanUsePermInspectTools()) { + $strExtraSwitches .= fxAdminPermInspectSwitchHtml(); + } + if (trim($vEnvNotice) === '') { + if ($strExtraSwitches !== '') { + echo '
' . $strExtraSwitches . '
'; + } return; } if (!fxAdminCanUseTextEditTools()) { echo $vEnvNotice; + if ($strExtraSwitches !== '') { + echo '
' . $strExtraSwitches . '
'; + } return; } - $strSwitch = fxAdminTextEditSwitchHtml(); + $strSwitch = fxAdminTextEditSwitchHtml() . $strExtraSwitches; $strHtml = preg_replace('/<\/strong>/', ' ' . $strSwitch, trim($vEnvNotice), 1); if ($strHtml === null || $strHtml === trim($vEnvNotice)) { diff --git a/php/inc_fx_eve_acces.php b/php/inc_fx_eve_acces.php index 0fcedd2..1487861 100644 --- a/php/inc_fx_eve_acces.php +++ b/php/inc_fx_eve_acces.php @@ -164,6 +164,10 @@ function fxEveAccesGetEventIds($intComId) /** Acces web gestion inscriptions : vue API/page OU au moins une permission action inscriptions_gestion.* */ function fxEveAccesHasInscrGestionWebAccess($intComId, $intEveId) { + if (fxEveAccesComEventHasGrantsAllKit(intval($intComId), intval($intEveId))) { + return true; + } + if (fxEveAccesHasAnyPermission(intval($intComId), intval($intEveId), array('registrations.view', 'inscriptions_gestion.view'))) { return true; } @@ -191,6 +195,24 @@ function fxEveAccesGetEventIdsWithInscrGestionAccess($intComId) return array(); } + $arrIds = array(); + + if (fxEveAccesHasGrantsAllColumn()) { + $sqlAll = "SELECT DISTINCT ea.eve_id FROM inscriptions_eve_acces ea + INNER JOIN inscriptions_eve_roles r ON r.role_id = ea.role_id AND r.role_actif = 1 + WHERE ea.com_id = " . intval($intComId) . " + AND ea.ea_statut = 'actif' + AND (ea.ea_expires_at IS NULL OR ea.ea_expires_at > NOW()) + AND r.role_grants_all = 1 + ORDER BY ea.eve_id ASC"; + $tabAll = $objDatabase->fxGetResults($sqlAll); + if ($tabAll != null) { + foreach ($tabAll as $row) { + $arrIds[intval($row['eve_id'])] = intval($row['eve_id']); + } + } + } + $sql = "SELECT DISTINCT eve_id FROM " . fxEveAccesPermSql() . " WHERE com_id = " . intval($intComId) . " AND ( @@ -199,17 +221,77 @@ function fxEveAccesGetEventIdsWithInscrGestionAccess($intComId) ) ORDER BY eve_id ASC"; $tab = $objDatabase->fxGetResults($sql); - $arrIds = array(); if ($tab != null) { foreach ($tab as $row) { - $arrIds[] = intval($row['eve_id']); + $arrIds[intval($row['eve_id'])] = intval($row['eve_id']); } } + $arrIds = array_values($arrIds); + sort($arrIds, SORT_NUMERIC); + return $arrIds; } +function fxEveAccesHasGrantsAllColumn() +{ + global $objDatabase; + + static $blnHas = null; + + if ($blnHas !== null) { + return $blnHas; + } + + if (!fxEveAccesIsEnabled()) { + $blnHas = false; + return $blnHas; + } + + $tab = $objDatabase->fxGetResults("SHOW COLUMNS FROM inscriptions_eve_roles LIKE 'role_grants_all'"); + $blnHas = ($tab != null && count($tab) > 0); + + return $blnHas; +} + +function fxEveAccesCatalogPermIsActive($strPermKey) +{ + global $objDatabase; + + if (!fxEveAccesIsEnabled() || trim((string)$strPermKey) === '') { + return false; + } + + $sql = "SELECT COUNT(*) FROM inscriptions_eve_permissions + WHERE perm_key = '" . $objDatabase->fxEscape($strPermKey) . "' + AND perm_actif = 1"; + $intNb = $objDatabase->fxGetVar($sql); + + return ($intNb != null && intval($intNb) > 0); +} + +/** Compte avec au moins un kit role_grants_all actif sur cet evenement. */ +function fxEveAccesComEventHasGrantsAllKit($intComId, $intEveId) +{ + global $objDatabase; + + if (!fxEveAccesIsEnabled() || !fxEveAccesHasGrantsAllColumn()) { + return false; + } + + $sql = "SELECT COUNT(*) FROM inscriptions_eve_acces ea + INNER JOIN inscriptions_eve_roles r ON r.role_id = ea.role_id AND r.role_actif = 1 + WHERE ea.com_id = " . intval($intComId) . " + AND ea.eve_id = " . intval($intEveId) . " + AND ea.ea_statut = 'actif' + AND (ea.ea_expires_at IS NULL OR ea.ea_expires_at > NOW()) + AND r.role_grants_all = 1"; + $intNb = $objDatabase->fxGetVar($sql); + + return ($intNb != null && intval($intNb) > 0); +} + function fxEveAccesHasPermission($intComId, $intEveId, $strPermKey) { global $objDatabase; @@ -218,6 +300,10 @@ function fxEveAccesHasPermission($intComId, $intEveId, $strPermKey) return false; } + if (fxEveAccesComEventHasGrantsAllKit($intComId, $intEveId)) { + return fxEveAccesCatalogPermIsActive($strPermKey); + } + $sql = "SELECT COUNT(*) FROM " . fxEveAccesPermSql() . " WHERE com_id = " . intval($intComId) . " AND eve_id = " . intval($intEveId) . " @@ -235,6 +321,16 @@ function fxEveAccesHasAnyPermission($intComId, $intEveId, $arrPermKeys) return false; } + if (fxEveAccesComEventHasGrantsAllKit($intComId, $intEveId)) { + foreach ($arrPermKeys as $strKey) { + if (fxEveAccesCatalogPermIsActive($strKey)) { + return true; + } + } + + return false; + } + $arrEsc = array(); foreach ($arrPermKeys as $strKey) { $arrEsc[] = "'" . $objDatabase->fxEscape($strKey) . "'"; @@ -973,6 +1069,331 @@ function fxEveAccesShowEventAccessPanel($intEveId) 0) { + $arrIds[$intId] = $intId; + } + } + + return array_values($arrIds); +} + +function fxEveAccesGetMigrationLegacyRoleId() +{ + global $objDatabase; + + if (!fxEveAccesIsEnabled()) { + return 0; + } + + $intRoleId = intval($objDatabase->fxGetVar( + "SELECT role_id FROM inscriptions_eve_roles + WHERE role_code = 'migration_legacy' AND role_actif = 1 + LIMIT 1" + )); + + return ($intRoleId > 0) ? $intRoleId : 0; +} + +/** Le compte a-t-il deja le kit migration_legacy actif sur cet evenement ? */ +function fxEveAccesComEventHasMigrationKit($intComId, $intEveId) +{ + global $objDatabase; + + if (!fxEveAccesIsEnabled()) { + return false; + } + + $sql = "SELECT COUNT(*) FROM inscriptions_eve_acces ea + INNER JOIN inscriptions_eve_roles r ON r.role_id = ea.role_id + WHERE ea.com_id = " . intval($intComId) . " + AND ea.eve_id = " . intval($intEveId) . " + AND ea.ea_statut = 'actif' + AND (ea.ea_expires_at IS NULL OR ea.ea_expires_at > NOW()) + AND r.role_code = 'migration_legacy'"; + $intNb = $objDatabase->fxGetVar($sql); + + return ($intNb != null && intval($intNb) > 0); +} + +/** + * Etat migration legacy → v2 pour un compte (lecture inscriptions_comptes.com_eve_promoteur). + * + * @return array{com_id:int,legacy_csv:string,role_id:int,events:array,pending_count:int,migrated_count:int} + */ +function fxEveAccesMigrationStatusForCom($intComId) +{ + global $objDatabase; + + $intComId = intval($intComId); + $arrOut = array( + 'com_id' => $intComId, + 'legacy_csv' => '', + 'role_id' => fxEveAccesGetMigrationLegacyRoleId(), + 'events' => array(), + 'pending_count' => 0, + 'migrated_count' => 0, + ); + + if (!fxEveAccesIsEnabled() || $intComId <= 0) { + return $arrOut; + } + + $row = $objDatabase->fxGetRow( + "SELECT com_id, com_eve_promoteur FROM inscriptions_comptes WHERE com_id = $intComId LIMIT 1" + ); + if ($row === null) { + return $arrOut; + } + + $arrOut['legacy_csv'] = trim((string)($row['com_eve_promoteur'] ?? '')); + $arrEveIds = fxEveAccesParseLegacyPromoteurCsv($arrOut['legacy_csv']); + + if (empty($arrEveIds)) { + return $arrOut; + } + + $sql = "SELECT eve_id, eve_nom_fr FROM inscriptions_evenements + WHERE eve_id IN (" . implode(',', array_map('intval', $arrEveIds)) . ")"; + $tabEve = $objDatabase->fxGetResults($sql); + $arrEveNames = array(); + if ($tabEve != null) { + foreach ($tabEve as $rowEve) { + $arrEveNames[intval($rowEve['eve_id'])] = $rowEve['eve_nom_fr']; + } + } + + foreach ($arrEveIds as $intEveId) { + $blnMigrated = fxEveAccesComEventHasMigrationKit($intComId, $intEveId); + $arrOut['events'][] = array( + 'eve_id' => $intEveId, + 'eve_nom_fr' => $arrEveNames[$intEveId] ?? ('Événement #' . $intEveId), + 'migrated' => $blnMigrated, + ); + if ($blnMigrated) { + $arrOut['migrated_count']++; + } else { + $arrOut['pending_count']++; + } + } + + return $arrOut; +} + +/** + * Cree les acces v2 (kit migration_legacy) pour chaque evenement du promoteur legacy. + * + * @return array{state:string,message:string,granted:int,skipped:int,errors:array} + */ +function fxEveAccesMigrateCompteFromLegacy($intComId, $intGrantedBy = 0) +{ + $arrStatus = fxEveAccesMigrationStatusForCom($intComId); + $intRoleId = intval($arrStatus['role_id']); + + if ($intRoleId <= 0) { + return array( + 'state' => 'error', + 'message' => 'Kit migration_legacy introuvable. Executer sql/MSIN-eve-acces-v2-phase4-role-grants-all.sql', + 'granted' => 0, + 'skipped' => 0, + 'errors' => array(), + ); + } + + if ($arrStatus['legacy_csv'] === '') { + return array( + 'state' => 'error', + 'message' => 'Aucun evenement dans com_eve_promoteur (inscriptions_comptes).', + 'granted' => 0, + 'skipped' => 0, + 'errors' => array(), + ); + } + + $intGranted = 0; + $intSkipped = 0; + $arrErrors = array(); + + foreach ($arrStatus['events'] as $arrEvent) { + $intEveId = intval($arrEvent['eve_id']); + if (!empty($arrEvent['migrated'])) { + $intSkipped++; + continue; + } + + $arrResult = fxEveAccesGrant( + $intComId, + $intEveId, + $intRoleId, + 0, + $intGrantedBy, + 'Migration depuis com_eve_promoteur' + ); + + if (($arrResult['state'] ?? '') === 'success') { + $intGranted++; + } else { + $arrErrors[] = '#' . $intEveId . ': ' . ($arrResult['message'] ?? 'erreur'); + } + } + + if (!empty($arrErrors)) { + return array( + 'state' => 'error', + 'message' => $intGranted . ' migre(s), ' . count($arrErrors) . ' erreur(s).', + 'granted' => $intGranted, + 'skipped' => $intSkipped, + 'errors' => $arrErrors, + ); + } + + if ($intGranted === 0 && $intSkipped > 0) { + return array( + 'state' => 'success', + 'message' => 'Deja migre : tous les evenements legacy ont le kit migration.', + 'granted' => 0, + 'skipped' => $intSkipped, + 'errors' => array(), + ); + } + + return array( + 'state' => 'success', + 'message' => $intGranted . ' evenement(s) migre(s)' + . ($intSkipped > 0 ? ', ' . $intSkipped . ' deja en place' : '') . '.', + 'granted' => $intGranted, + 'skipped' => $intSkipped, + 'errors' => array(), + ); +} + +/** Liste comptes avec com_eve_promoteur non vide (migration globale). */ +function fxEveAccesMigrationListComptesPending() +{ + global $objDatabase; + + if (!fxEveAccesIsEnabled()) { + return array(); + } + + $sql = "SELECT com_id, com_nom, com_prenom, com_courriel, com_eve_promoteur + FROM inscriptions_comptes + WHERE com_eve_promoteur IS NOT NULL + AND TRIM(com_eve_promoteur) <> '' + ORDER BY com_nom ASC, com_prenom ASC"; + $tab = $objDatabase->fxGetResults($sql); + $arrRows = array(); + + if ($tab == null) { + return $arrRows; + } + + foreach ($tab as $row) { + $arrStatus = fxEveAccesMigrationStatusForCom(intval($row['com_id'])); + if ($arrStatus['pending_count'] <= 0) { + continue; + } + $arrRows[] = array( + 'com_id' => intval($row['com_id']), + 'com_nom' => $row['com_nom'], + 'com_prenom' => $row['com_prenom'], + 'com_courriel' => $row['com_courriel'], + 'legacy_csv' => $arrStatus['legacy_csv'], + 'pending_count' => $arrStatus['pending_count'], + 'migrated_count' => $arrStatus['migrated_count'], + 'event_count' => count($arrStatus['events']), + ); + } + + return $arrRows; +} + +function fxEveAccesShowCompteMigrationPanel($intComId) +{ + $arrStatus = fxEveAccesMigrationStatusForCom($intComId); + $strT = urlencode($_GET['t'] ?? ''); + $intComId = intval($intComId); + + if (!empty($_GET['mig_msg'])) { + $strClass = (!empty($_GET['mig_err'])) ? 'alert-danger' : 'alert-success'; + echo '
' + . htmlspecialchars((string)$_GET['mig_msg'], ENT_QUOTES, 'UTF-8') . '
'; + } + ?> +
+

Migration promoteur legacy → accès v2

+

+ Source : champ inscriptions_comptes.com_eve_promoteur — + kit migration_legacy (tous les droits). + Migration globale +

+ + +

Ce compte n'a aucun événement promoteur legacy.

+ +

+ com_eve_promoteur : + +

+ + +
+ Kit migration_legacy absent — exécuter + sql/MSIN-eve-acces-v2-phase4-role-grants-all.sql. +
+ + + + + + + + + + + + + + + + +
Événementv2 migration
+ + (#) + + + OK + + À migrer + +
+ + 0) { ?> + + + Migrer événement(s) vers v2 + + + Tous les événements legacy sont migrés en v2. + + + +
+ Accès aux événements

Gérer les kits + · + Migration legacy

+ + @@ -1334,3 +1759,77 @@ function fxEveAccesShowCompteForm($intComId) ' + . ' ' + . '' . htmlspecialchars($strPermKey, ENT_QUOTES, 'UTF-8') . ''; +} + +/** Attributs HTML zone inspectee (data-ms1-perm). */ +function fxEveAccesPermInspectZoneAttr($strPermKey) +{ + if (!function_exists('fxAdminPermInspectModeActive') || !fxAdminPermInspectModeActive()) { + return ''; + } + + $strPermKey = trim((string)$strPermKey); + if ($strPermKey === '') { + return ''; + } + + return ' class="ms1-perm-inspect-zone" data-ms1-perm="' + . htmlspecialchars($strPermKey, ENT_QUOTES, 'UTF-8') . '"'; +} + +/** + * Badge cadenas droits v2 (visible si super admin + mode inspecteur actif). + */ +function fxEveAccesPermInspectBadge($strPermKey, $strContext = 'v2') +{ + if (!function_exists('fxAdminPermInspectModeActive') || !fxAdminPermInspectModeActive()) { + return ''; + } + + $strPermKey = trim((string)$strPermKey); + if ($strPermKey === '') { + return ''; + } + + $strTitle = ($strContext !== '' ? $strContext . ' — ' : '') . $strPermKey; + + return '' + . ' ' + . '' . htmlspecialchars($strPermKey, ENT_QUOTES, 'UTF-8') . ''; +} + +/** Attributs HTML zone inspectee (data-ms1-perm). */ +function fxEveAccesPermInspectZoneAttr($strPermKey) +{ + if (!function_exists('fxAdminPermInspectModeActive') || !fxAdminPermInspectModeActive()) { + return ''; + } + + $strPermKey = trim((string)$strPermKey); + if ($strPermKey === '') { + return ''; + } + + return ' class="ms1-perm-inspect-zone" data-ms1-perm="' + . htmlspecialchars($strPermKey, ENT_QUOTES, 'UTF-8') . '"'; +} diff --git a/sql/MSIN-eve-acces-v2-phase4-role-grants-all.sql b/sql/MSIN-eve-acces-v2-phase4-role-grants-all.sql new file mode 100644 index 0000000..cffc67f --- /dev/null +++ b/sql/MSIN-eve-acces-v2-phase4-role-grants-all.sql @@ -0,0 +1,38 @@ +/* + MSIN - Acces evenement v2 (phase 4) - Kit « tous les droits » + Executer APRES MSIN-eve-acces-v2-phase3-role-delegable.sql + + role_grants_all = 1 : le kit accorde toute permission active du catalogue, + presentes et futures, sans maintenir la matrice role_permissions. +*/ + +SET NAMES utf8mb4; + +ALTER TABLE `inscriptions_eve_roles` + ADD COLUMN `role_grants_all` tinyint(1) unsigned NOT NULL DEFAULT 0 + COMMENT '1 = tous les droits actifs du catalogue (presents et futurs)' + AFTER `role_delegable`; + +UPDATE `inscriptions_eve_roles` +SET `role_grants_all` = 1 +WHERE `role_code` = 'owner'; + +INSERT INTO `inscriptions_eve_roles` + (`role_code`, `role_label_fr`, `role_label_en`, `role_description_fr`, `role_description_en`, + `role_icone`, `role_systeme`, `role_actif`, `role_tri`, `role_delegable`, `role_grants_all`) +VALUES + ('migration_legacy', 'Migration promoteur', 'Legacy promoter migration', + 'Acces total equivalent promoteur legacy — migration uniquement', + 'Full legacy promoter equivalent access — migration only', + 'fa-exchange', 1, 1, 5, 0, 1) +ON DUPLICATE KEY UPDATE + `role_label_fr` = VALUES(`role_label_fr`), + `role_label_en` = VALUES(`role_label_en`), + `role_description_fr` = VALUES(`role_description_fr`), + `role_description_en` = VALUES(`role_description_en`), + `role_icone` = VALUES(`role_icone`), + `role_systeme` = VALUES(`role_systeme`), + `role_actif` = VALUES(`role_actif`), + `role_tri` = VALUES(`role_tri`), + `role_delegable` = VALUES(`role_delegable`), + `role_grants_all` = VALUES(`role_grants_all`); diff --git a/superadm/css/style_blue.css b/superadm/css/style_blue.css index b9f79a0..ee677bc 100644 --- a/superadm/css/style_blue.css +++ b/superadm/css/style_blue.css @@ -156,4 +156,51 @@ table.rapport tr {background-color: #190d7394;}*/ } .superadm-sidebar-subtitle + .nav { margin-bottom: 0.25rem; +} + +/* Toggle Aperçu / Droits (super admin) */ +.navbar .ms1-env-text-edit-label{ + display:inline-flex; + align-items:center; + gap:6px; + color:#fff; + font-size:12px; + cursor:pointer; + margin:0; +} +.navbar .ms1-env-text-edit-opt{ + opacity:.65; +} +.navbar .ms1-env-text-edit-opt.is-active{ + opacity:1; + font-weight:600; +} +.navbar .ms1-env-text-edit-switch{ + appearance:none; + width:36px; + height:18px; + border-radius:9px; + background:#6c757d; + border:1px solid #495057; + position:relative; + cursor:pointer; + vertical-align:middle; +} +.navbar .ms1-env-text-edit-switch::after{ + content:''; + position:absolute; + top:2px; + left:2px; + width:12px; + height:12px; + border-radius:50%; + background:#fff; + transition:transform .15s ease; +} +.navbar .ms1-env-text-edit-switch:checked{ + background:#e67e22; + border-color:#a04000; +} +.navbar .ms1-env-text-edit-switch:checked::after{ + transform:translateX(18px); } \ No newline at end of file diff --git a/superadm/eve_acces.php b/superadm/eve_acces.php index dbfdf3f..613b810 100644 --- a/superadm/eve_acces.php +++ b/superadm/eve_acces.php @@ -74,6 +74,12 @@ include('inc_header.php');
' . htmlspecialchars($strError, ENT_QUOTES, 'UTF-8') . '
'; + } + fxEveAccesAdminRenderMigrationPage($strFlash); + break; case 'kit': if ($strFlash !== '' && $strError === '') { echo '
' . htmlspecialchars($strFlash, ENT_QUOTES, 'UTF-8') . '
'; diff --git a/superadm/inc_droite.php b/superadm/inc_droite.php index 25ae37b..a720c67 100644 --- a/superadm/inc_droite.php +++ b/superadm/inc_droite.php @@ -73,6 +73,12 @@ global $db, $objDatabase, $vblnEnvironementDev, $vDomaine, $vblnEnvironementPreP  Kits d'accès +
Gestion de la documentation et Aide
diff --git a/superadm/inc_header.php b/superadm/inc_header.php index 8025c2f..e66033a 100644 --- a/superadm/inc_header.php +++ b/superadm/inc_header.php @@ -3,6 +3,9 @@ if (function_exists('fxAdminTextEditModeHandleRequest')) { fxAdminTextEditModeHandleRequest(); } +if (function_exists('fxAdminPermInspectModeHandleRequest')) { + fxAdminPermInspectModeHandleRequest(); +} ?> @@ -119,6 +122,11 @@ if ($strPage != 'popup.php') {  Sync BD + + + diff --git a/superadm/index.php b/superadm/index.php index 2b50133..2ffa4cd 100644 --- a/superadm/index.php +++ b/superadm/index.php @@ -161,6 +161,48 @@ if (isset($_GET['action']) && $_GET['action'] == 'reactivateveaccesextra') { header('Location: index.php?t=' . urlencode($_GET['t']) . '&a=mod&id=' . intval($_GET['id']) . '#eve-acces-v2'); exit; } + +if (isset($_GET['action']) && $_GET['action'] == 'migrateveacceslegacy') { + if (session_status() === PHP_SESSION_NONE) { + session_start(); + } + require_once(dirname(__FILE__) . '/../php/inc_fx_eve_acces.php'); + $intGrantedBy = isset($_SESSION['usa_id']) ? intval($_SESSION['usa_id']) : 0; + $arrResult = fxEveAccesMigrateCompteFromLegacy(intval($_GET['id']), $intGrantedBy); + $strQ = 'index.php?t=' . urlencode($_GET['t']) . '&a=mod&id=' . intval($_GET['id']) + . '#eve-acces-migration' + . '&mig_msg=' . urlencode($arrResult['message']); + if (($arrResult['state'] ?? '') !== 'success') { + $strQ .= '&mig_err=1'; + } + header('Location: ' . $strQ); + exit; +} + +if (isset($_GET['action']) && $_GET['action'] == 'migrateveacceslegacyall') { + if (session_status() === PHP_SESSION_NONE) { + session_start(); + } + require_once(dirname(__FILE__) . '/../php/inc_fx_eve_acces.php'); + $intGrantedBy = isset($_SESSION['usa_id']) ? intval($_SESSION['usa_id']) : 0; + $intTotalGranted = 0; + $intTotalSkipped = 0; + $intComptes = 0; + foreach (fxEveAccesMigrationListComptesPending() as $arrRow) { + $arrResult = fxEveAccesMigrateCompteFromLegacy(intval($arrRow['com_id']), $intGrantedBy); + if (($arrResult['state'] ?? '') === 'success' || ($arrResult['granted'] ?? 0) > 0) { + $intTotalGranted += intval($arrResult['granted'] ?? 0); + $intTotalSkipped += intval($arrResult['skipped'] ?? 0); + $intComptes++; + } + } + header('Location: eve_acces.php?p=migrate&ok=' . urlencode( + $intTotalGranted . ' acces cree(s) sur ' . $intComptes . ' compte(s)' + . ($intTotalSkipped > 0 ? ', ' . $intTotalSkipped . ' deja en place' : '') + )); + exit; +} + if ($strAction != 'report') { require_once('php/inc_start_time.php'); $blnLogged = true; diff --git a/superadm/php/inc_fx_eve_acces_admin.php b/superadm/php/inc_fx_eve_acces_admin.php index 28af990..8a51231 100644 --- a/superadm/php/inc_fx_eve_acces_admin.php +++ b/superadm/php/inc_fx_eve_acces_admin.php @@ -26,6 +26,26 @@ function fxEveAccesAdminHasDelegableColumn() return $blnHas; } +function fxEveAccesAdminHasGrantsAllColumn() +{ + global $objDatabase; + + static $blnHas = null; + if ($blnHas !== null) { + return $blnHas; + } + + if (!fxEveAccesIsEnabled()) { + $blnHas = false; + return $blnHas; + } + + $tab = $objDatabase->fxGetResults("SHOW COLUMNS FROM inscriptions_eve_roles LIKE 'role_grants_all'"); + $blnHas = ($tab != null && count($tab) > 0); + + return $blnHas; +} + function fxEveAccesAdminPermGroupLabels() { return array( @@ -75,10 +95,11 @@ function fxEveAccesAdminGetRolesForList($blnActifOnly = false) } $strDelegable = fxEveAccesAdminHasDelegableColumn() ? ', r.role_delegable' : ', 0 AS role_delegable'; + $strGrantsAll = fxEveAccesAdminHasGrantsAllColumn() ? ', r.role_grants_all' : ', 0 AS role_grants_all'; $sql = "SELECT r.role_id, r.role_code, r.role_label_fr, r.role_label_en, r.role_description_fr, r.role_icone, r.role_systeme, r.role_actif, r.role_tri - {$strDelegable}, + {$strDelegable}{$strGrantsAll}, (SELECT COUNT(*) FROM inscriptions_eve_role_permissions erp WHERE erp.role_id = r.role_id) AS perm_count, (SELECT COUNT(*) FROM inscriptions_eve_acces ea WHERE ea.role_id = r.role_id AND ea.ea_statut = 'actif') AS assign_count @@ -102,10 +123,11 @@ function fxEveAccesAdminGetRoleById($intRoleId) } $strDelegable = fxEveAccesAdminHasDelegableColumn() ? ', role_delegable' : ', 0 AS role_delegable'; + $strGrantsAll = fxEveAccesAdminHasGrantsAllColumn() ? ', role_grants_all' : ', 0 AS role_grants_all'; $sql = "SELECT role_id, role_code, role_label_fr, role_label_en, role_description_fr, role_description_en, role_icone, - role_systeme, role_actif, role_tri {$strDelegable} + role_systeme, role_actif, role_tri {$strDelegable}{$strGrantsAll} FROM inscriptions_eve_roles WHERE role_id = " . intval($intRoleId) . " LIMIT 1"; @@ -189,12 +211,19 @@ function fxEveAccesAdminSaveRole($arrData, $arrPermKeys) $intTri = intval($arrData['role_tri'] ?? 0); $blnActif = !empty($arrData['role_actif']) ? 1 : 0; $blnDelegable = !empty($arrData['role_delegable']) ? 1 : 0; - if ($blnSysteme && in_array($strCode, array('owner', 'qr_debug'), true)) { + $blnGrantsAll = !empty($arrData['role_grants_all']) ? 1 : 0; + if ($blnSysteme && $rowExisting !== null && ($rowExisting['role_code'] ?? '') === 'migration_legacy') { + $blnGrantsAll = 1; + } + if ($blnGrantsAll) { + $blnDelegable = 0; + } + if ($blnSysteme && in_array($strCode, array('owner', 'qr_debug', 'migration_legacy'), true)) { $blnDelegable = 0; } $arrValidKeys = array(); - if (!empty($arrPermKeys)) { + if (!$blnGrantsAll && !empty($arrPermKeys)) { $arrCatalog = fxEveAccesGetCatalogPermissions(null, true); $arrCatalogKeys = array(); if ($arrCatalog != null) { @@ -228,6 +257,9 @@ function fxEveAccesAdminSaveRole($arrData, $arrPermKeys) if (fxEveAccesAdminHasDelegableColumn()) { $sqlInsert .= ', role_delegable = ' . intval($blnDelegable); } + if (fxEveAccesAdminHasGrantsAllColumn()) { + $sqlInsert .= ', role_grants_all = ' . intval($blnGrantsAll); + } $objDatabase->fxQuery($sqlInsert); $intRoleId = intval($objDatabase->fxGetVar('SELECT LAST_INSERT_ID()')); } else { @@ -243,16 +275,21 @@ function fxEveAccesAdminSaveRole($arrData, $arrPermKeys) if (fxEveAccesAdminHasDelegableColumn()) { $sqlUpdate .= ', role_delegable = ' . intval($blnDelegable); } + if (fxEveAccesAdminHasGrantsAllColumn()) { + $sqlUpdate .= ', role_grants_all = ' . intval($blnGrantsAll); + } $sqlUpdate .= ' WHERE role_id = ' . intval($intRoleId); $objDatabase->fxQuery($sqlUpdate); } $objDatabase->fxQuery('DELETE FROM inscriptions_eve_role_permissions WHERE role_id = ' . intval($intRoleId)); - foreach (array_keys($arrValidKeys) as $strKey) { - $objDatabase->fxQuery( - "INSERT INTO inscriptions_eve_role_permissions (role_id, perm_key) - VALUES (" . intval($intRoleId) . ", '" . $objDatabase->fxEscape($strKey) . "')" - ); + if (!$blnGrantsAll) { + foreach (array_keys($arrValidKeys) as $strKey) { + $objDatabase->fxQuery( + "INSERT INTO inscriptions_eve_role_permissions (role_id, perm_key) + VALUES (" . intval($intRoleId) . ", '" . $objDatabase->fxEscape($strKey) . "')" + ); + } } return array( @@ -290,9 +327,13 @@ function fxEveAccesAdminDuplicateRole($intRoleId) 'role_tri' => intval($row['role_tri']) + 1, 'role_actif' => 1, 'role_delegable' => !empty($row['role_delegable']) ? 1 : 0, + 'role_grants_all' => !empty($row['role_grants_all']) ? 1 : 0, ); - return fxEveAccesAdminSaveRole($arrSave, fxEveAccesAdminGetRolePermKeys($intRoleId)); + return fxEveAccesAdminSaveRole( + $arrSave, + !empty($row['role_grants_all']) ? array() : fxEveAccesAdminGetRolePermKeys($intRoleId) + ); } function fxEveAccesAdminToggleRoleActif($intRoleId) @@ -327,6 +368,10 @@ function fxEveAccesAdminRenderKitsList($strFlash = '') echo '
Executer sql/MSIN-eve-acces-v2-phase3-role-delegable.sql pour activer le flag « delegable par promoteur ».
'; } + if (!fxEveAccesAdminHasGrantsAllColumn()) { + echo '
Executer sql/MSIN-eve-acces-v2-phase4-role-grants-all.sql pour activer les kits « tous les droits ».
'; + } + $blnActifOnly = isset($_GET['actif']) && $_GET['actif'] === '1'; $arrRoles = fxEveAccesAdminGetRolesForList($blnActifOnly); @@ -380,8 +425,17 @@ function fxEveAccesAdminRenderKitsList($strFlash = '') - +
+ + Tous les droits +
∞'; + } else { + echo intval($row['perm_count']); + } + ?> oui' : '' ?> @@ -533,11 +587,30 @@ function fxEveAccesAdminRenderKitForm($intRoleId, $strError = '') Le promoteur pourra assigner ce kit à un membre invité, dans les limites définies par l'admin. + +
+
+ + > + + + + +
+ + Aucune matrice à maintenir : toute permission active du catalogue est accordée automatiquement. + Incompatible avec « délégable promoteur ». + +
+ -
+