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 '
+
+
+ '
+ . ' Aperçu'
+ . '
+
+ '
+ . ' Droits'
+ . '
+
+
+ ';
+}
+
/** É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 :
+ = htmlspecialchars($arrStatus['legacy_csv'], ENT_QUOTES, 'UTF-8') ?>
+
+
+
+
+ Kit migration_legacy absent — exécuter
+ sql/MSIN-eve-acces-v2-phase4-role-grants-all.sql.
+
+
+
+
+
+ Événement
+ v2 migration
+
+
+
+
+
+
+ = htmlspecialchars($arrEvent['eve_nom_fr'], ENT_QUOTES, 'UTF-8') ?>
+ (#= intval($arrEvent['eve_id']) ?>)
+
+
+
+ OK
+
+ À migrer
+
+
+
+
+
+
+
+ 0) { ?>
+
+
+ Migrer = intval($arrStatus['pending_count']) ?> é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
+
+
+ Migration legacy
+
+
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
+
+
+
+
+
Voir le site
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 = '')
= htmlspecialchars($row['role_label_fr'], ENT_QUOTES, 'UTF-8') ?>
= htmlspecialchars($row['role_code'], ENT_QUOTES, 'UTF-8') ?>
+
+ Tous les droits
+
- = intval($row['perm_count']) ?>
+ ∞';
+ } else {
+ echo intval($row['perm_count']);
+ }
+ ?>
= intval($row['assign_count']) ?>
= !empty($row['role_delegable']) ? '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.
+
+
+
-
+
>
';
+ return;
+ }
+
+ $intRoleId = fxEveAccesGetMigrationLegacyRoleId();
+ $arrPending = fxEveAccesMigrationListComptesPending();
+
+ if ($strFlash !== '') {
+ echo '
' . htmlspecialchars($strFlash, ENT_QUOTES, 'UTF-8') . '
';
+ }
+ ?>
+
Migration promoteur legacy → v2
+
+ Pour chaque compte, lit inscriptions_comptes.com_eve_promoteur et assigne le kit
+ migration_legacy (accès total) par événement. Le champ legacy n'est pas modifié.
+
+
+
+
+ Kit migration_legacy introuvable —
+ exécuter sql/MSIN-eve-acces-v2-phase4-role-grants-all.sql.
+
+
+
+ Aucun compte en attente : tous les événements com_eve_promoteur ont déjà le kit migration.
+
+
+
+
+ Migrer tous les comptes en attente (= count($arrPending) ?>)
+
+
+
+
+
+
+ Compte
+ Courriel
+ com_eve_promoteur
+ À migrer
+
+
+
+
+
+
+ = htmlspecialchars($arrRow['com_prenom'] . ' ' . $arrRow['com_nom'], ENT_QUOTES, 'UTF-8') ?>
+ = htmlspecialchars($arrRow['com_courriel'], ENT_QUOTES, 'UTF-8') ?>
+ = htmlspecialchars($arrRow['legacy_csv'], ENT_QUOTES, 'UTF-8') ?>
+ = intval($arrRow['pending_count']) ?> / = intval($arrRow['event_count']) ?>
+
+
+ Fiche compte
+
+
+
+
+
+
+
+
+