1222 lines
54 KiB
PHP
1222 lines
54 KiB
PHP
<?php
|
||
|
||
/**
|
||
* Super admin — gestion des kits d'acces v2 (roles + matrice permissions).
|
||
*/
|
||
|
||
require_once dirname(__DIR__, 2) . '/php/inc_fx_eve_acces.php';
|
||
|
||
function fxEveAccesAdminHasDelegableColumn()
|
||
{
|
||
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_delegable'");
|
||
$blnHas = ($tab != null && count($tab) > 0);
|
||
|
||
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;
|
||
}
|
||
|
||
/** MSIN-4401 — Colonne kit : forcer sections fiche inscriptions ouvertes. */
|
||
function fxEveAccesAdminHasFicheSectionsOpenColumn()
|
||
{
|
||
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_fiche_sections_open'");
|
||
$blnHas = ($tab != null && count($tab) > 0);
|
||
|
||
return $blnHas;
|
||
}
|
||
|
||
function fxEveAccesAdminPermGroupLabels()
|
||
{
|
||
// MSIN-4401 — niveau 1 = pages hub ; niveau 2 = détails (pas de jargon API mobile)
|
||
return array(
|
||
'page_hub' => '1. Pages du hub (accès menu)',
|
||
'inscriptions_v2' => '2. Inscriptions V2 — détails',
|
||
'dossards_detail' => '2. Dossards / quantités — détails',
|
||
'rabais_detail' => '2. Rabais — détails',
|
||
'acces_detail' => '2. Accès V2 — détails',
|
||
'rapports_autres' => 'Rapports (autres)',
|
||
'autre' => 'Autres',
|
||
// Anciens groupes (si données pas encore migrées)
|
||
'api' => 'Ancien (inactif)',
|
||
'inscriptions' => 'Inscriptions',
|
||
'dossards' => 'Dossards',
|
||
'epreuves' => 'Épreuves',
|
||
'rabais' => 'Rabais',
|
||
'emails' => 'Courriels',
|
||
'reports' => 'Rapports',
|
||
'team' => 'Équipe',
|
||
'tools' => 'Outils',
|
||
'action' => 'Actions',
|
||
'general' => 'Général',
|
||
);
|
||
}
|
||
|
||
/** Ordre d'affichage des groupes dans le formulaire kit. */
|
||
function fxEveAccesAdminPermGroupOrder()
|
||
{
|
||
return array(
|
||
'page_hub',
|
||
'inscriptions_v2',
|
||
'dossards_detail',
|
||
'rabais_detail',
|
||
'acces_detail',
|
||
'rapports_autres',
|
||
'autre',
|
||
);
|
||
}
|
||
|
||
function fxEveAccesAdminNormalizeRoleCode($strCode)
|
||
{
|
||
$strCode = strtolower(trim((string)$strCode));
|
||
$strCode = preg_replace('/[^a-z0-9_]+/', '_', $strCode);
|
||
$strCode = preg_replace('/_+/', '_', $strCode);
|
||
$strCode = trim($strCode, '_');
|
||
|
||
return substr($strCode, 0, 32);
|
||
}
|
||
|
||
function fxEveAccesAdminRoleCodeExists($strCode, $intExcludeRoleId = 0)
|
||
{
|
||
global $objDatabase;
|
||
|
||
$sql = "SELECT COUNT(*) FROM inscriptions_eve_roles
|
||
WHERE role_code = '" . $objDatabase->fxEscape($strCode) . "'";
|
||
if (intval($intExcludeRoleId) > 0) {
|
||
$sql .= ' AND role_id <> ' . intval($intExcludeRoleId);
|
||
}
|
||
|
||
return intval($objDatabase->fxGetVar($sql)) > 0;
|
||
}
|
||
|
||
function fxEveAccesAdminGetRolesForList($blnActifOnly = false)
|
||
{
|
||
global $objDatabase;
|
||
|
||
if (!fxEveAccesIsEnabled()) {
|
||
return array();
|
||
}
|
||
|
||
$strDelegable = fxEveAccesAdminHasDelegableColumn() ? ', r.role_delegable' : ', 0 AS role_delegable';
|
||
$strGrantsAll = fxEveAccesAdminHasGrantsAllColumn() ? ', r.role_grants_all' : ', 0 AS role_grants_all';
|
||
$strFicheOpen = fxEveAccesAdminHasFicheSectionsOpenColumn()
|
||
? ', r.role_fiche_sections_open'
|
||
: ', 0 AS role_fiche_sections_open';
|
||
|
||
$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}{$strGrantsAll}{$strFicheOpen},
|
||
(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,
|
||
(SELECT COUNT(*) FROM inscriptions_eve_acces ea
|
||
WHERE ea.role_id = r.role_id AND ea.ea_statut <> 'actif') AS history_assign_count
|
||
FROM inscriptions_eve_roles r";
|
||
|
||
if ($blnActifOnly) {
|
||
$sql .= ' WHERE r.role_actif = 1';
|
||
}
|
||
|
||
$sql .= ' ORDER BY r.role_tri ASC, r.role_label_fr ASC';
|
||
|
||
return $objDatabase->fxGetResults($sql);
|
||
}
|
||
|
||
function fxEveAccesAdminGetRoleById($intRoleId)
|
||
{
|
||
global $objDatabase;
|
||
|
||
if (!fxEveAccesIsEnabled() || intval($intRoleId) <= 0) {
|
||
return null;
|
||
}
|
||
|
||
$strDelegable = fxEveAccesAdminHasDelegableColumn() ? ', role_delegable' : ', 0 AS role_delegable';
|
||
$strGrantsAll = fxEveAccesAdminHasGrantsAllColumn() ? ', role_grants_all' : ', 0 AS role_grants_all';
|
||
$strFicheOpen = fxEveAccesAdminHasFicheSectionsOpenColumn()
|
||
? ', role_fiche_sections_open'
|
||
: ', 0 AS role_fiche_sections_open';
|
||
|
||
$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}{$strGrantsAll}{$strFicheOpen}
|
||
FROM inscriptions_eve_roles
|
||
WHERE role_id = " . intval($intRoleId) . "
|
||
LIMIT 1";
|
||
|
||
return $objDatabase->fxGetRow($sql);
|
||
}
|
||
|
||
function fxEveAccesAdminGetRolePermKeys($intRoleId)
|
||
{
|
||
global $objDatabase;
|
||
|
||
if (!fxEveAccesIsEnabled() || intval($intRoleId) <= 0) {
|
||
return array();
|
||
}
|
||
|
||
$sql = "SELECT perm_key FROM inscriptions_eve_role_permissions
|
||
WHERE role_id = " . intval($intRoleId) . "
|
||
ORDER BY perm_key ASC";
|
||
$tab = $objDatabase->fxGetResults($sql);
|
||
$arrKeys = array();
|
||
|
||
if ($tab != null) {
|
||
foreach ($tab as $row) {
|
||
$arrKeys[] = $row['perm_key'];
|
||
}
|
||
}
|
||
|
||
return $arrKeys;
|
||
}
|
||
|
||
function fxEveAccesAdminCountActiveAssignments($intRoleId)
|
||
{
|
||
global $objDatabase;
|
||
|
||
$sql = "SELECT COUNT(*) FROM inscriptions_eve_acces
|
||
WHERE role_id = " . intval($intRoleId) . "
|
||
AND ea_statut = 'actif'";
|
||
|
||
return intval($objDatabase->fxGetVar($sql));
|
||
}
|
||
|
||
function fxEveAccesAdminCountAllAssignments($intRoleId)
|
||
{
|
||
global $objDatabase;
|
||
|
||
$sql = "SELECT COUNT(*) FROM inscriptions_eve_acces
|
||
WHERE role_id = " . intval($intRoleId);
|
||
|
||
return intval($objDatabase->fxGetVar($sql));
|
||
}
|
||
|
||
function fxEveAccesAdminCanDeleteRole($intRoleId)
|
||
{
|
||
$row = fxEveAccesAdminGetRoleById($intRoleId);
|
||
if ($row === null) {
|
||
return array('can' => false, 'message' => 'Kit introuvable.');
|
||
}
|
||
|
||
$intActive = fxEveAccesAdminCountActiveAssignments($intRoleId);
|
||
if ($intActive > 0) {
|
||
return array(
|
||
'can' => false,
|
||
'message' => 'Ce kit est assigné à ' . $intActive . ' compte(s). Retirez les assignations sur la fiche compte avant de supprimer.',
|
||
);
|
||
}
|
||
|
||
return array('can' => true, 'message' => '');
|
||
}
|
||
|
||
function fxEveAccesAdminDeleteRole($intRoleId)
|
||
{
|
||
global $objDatabase;
|
||
|
||
$arrCheck = fxEveAccesAdminCanDeleteRole($intRoleId);
|
||
if (!$arrCheck['can']) {
|
||
return array('state' => 'error', 'message' => $arrCheck['message']);
|
||
}
|
||
|
||
$intRoleId = intval($intRoleId);
|
||
$objDatabase->fxQuery('DELETE FROM inscriptions_eve_acces WHERE role_id = ' . $intRoleId);
|
||
$objDatabase->fxQuery('DELETE FROM inscriptions_eve_role_permissions WHERE role_id = ' . $intRoleId);
|
||
$objDatabase->fxQuery('DELETE FROM inscriptions_eve_roles WHERE role_id = ' . $intRoleId);
|
||
|
||
return array('state' => 'ok', 'message' => 'Kit supprimé.');
|
||
}
|
||
|
||
/**
|
||
* Assignations d'un kit (actives et historique).
|
||
*
|
||
* @return array<int, array<string, mixed>>
|
||
*/
|
||
function fxEveAccesAdminGetRoleAssignments($intRoleId, $strStatut = null)
|
||
{
|
||
global $objDatabase;
|
||
|
||
if (!fxEveAccesIsEnabled() || intval($intRoleId) <= 0) {
|
||
return array();
|
||
}
|
||
|
||
$sql = "SELECT ea.ea_id, ea.com_id, ea.eve_id, ea.ea_statut, ea.ea_created_at, ea.ea_revoked_at,
|
||
c.com_nom, c.com_prenom, c.com_courriel, c.com_lastvisit,
|
||
e.eve_nom_fr, e.eve_date_fin
|
||
FROM inscriptions_eve_acces ea
|
||
INNER JOIN inscriptions_comptes c ON c.com_id = ea.com_id
|
||
INNER JOIN inscriptions_evenements e ON e.eve_id = ea.eve_id
|
||
WHERE ea.role_id = " . intval($intRoleId);
|
||
|
||
if ($strStatut === 'actif') {
|
||
$sql .= " AND ea.ea_statut = 'actif'";
|
||
} elseif ($strStatut !== null && $strStatut !== '') {
|
||
$sql .= " AND ea.ea_statut = '" . $objDatabase->fxEscape($strStatut) . "'";
|
||
}
|
||
|
||
$sql .= " ORDER BY FIELD(ea.ea_statut, 'actif', 'invite', 'revoke'),
|
||
e.eve_date_fin DESC, c.com_nom ASC, c.com_prenom ASC";
|
||
|
||
$tab = $objDatabase->fxGetResults($sql);
|
||
|
||
return ($tab != null) ? $tab : array();
|
||
}
|
||
|
||
/**
|
||
* Tableau des comptes assignés à un kit (réutilisé fiche kit + page dédiée).
|
||
*/
|
||
function fxEveAccesAdminRenderRoleAssignmentsBlock($intRoleId, $arrOpts = array())
|
||
{
|
||
$blnShowFilters = !empty($arrOpts['filters']);
|
||
$strAnchorId = isset($arrOpts['anchor_id']) ? (string)$arrOpts['anchor_id'] : '';
|
||
$strFilter = $arrOpts['statut'] ?? 'actif';
|
||
if (!in_array($strFilter, array('actif', 'all', 'revoke', 'invite'), true)) {
|
||
$strFilter = 'actif';
|
||
}
|
||
|
||
$intActive = fxEveAccesAdminCountActiveAssignments($intRoleId);
|
||
$intTotal = fxEveAccesAdminCountAllAssignments($intRoleId);
|
||
$strStatutSql = ($strFilter === 'all') ? null : $strFilter;
|
||
$arrRows = fxEveAccesAdminGetRoleAssignments($intRoleId, $strStatutSql);
|
||
?>
|
||
<div class="card mb-3"<?= $strAnchorId !== '' ? ' id="' . htmlspecialchars($strAnchorId, ENT_QUOTES, 'UTF-8') . '"' : '' ?>>
|
||
<div class="card-header d-flex justify-content-between align-items-center flex-wrap">
|
||
<span><i class="fa fa-users"></i> Personnes assignées</span>
|
||
<span class="small text-muted">
|
||
<?= intval($intActive) ?> actif(s)
|
||
<?php if ($intTotal > $intActive) { ?>
|
||
— <?= intval($intTotal - $intActive) ?> dans l'historique
|
||
<?php } ?>
|
||
</span>
|
||
</div>
|
||
<div class="card-body py-3">
|
||
<p class="small text-muted mb-2">
|
||
Pour <strong>ajouter ou retirer</strong> un kit, utilisez la fiche compte (section Accès événement v2).
|
||
</p>
|
||
<?php if ($blnShowFilters) { ?>
|
||
<p class="mb-2">
|
||
<?php
|
||
$arrFilters = array(
|
||
'actif' => 'Actifs (' . intval($intActive) . ')',
|
||
'all' => 'Tous (' . intval($intTotal) . ')',
|
||
'revoke' => 'Révoqués',
|
||
'invite' => 'Invitations',
|
||
);
|
||
foreach ($arrFilters as $strKey => $strLabel) {
|
||
$blnOn = ($strFilter === $strKey);
|
||
echo '<a href="eve_acces.php?p=assignations&id=' . intval($intRoleId)
|
||
. '&statut=' . urlencode($strKey) . '" class="btn btn-sm btn-outline-secondary'
|
||
. ($blnOn ? ' active' : '') . ' mr-1">' . htmlspecialchars($strLabel, ENT_QUOTES, 'UTF-8') . '</a>';
|
||
}
|
||
?>
|
||
</p>
|
||
<?php } elseif ($intTotal > $intActive) { ?>
|
||
<p class="mb-2">
|
||
<a href="eve_acces.php?p=assignations&id=<?= intval($intRoleId) ?>&statut=all" class="btn btn-sm btn-outline-secondary">
|
||
Voir l'historique complet
|
||
</a>
|
||
</p>
|
||
<?php } ?>
|
||
|
||
<div class="table-responsive mb-0">
|
||
<table class="table table-sm table-striped table-hover mb-0">
|
||
<thead class="thead-light">
|
||
<tr>
|
||
<th>Compte</th>
|
||
<th>Événement</th>
|
||
<th class="text-center">Statut</th>
|
||
<th>Assigné le</th>
|
||
<th>Dernière connexion</th>
|
||
<th></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php
|
||
if (count($arrRows) === 0) {
|
||
echo '<tr><td colspan="6" class="text-muted">Aucune assignation.</td></tr>';
|
||
} else {
|
||
foreach ($arrRows as $arrAssign) {
|
||
$strCompte = trim($arrAssign['com_prenom'] . ' ' . $arrAssign['com_nom']);
|
||
$strStatut = (string)$arrAssign['ea_statut'];
|
||
$strBadge = 'secondary';
|
||
if ($strStatut === 'actif') {
|
||
$strBadge = 'success';
|
||
} elseif ($strStatut === 'invite') {
|
||
$strBadge = 'info';
|
||
} elseif ($strStatut === 'revoke') {
|
||
$strBadge = 'warning';
|
||
}
|
||
$strCompteUrl = fxEveAccesCompteAdminUrl(intval($arrAssign['com_id']), intval($arrAssign['eve_id']));
|
||
?>
|
||
<tr>
|
||
<td>
|
||
<div><?= htmlspecialchars($strCompte, ENT_QUOTES, 'UTF-8') ?></div>
|
||
<div class="small text-muted"><?= htmlspecialchars($arrAssign['com_courriel'], ENT_QUOTES, 'UTF-8') ?></div>
|
||
</td>
|
||
<td>
|
||
<div><?= htmlspecialchars($arrAssign['eve_nom_fr'], ENT_QUOTES, 'UTF-8') ?></div>
|
||
<div class="small text-muted">#<?= intval($arrAssign['eve_id']) ?></div>
|
||
</td>
|
||
<td class="text-center">
|
||
<span class="badge badge-<?= $strBadge ?>"><?= htmlspecialchars($strStatut, ENT_QUOTES, 'UTF-8') ?></span>
|
||
</td>
|
||
<td class="text-nowrap small"><?= htmlspecialchars(fxEveAccesAdminFormatReportDatetime($arrAssign['ea_created_at']), ENT_QUOTES, 'UTF-8') ?></td>
|
||
<td class="text-nowrap small"><?= htmlspecialchars(fxEveAccesAdminFormatReportDatetime($arrAssign['com_lastvisit']), ENT_QUOTES, 'UTF-8') ?></td>
|
||
<td class="text-right text-nowrap">
|
||
<a class="btn btn-sm btn-outline-primary" href="<?= htmlspecialchars($strCompteUrl, ENT_QUOTES, 'UTF-8') ?>">
|
||
Fiche compte
|
||
</a>
|
||
</td>
|
||
</tr>
|
||
<?php
|
||
}
|
||
}
|
||
?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
function fxEveAccesAdminRenderKitAssignmentsPage($intRoleId, $strFlash = '')
|
||
{
|
||
if (!fxEveAccesIsEnabled()) {
|
||
echo '<div class="alert alert-warning">Tables acces v2 non installees.</div>';
|
||
return;
|
||
}
|
||
|
||
$row = fxEveAccesAdminGetRoleById($intRoleId);
|
||
if ($row === null) {
|
||
echo '<div class="alert alert-danger">Kit introuvable.</div>';
|
||
return;
|
||
}
|
||
|
||
$strFilter = $_GET['statut'] ?? 'actif';
|
||
if (!in_array($strFilter, array('actif', 'all', 'revoke', 'invite'), true)) {
|
||
$strFilter = 'actif';
|
||
}
|
||
|
||
if ($strFlash !== '') {
|
||
echo '<div class="alert alert-success">' . htmlspecialchars($strFlash, ENT_QUOTES, 'UTF-8') . '</div>';
|
||
}
|
||
?>
|
||
<div class="mb-3">
|
||
<a href="eve_acces.php?p=kits" class="btn btn-sm btn-outline-secondary">
|
||
<i class="fa fa-chevron-left"></i> Retour aux kits
|
||
</a>
|
||
<a href="eve_acces.php?p=kit&id=<?= intval($intRoleId) ?>" class="btn btn-sm btn-outline-primary ml-1">
|
||
<i class="fa fa-pencil"></i> Modifier le kit
|
||
</a>
|
||
</div>
|
||
|
||
<h1 class="mb-2">Assignations — <?= htmlspecialchars($row['role_label_fr'], ENT_QUOTES, 'UTF-8') ?></h1>
|
||
<p class="text-muted mb-3">
|
||
Code <code><?= htmlspecialchars($row['role_code'], ENT_QUOTES, 'UTF-8') ?></code>.
|
||
<a href="eve_acces.php?p=kit&id=<?= intval($intRoleId) ?>#kit-assignations">Retour à la fiche kit</a>
|
||
</p>
|
||
|
||
<?php
|
||
fxEveAccesAdminRenderRoleAssignmentsBlock($intRoleId, array(
|
||
'filters' => true,
|
||
'statut' => $strFilter,
|
||
));
|
||
}
|
||
|
||
function fxEveAccesAdminSaveRole($arrData, $arrPermKeys)
|
||
{
|
||
global $objDatabase;
|
||
|
||
if (!fxEveAccesIsEnabled()) {
|
||
return array('state' => 'error', 'message' => 'Tables acces v2 non installees.');
|
||
}
|
||
|
||
$intRoleId = intval($arrData['role_id'] ?? 0);
|
||
$rowExisting = ($intRoleId > 0) ? fxEveAccesAdminGetRoleById($intRoleId) : null;
|
||
|
||
$strLabelFr = trim((string)($arrData['role_label_fr'] ?? ''));
|
||
$strLabelEn = trim((string)($arrData['role_label_en'] ?? ''));
|
||
if ($strLabelFr === '') {
|
||
return array('state' => 'error', 'message' => 'Le libelle FR est obligatoire.');
|
||
}
|
||
if ($strLabelEn === '') {
|
||
$strLabelEn = $strLabelFr;
|
||
}
|
||
|
||
$strCode = fxEveAccesAdminNormalizeRoleCode($arrData['role_code'] ?? '');
|
||
if ($strCode === '' || !preg_match('/^[a-z][a-z0-9_]{0,31}$/', $strCode)) {
|
||
return array('state' => 'error', 'message' => 'Code invalide (a-z, 0-9, _, min. 2 caracteres).');
|
||
}
|
||
|
||
$blnCodeLocked = ($rowExisting !== null && ($rowExisting['role_code'] ?? '') === 'migration_legacy');
|
||
if ($blnCodeLocked) {
|
||
$strCode = $rowExisting['role_code'];
|
||
} elseif (fxEveAccesAdminRoleCodeExists($strCode, $intRoleId)) {
|
||
return array('state' => 'error', 'message' => 'Ce code de kit existe deja.');
|
||
}
|
||
|
||
$strDescFr = trim((string)($arrData['role_description_fr'] ?? ''));
|
||
$strDescEn = trim((string)($arrData['role_description_en'] ?? ''));
|
||
$strIcone = trim((string)($arrData['role_icone'] ?? ''));
|
||
if ($strIcone !== '' && !preg_match('/^fa-[a-z0-9-]+$/', $strIcone)) {
|
||
$strIcone = '';
|
||
}
|
||
|
||
$intTri = intval($arrData['role_tri'] ?? 0);
|
||
$blnActif = !empty($arrData['role_actif']) ? 1 : 0;
|
||
$blnDelegable = !empty($arrData['role_delegable']) ? 1 : 0;
|
||
$blnGrantsAll = !empty($arrData['role_grants_all']) ? 1 : 0;
|
||
$blnFicheOpen = !empty($arrData['role_fiche_sections_open']) ? 1 : 0;
|
||
if ($blnCodeLocked) {
|
||
$blnGrantsAll = 1;
|
||
}
|
||
// MSIN-4478 — kit total + kits systeme : jamais redistribuables par un promoteur
|
||
// (évite qu'une invitation donne rapports / argent / tout).
|
||
if ($blnCodeLocked || $blnGrantsAll || in_array($strCode, array('owner', 'qr_debug'), true)) {
|
||
$blnDelegable = 0;
|
||
}
|
||
|
||
$arrValidKeys = array();
|
||
if (!$blnGrantsAll && !empty($arrPermKeys)) {
|
||
$arrCatalog = fxEveAccesGetCatalogPermissions(null, true);
|
||
$arrCatalogKeys = array();
|
||
if ($arrCatalog != null) {
|
||
foreach ($arrCatalog as $rowPerm) {
|
||
$arrCatalogKeys[$rowPerm['perm_key']] = true;
|
||
}
|
||
}
|
||
foreach ($arrPermKeys as $strKey) {
|
||
$strKey = trim((string)$strKey);
|
||
if ($strKey !== '' && isset($arrCatalogKeys[$strKey])) {
|
||
$arrValidKeys[$strKey] = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ($intRoleId > 0 && $rowExisting === null) {
|
||
return array('state' => 'error', 'message' => 'Kit introuvable.');
|
||
}
|
||
|
||
if ($intRoleId <= 0) {
|
||
$sqlInsert = "INSERT INTO inscriptions_eve_roles SET
|
||
role_code = '" . $objDatabase->fxEscape($strCode) . "',
|
||
role_label_fr = '" . $objDatabase->fxEscape($strLabelFr) . "',
|
||
role_label_en = '" . $objDatabase->fxEscape($strLabelEn) . "',
|
||
role_description_fr = " . ($strDescFr !== '' ? "'" . $objDatabase->fxEscape($strDescFr) . "'" : 'NULL') . ",
|
||
role_description_en = " . ($strDescEn !== '' ? "'" . $objDatabase->fxEscape($strDescEn) . "'" : 'NULL') . ",
|
||
role_icone = " . ($strIcone !== '' ? "'" . $objDatabase->fxEscape($strIcone) . "'" : 'NULL') . ",
|
||
role_systeme = 0,
|
||
role_actif = " . intval($blnActif) . ",
|
||
role_tri = " . intval($intTri);
|
||
if (fxEveAccesAdminHasDelegableColumn()) {
|
||
$sqlInsert .= ', role_delegable = ' . intval($blnDelegable);
|
||
}
|
||
if (fxEveAccesAdminHasGrantsAllColumn()) {
|
||
$sqlInsert .= ', role_grants_all = ' . intval($blnGrantsAll);
|
||
}
|
||
if (fxEveAccesAdminHasFicheSectionsOpenColumn()) {
|
||
$sqlInsert .= ', role_fiche_sections_open = ' . intval($blnFicheOpen);
|
||
}
|
||
$objDatabase->fxQuery($sqlInsert);
|
||
$intRoleId = intval($objDatabase->fxGetVar('SELECT LAST_INSERT_ID()'));
|
||
} else {
|
||
$sqlUpdate = "UPDATE inscriptions_eve_roles SET
|
||
role_code = '" . $objDatabase->fxEscape($strCode) . "',
|
||
role_label_fr = '" . $objDatabase->fxEscape($strLabelFr) . "',
|
||
role_label_en = '" . $objDatabase->fxEscape($strLabelEn) . "',
|
||
role_description_fr = " . ($strDescFr !== '' ? "'" . $objDatabase->fxEscape($strDescFr) . "'" : 'NULL') . ",
|
||
role_description_en = " . ($strDescEn !== '' ? "'" . $objDatabase->fxEscape($strDescEn) . "'" : 'NULL') . ",
|
||
role_icone = " . ($strIcone !== '' ? "'" . $objDatabase->fxEscape($strIcone) . "'" : 'NULL') . ",
|
||
role_actif = " . intval($blnActif) . ",
|
||
role_tri = " . intval($intTri);
|
||
if (fxEveAccesAdminHasDelegableColumn()) {
|
||
$sqlUpdate .= ', role_delegable = ' . intval($blnDelegable);
|
||
}
|
||
if (fxEveAccesAdminHasGrantsAllColumn()) {
|
||
$sqlUpdate .= ', role_grants_all = ' . intval($blnGrantsAll);
|
||
}
|
||
if (fxEveAccesAdminHasFicheSectionsOpenColumn()) {
|
||
$sqlUpdate .= ', role_fiche_sections_open = ' . intval($blnFicheOpen);
|
||
}
|
||
$sqlUpdate .= ' WHERE role_id = ' . intval($intRoleId);
|
||
$objDatabase->fxQuery($sqlUpdate);
|
||
}
|
||
|
||
$objDatabase->fxQuery('DELETE FROM inscriptions_eve_role_permissions WHERE role_id = ' . intval($intRoleId));
|
||
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(
|
||
'state' => 'ok',
|
||
'message' => 'Kit enregistre.',
|
||
'role_id' => $intRoleId,
|
||
);
|
||
}
|
||
|
||
function fxEveAccesAdminDuplicateRole($intRoleId)
|
||
{
|
||
global $objDatabase;
|
||
|
||
$row = fxEveAccesAdminGetRoleById($intRoleId);
|
||
if ($row === null) {
|
||
return array('state' => 'error', 'message' => 'Kit introuvable.');
|
||
}
|
||
|
||
$strBase = fxEveAccesAdminNormalizeRoleCode($row['role_code'] . '_copy');
|
||
$strCode = $strBase;
|
||
$intSuffix = 2;
|
||
while (fxEveAccesAdminRoleCodeExists($strCode)) {
|
||
$strCode = substr($strBase, 0, 28) . '_' . $intSuffix;
|
||
$intSuffix++;
|
||
}
|
||
|
||
$arrSave = array(
|
||
'role_id' => 0,
|
||
'role_code' => $strCode,
|
||
'role_label_fr' => $row['role_label_fr'] . ' (copie)',
|
||
'role_label_en' => ($row['role_label_en'] !== '' ? $row['role_label_en'] : $row['role_label_fr']) . ' (copy)',
|
||
'role_description_fr' => $row['role_description_fr'] ?? '',
|
||
'role_description_en' => $row['role_description_en'] ?? '',
|
||
'role_icone' => $row['role_icone'] ?? '',
|
||
'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,
|
||
'role_fiche_sections_open' => !empty($row['role_fiche_sections_open']) ? 1 : 0,
|
||
);
|
||
|
||
return fxEveAccesAdminSaveRole(
|
||
$arrSave,
|
||
!empty($row['role_grants_all']) ? array() : fxEveAccesAdminGetRolePermKeys($intRoleId)
|
||
);
|
||
}
|
||
|
||
function fxEveAccesAdminToggleRoleActif($intRoleId)
|
||
{
|
||
global $objDatabase;
|
||
|
||
$row = fxEveAccesAdminGetRoleById($intRoleId);
|
||
if ($row === null) {
|
||
return array('state' => 'error', 'message' => 'Kit introuvable.');
|
||
}
|
||
|
||
$blnNew = intval($row['role_actif']) === 1 ? 0 : 1;
|
||
$objDatabase->fxQuery(
|
||
'UPDATE inscriptions_eve_roles SET role_actif = ' . intval($blnNew)
|
||
. ' WHERE role_id = ' . intval($intRoleId)
|
||
);
|
||
|
||
return array(
|
||
'state' => 'ok',
|
||
'message' => $blnNew ? 'Kit reactive.' : 'Kit desactive.',
|
||
);
|
||
}
|
||
|
||
function fxEveAccesAdminRenderKitsList($strFlash = '')
|
||
{
|
||
if (!fxEveAccesIsEnabled()) {
|
||
echo '<div class="alert alert-warning">Tables acces v2 non installees. Executer les SQL MSIN-eve-acces-v2-phase1.</div>';
|
||
return;
|
||
}
|
||
|
||
if (!fxEveAccesAdminHasDelegableColumn()) {
|
||
echo '<div class="alert alert-info">Executer <code>sql/MSIN-eve-acces-v2-phase3-role-delegable.sql</code> pour activer le flag « delegable par promoteur ».</div>';
|
||
}
|
||
|
||
if (!fxEveAccesAdminHasGrantsAllColumn()) {
|
||
echo '<div class="alert alert-info">Executer <code>sql/MSIN-eve-acces-v2-phase4-role-grants-all.sql</code> pour activer les kits « tous les droits ».</div>';
|
||
}
|
||
|
||
$blnActifOnly = isset($_GET['actif']) && $_GET['actif'] === '1';
|
||
$arrRoles = fxEveAccesAdminGetRolesForList($blnActifOnly);
|
||
|
||
$blnCanEditKits = fxAdminCanEditEveAccesKits();
|
||
if ($strFlash !== '') {
|
||
echo '<div class="alert alert-success">' . htmlspecialchars($strFlash, ENT_QUOTES, 'UTF-8') . '</div>';
|
||
}
|
||
?>
|
||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||
<h1 class="mb-0">Kits d'accès</h1>
|
||
<?php if ($blnCanEditKits) { ?>
|
||
<a class="btn btn-success" href="eve_acces.php?p=kit">
|
||
<i class="fa fa-plus"></i> Nouveau kit
|
||
</a>
|
||
<?php } ?>
|
||
</div>
|
||
<?php if (!$blnCanEditKits) { ?>
|
||
<div class="alert alert-info py-2">
|
||
Lecture seule : vous pouvez consulter les kits. Création / modification réservées.
|
||
L’assignation aux comptes reste disponible sur la fiche compte.
|
||
</div>
|
||
<?php } ?>
|
||
|
||
<div class="card mb-3 border-info">
|
||
<div class="card-header py-2 bg-light">
|
||
<strong><i class="fa fa-info-circle text-info"></i> Comment ça marche ?</strong>
|
||
</div>
|
||
<div class="card-body py-3 small">
|
||
<p class="mb-2">
|
||
Un <strong>kit</strong> accorde des droits à un compte sur un événement. Deux modes :
|
||
</p>
|
||
<ul class="mb-2 pl-3">
|
||
<li><strong>Droits à la pièce</strong> — cochez les permissions dans la matrice.</li>
|
||
<li><strong>Tous les droits</strong> — switch « Kit total » (toutes les permissions actives, présentes et futures).</li>
|
||
<li><strong>Assigner</strong> → fiche compte, section <em>Accès événement v2</em>.</li>
|
||
<li><strong>Supprimer un kit</strong> → possible dès qu'<em>aucun compte</em> ne l'a actuellement (colonne Assign. = 0).</li>
|
||
<li><strong>Qui a ce kit ?</strong> → ouvrez le kit : section « Personnes assignées » en bas de fiche.</li>
|
||
</ul>
|
||
<p class="mb-0 text-muted">
|
||
Un kit « délégable » peut être proposé par un promoteur à son équipe (invitation).
|
||
Le super admin décide kit par kit — y compris pour un kit total.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<p>
|
||
<a href="eve_acces.php?p=kits" class="btn btn-sm btn-outline-secondary<?= !$blnActifOnly ? ' active' : '' ?>">Tous</a>
|
||
<a href="eve_acces.php?p=kits&actif=1" class="btn btn-sm btn-outline-secondary<?= $blnActifOnly ? ' active' : '' ?>">Actifs seulement</a>
|
||
</p>
|
||
<div class="table-responsive">
|
||
<table class="table table-striped table-sm table-hover mb-0 align-middle">
|
||
<thead class="thead-dark">
|
||
<tr>
|
||
<th class="text-center" style="width:2.5rem" aria-label="Icône"></th>
|
||
<th>Kit</th>
|
||
<th class="text-center text-nowrap" style="width:1%">Perms</th>
|
||
<th class="text-center text-nowrap" style="width:1%">Assign.</th>
|
||
<th class="text-center text-nowrap" style="width:1%">Délég.</th>
|
||
<th class="text-center text-nowrap" style="width:1%">Statut</th>
|
||
<th class="text-right text-nowrap" style="width:1%"></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php
|
||
if ($arrRoles === null || count($arrRoles) === 0) {
|
||
echo '<tr><td colspan="7" class="text-muted">Aucun kit.</td></tr>';
|
||
} else {
|
||
foreach ($arrRoles as $row) {
|
||
$strIcon = trim((string)($row['role_icone'] ?? ''));
|
||
$arrDelete = fxEveAccesAdminCanDeleteRole(intval($row['role_id']));
|
||
?>
|
||
<tr>
|
||
<td class="text-center text-muted">
|
||
<?php if ($strIcon !== '') { ?>
|
||
<i class="fa fa-lg <?= htmlspecialchars($strIcon, ENT_QUOTES, 'UTF-8') ?>" aria-hidden="true"></i>
|
||
<?php } else { ?>
|
||
<span class="small">–</span>
|
||
<?php } ?>
|
||
</td>
|
||
<td>
|
||
<div class="font-weight-bold"><?= htmlspecialchars($row['role_label_fr'], ENT_QUOTES, 'UTF-8') ?></div>
|
||
<div class="small text-muted font-monospace eve-acces-kit-code"><?= htmlspecialchars($row['role_code'], ENT_QUOTES, 'UTF-8') ?></div>
|
||
<?php if (!empty($row['role_grants_all'])) { ?>
|
||
<span class="badge badge-warning mt-1">Tous les droits</span>
|
||
<?php } ?>
|
||
<?php if (!empty($row['role_fiche_sections_open'])) { ?>
|
||
<span class="badge badge-info mt-1">Sections ouvertes</span>
|
||
<?php } ?>
|
||
</td>
|
||
<td class="text-center"><?php
|
||
if (!empty($row['role_grants_all'])) {
|
||
echo '<span class="text-muted" title="Toutes les permissions actives">∞</span>';
|
||
} else {
|
||
echo intval($row['perm_count']);
|
||
}
|
||
?></td>
|
||
<td class="text-center"><?php
|
||
$intAssign = intval($row['assign_count']);
|
||
if ($intAssign > 0) {
|
||
echo '<a href="eve_acces.php?p=kit&id=' . intval($row['role_id'])
|
||
. '#kit-assignations" class="badge badge-primary" title="Voir les comptes assignés">' . $intAssign . '</a>';
|
||
} else {
|
||
echo '<span class="text-muted">0</span>';
|
||
}
|
||
?></td>
|
||
<td class="text-center"><?= !empty($row['role_delegable']) ? '<span class="badge badge-info">oui</span>' : '<span class="text-muted">—</span>' ?></td>
|
||
<td class="text-center text-nowrap">
|
||
<?php if (intval($row['role_actif']) === 1) { ?>
|
||
<span class="badge badge-success">actif</span>
|
||
<?php } else { ?>
|
||
<span class="badge badge-warning">inactif</span>
|
||
<?php } ?>
|
||
</td>
|
||
<td class="text-right text-nowrap">
|
||
<a class="btn btn-sm btn-primary" href="eve_acces.php?p=kit&id=<?= intval($row['role_id']) ?>"
|
||
title="<?= $blnCanEditKits ? 'Modifier' : 'Voir' ?>">
|
||
<i class="fa <?= $blnCanEditKits ? 'fa-pencil' : 'fa-eye' ?>"></i>
|
||
</a>
|
||
<?php if ($blnCanEditKits) { ?>
|
||
<a class="btn btn-sm btn-secondary" href="eve_acces.php?action=duplicate&id=<?= intval($row['role_id']) ?>"
|
||
title="Dupliquer">
|
||
<i class="fa fa-copy"></i>
|
||
</a>
|
||
<a class="btn btn-sm btn-outline-secondary" href="eve_acces.php?action=toggle&id=<?= intval($row['role_id']) ?>"
|
||
title="<?= intval($row['role_actif']) === 1 ? 'Desactiver' : 'Activer' ?>"
|
||
onclick="return confirm('Changer le statut de ce kit ?');">
|
||
<i class="fa fa-power-off"></i>
|
||
</a>
|
||
<?php if ($arrDelete['can']) { ?>
|
||
<a class="btn btn-sm btn-outline-danger" href="eve_acces.php?action=delete&id=<?= intval($row['role_id']) ?>"
|
||
title="Supprimer"
|
||
onclick="return confirm('Supprimer définitivement ce kit ?');">
|
||
<i class="fa fa-trash"></i>
|
||
</a>
|
||
<?php } elseif ($arrDelete['message'] !== '') { ?>
|
||
<span class="btn btn-sm btn-outline-secondary disabled" style="opacity:.45;cursor:help"
|
||
title="<?= htmlspecialchars($arrDelete['message'], ENT_QUOTES, 'UTF-8') ?>">
|
||
<i class="fa fa-trash"></i>
|
||
</span>
|
||
<?php } ?>
|
||
<?php } ?>
|
||
</td>
|
||
</tr>
|
||
<?php
|
||
}
|
||
}
|
||
?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
function fxEveAccesAdminRenderKitForm($intRoleId, $strError = '')
|
||
{
|
||
if (!fxEveAccesIsEnabled()) {
|
||
echo '<div class="alert alert-warning">Tables acces v2 non installees.</div>';
|
||
return;
|
||
}
|
||
|
||
$row = null;
|
||
$arrSelected = array();
|
||
if ($intRoleId > 0) {
|
||
$row = fxEveAccesAdminGetRoleById($intRoleId);
|
||
if ($row === null) {
|
||
echo '<div class="alert alert-danger">Kit introuvable.</div>';
|
||
return;
|
||
}
|
||
foreach (fxEveAccesAdminGetRolePermKeys($intRoleId) as $strKey) {
|
||
$arrSelected[$strKey] = true;
|
||
}
|
||
}
|
||
|
||
$blnCodeLocked = ($row !== null && ($row['role_code'] ?? '') === 'migration_legacy');
|
||
$blnCanEditKits = fxAdminCanEditEveAccesKits();
|
||
$strDisabled = $blnCanEditKits ? '' : ' disabled';
|
||
$arrDelete = ($intRoleId > 0) ? fxEveAccesAdminCanDeleteRole($intRoleId) : array('can' => false, 'message' => '');
|
||
$arrCatalog = fxEveAccesGetCatalogPermissions(null, true);
|
||
$arrByGroup = array();
|
||
if ($arrCatalog != null) {
|
||
foreach ($arrCatalog as $rowPerm) {
|
||
$strGroup = $rowPerm['perm_group'] ?? 'general';
|
||
if (!isset($arrByGroup[$strGroup])) {
|
||
$arrByGroup[$strGroup] = array();
|
||
}
|
||
$arrByGroup[$strGroup][] = $rowPerm;
|
||
}
|
||
}
|
||
$arrGroupLabels = fxEveAccesAdminPermGroupLabels();
|
||
$arrGroupOrder = fxEveAccesAdminPermGroupOrder();
|
||
$arrOrderedGroups = array();
|
||
foreach ($arrGroupOrder as $strG) {
|
||
if (isset($arrByGroup[$strG])) {
|
||
$arrOrderedGroups[$strG] = $arrByGroup[$strG];
|
||
unset($arrByGroup[$strG]);
|
||
}
|
||
}
|
||
ksort($arrByGroup);
|
||
foreach ($arrByGroup as $strG => $arrP) {
|
||
$arrOrderedGroups[$strG] = $arrP;
|
||
}
|
||
|
||
if ($strError !== '') {
|
||
echo '<div class="alert alert-danger">' . htmlspecialchars($strError, ENT_QUOTES, 'UTF-8') . '</div>';
|
||
}
|
||
?>
|
||
<div class="mb-3">
|
||
<a href="eve_acces.php?p=kits" class="btn btn-sm btn-outline-secondary">
|
||
<i class="fa fa-chevron-left"></i> Retour à la liste
|
||
</a>
|
||
</div>
|
||
<h1><?php
|
||
if (!$blnCanEditKits) {
|
||
echo 'Voir le kit';
|
||
} else {
|
||
echo $intRoleId > 0 ? 'Modifier le kit' : 'Nouveau kit';
|
||
}
|
||
?></h1>
|
||
<?php if (!$blnCanEditKits) { ?>
|
||
<div class="alert alert-info py-2">Lecture seule — vous ne pouvez pas modifier ce kit.</div>
|
||
<?php } ?>
|
||
|
||
<form method="post" action="eve_acces.php?p=kit<?= $intRoleId > 0 ? '&id=' . intval($intRoleId) : '' ?>"<?= $blnCanEditKits ? '' : ' onsubmit="return false;"' ?>>
|
||
<input type="hidden" name="action" value="save_kit">
|
||
<input type="hidden" name="role_id" value="<?= intval($intRoleId) ?>">
|
||
<fieldset<?= $strDisabled ?>>
|
||
|
||
<div class="card mb-3">
|
||
<div class="card-header">Identité</div>
|
||
<div class="card-body">
|
||
<div class="form-row">
|
||
<div class="form-group col-md-4">
|
||
<label for="role_code">Code <span class="text-danger">*</span></label>
|
||
<input type="text" class="form-control" id="role_code" name="role_code" maxlength="32"
|
||
value="<?= htmlspecialchars($row['role_code'] ?? '', ENT_QUOTES, 'UTF-8') ?>"
|
||
<?= $blnCodeLocked ? 'readonly' : '' ?>
|
||
placeholder="ex. gestion_statut">
|
||
<?php if ($blnCodeLocked) { ?>
|
||
<small class="text-muted">Code verrouillé (kit migration legacy).</small>
|
||
<?php } ?>
|
||
</div>
|
||
<div class="form-group col-md-4">
|
||
<label for="role_label_fr">Libellé FR <span class="text-danger">*</span></label>
|
||
<input type="text" class="form-control" id="role_label_fr" name="role_label_fr" maxlength="80"
|
||
value="<?= htmlspecialchars($row['role_label_fr'] ?? '', ENT_QUOTES, 'UTF-8') ?>" required>
|
||
</div>
|
||
<div class="form-group col-md-4">
|
||
<label for="role_label_en">Libellé EN</label>
|
||
<input type="text" class="form-control" id="role_label_en" name="role_label_en" maxlength="80"
|
||
value="<?= htmlspecialchars($row['role_label_en'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
|
||
</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group col-md-8">
|
||
<label for="role_description_fr">Description FR</label>
|
||
<input type="text" class="form-control" id="role_description_fr" name="role_description_fr" maxlength="255"
|
||
value="<?= htmlspecialchars($row['role_description_fr'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
|
||
</div>
|
||
<div class="form-group col-md-2">
|
||
<label for="role_icone">Icône FA</label>
|
||
<input type="text" class="form-control" id="role_icone" name="role_icone" maxlength="32"
|
||
placeholder="fa-mobile"
|
||
value="<?= htmlspecialchars($row['role_icone'] ?? '', ENT_QUOTES, 'UTF-8') ?>">
|
||
</div>
|
||
<div class="form-group col-md-2">
|
||
<label for="role_tri">Ordre</label>
|
||
<input type="number" class="form-control" id="role_tri" name="role_tri" min="0" max="9999"
|
||
value="<?= intval($row['role_tri'] ?? 50) ?>">
|
||
</div>
|
||
</div>
|
||
<div class="form-row">
|
||
<div class="form-group col-md-4">
|
||
<div class="custom-control custom-checkbox mt-2">
|
||
<input type="checkbox" class="custom-control-input" id="role_actif" name="role_actif" value="1"
|
||
<?= ($row === null || intval($row['role_actif']) === 1) ? 'checked' : '' ?>>
|
||
<label class="custom-control-label" for="role_actif">Kit actif (proposable à l'assignation)</label>
|
||
</div>
|
||
</div>
|
||
<?php if (fxEveAccesAdminHasDelegableColumn()) { ?>
|
||
<div class="form-group col-md-8">
|
||
<div class="custom-control custom-checkbox mt-2">
|
||
<input type="checkbox" class="custom-control-input" id="role_delegable" name="role_delegable" value="1"
|
||
<?= !empty($row['role_delegable']) ? 'checked' : '' ?>
|
||
<?= in_array($row['role_code'] ?? '', array('owner', 'qr_debug', 'migration_legacy'), true) ? 'disabled' : '' ?>>
|
||
<label class="custom-control-label" for="role_delegable">
|
||
Délégable par le promoteur (invitation équipe)
|
||
</label>
|
||
</div>
|
||
<small class="text-muted">Le promoteur pourra assigner ce kit à un membre invité. Impossible si « Kit total » est coché (MSIN-4478).</small>
|
||
</div>
|
||
<?php } ?>
|
||
<?php if (fxEveAccesAdminHasGrantsAllColumn()) { ?>
|
||
<div class="form-group col-md-12">
|
||
<div class="custom-control custom-checkbox mt-2">
|
||
<input type="checkbox" class="custom-control-input" id="role_grants_all" name="role_grants_all" value="1"
|
||
<?= !empty($row['role_grants_all']) ? 'checked' : '' ?>
|
||
<?= $blnCodeLocked ? 'disabled' : '' ?>>
|
||
<?php if ($blnCodeLocked) { ?>
|
||
<input type="hidden" name="role_grants_all" value="1">
|
||
<?php } ?>
|
||
<label class="custom-control-label" for="role_grants_all">
|
||
<strong>Kit total</strong> — tous les droits (présents et futurs)
|
||
</label>
|
||
</div>
|
||
<small class="text-muted">
|
||
Si coché : aucune matrice à maintenir. Sinon : choisissez les droits un par un ci-dessous.
|
||
</small>
|
||
</div>
|
||
<?php } ?>
|
||
<?php if (fxEveAccesAdminHasFicheSectionsOpenColumn()) { ?>
|
||
<div class="form-group col-md-12">
|
||
<div class="custom-control custom-checkbox mt-2">
|
||
<input type="checkbox" class="custom-control-input" id="role_fiche_sections_open" name="role_fiche_sections_open" value="1"
|
||
<?= !empty($row['role_fiche_sections_open']) ? 'checked' : '' ?>>
|
||
<label class="custom-control-label" for="role_fiche_sections_open">
|
||
<strong>Sections fiche ouvertes</strong> — Inscriptions V2
|
||
</label>
|
||
</div>
|
||
<small class="text-muted">
|
||
Si coché : sur la fiche inscription, toutes les sections (détails, gestion, dossard/statut) s’ouvrent automatiquement.
|
||
Sinon : comportement par défaut (détails ouverts, le reste fermé).
|
||
</small>
|
||
</div>
|
||
<?php } ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="card mb-3" id="card-kit-permissions"<?= !empty($row['role_grants_all']) ? ' style="display:none;"' : '' ?>>
|
||
<div class="card-header d-flex justify-content-between align-items-center">
|
||
<span>Permissions incluses</span>
|
||
<span>
|
||
<button type="button" class="btn btn-sm btn-outline-primary" id="btn-perm-all">Tout cocher</button>
|
||
<button type="button" class="btn btn-sm btn-outline-secondary" id="btn-perm-none">Tout décocher</button>
|
||
</span>
|
||
</div>
|
||
<div class="card-body">
|
||
<p class="small text-muted mb-3">
|
||
<strong>Niveau 1</strong> = accès aux menus du hub.
|
||
<strong>Niveau 2</strong> = actions dans la page (ex. Inscriptions V2).
|
||
La page <code>/mobile</code> est la même gestion inscriptions en affichage mobile — pas une API.
|
||
</p>
|
||
<?php
|
||
foreach ($arrOrderedGroups as $strGroup => $arrPerms) {
|
||
$strGroupLabel = $arrGroupLabels[$strGroup] ?? ucfirst($strGroup);
|
||
$strGroupId = preg_replace('/[^a-z0-9_]/', '_', $strGroup);
|
||
?>
|
||
<div class="border rounded p-3 mb-3 perm-group-block" data-group="<?= htmlspecialchars($strGroupId, ENT_QUOTES, 'UTF-8') ?>">
|
||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||
<h5 class="mb-0"><?= htmlspecialchars($strGroupLabel, ENT_QUOTES, 'UTF-8') ?></h5>
|
||
<span>
|
||
<button type="button" class="btn btn-xs btn-link btn-group-all p-0 mr-2">Tout</button>
|
||
<button type="button" class="btn btn-xs btn-link btn-group-none p-0">Aucun</button>
|
||
</span>
|
||
</div>
|
||
<div class="row">
|
||
<?php foreach ($arrPerms as $rowPerm) {
|
||
$strKey = $rowPerm['perm_key'];
|
||
$strId = 'perm_' . preg_replace('/[^a-z0-9_]/', '_', $strKey);
|
||
$strScope = (string)($rowPerm['perm_scope'] ?? '');
|
||
$strBadge = ($strScope === 'page')
|
||
? '<span class="badge badge-primary ml-1">page</span>'
|
||
: (($strScope === 'action')
|
||
? '<span class="badge badge-secondary ml-1">détail</span>'
|
||
: '');
|
||
$strPad = ($strScope === 'action') ? ' pl-3' : '';
|
||
?>
|
||
<div class="col-md-6 col-lg-4 mb-2<?= $strPad ?>">
|
||
<div class="custom-control custom-checkbox">
|
||
<input type="checkbox" class="custom-control-input perm-checkbox"
|
||
id="<?= htmlspecialchars($strId, ENT_QUOTES, 'UTF-8') ?>"
|
||
name="perm_keys[]"
|
||
value="<?= htmlspecialchars($strKey, ENT_QUOTES, 'UTF-8') ?>"
|
||
<?= isset($arrSelected[$strKey]) ? 'checked' : '' ?>>
|
||
<label class="custom-control-label" for="<?= htmlspecialchars($strId, ENT_QUOTES, 'UTF-8') ?>">
|
||
<?= htmlspecialchars($rowPerm['perm_label_fr'], ENT_QUOTES, 'UTF-8') ?>
|
||
<?= $strBadge ?>
|
||
<br><small class="eve-acces-perm-key"><code><?= htmlspecialchars($strKey, ENT_QUOTES, 'UTF-8') ?></code></small>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
<?php } ?>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
}
|
||
?>
|
||
</div>
|
||
</div>
|
||
|
||
<?php if ($blnCanEditKits) { ?>
|
||
<button type="submit" class="btn btn-success">
|
||
<i class="fa fa-save"></i> Enregistrer
|
||
</button>
|
||
<?php if ($arrDelete['can']) { ?>
|
||
<a class="btn btn-outline-danger ml-2"
|
||
href="eve_acces.php?action=delete&id=<?= intval($intRoleId) ?>"
|
||
onclick="return confirm('Supprimer définitivement ce kit ?');">
|
||
<i class="fa fa-trash"></i> Supprimer
|
||
</a>
|
||
<?php } elseif ($intRoleId > 0 && $arrDelete['message'] !== '') { ?>
|
||
<span class="text-muted small ml-2" title="<?= htmlspecialchars($arrDelete['message'], ENT_QUOTES, 'UTF-8') ?>">
|
||
<i class="fa fa-info-circle"></i> <?= htmlspecialchars($arrDelete['message'], ENT_QUOTES, 'UTF-8') ?>
|
||
</span>
|
||
<?php } ?>
|
||
<?php } ?>
|
||
</fieldset>
|
||
</form>
|
||
|
||
<?php if ($intRoleId > 0) {
|
||
fxEveAccesAdminRenderRoleAssignmentsBlock($intRoleId, array(
|
||
'anchor_id' => 'kit-assignations',
|
||
'statut' => 'actif',
|
||
));
|
||
} ?>
|
||
|
||
<script>
|
||
(function () {
|
||
function syncGrantsAllUi() {
|
||
var $chk = $('#role_grants_all');
|
||
if (!$chk.length) {
|
||
return;
|
||
}
|
||
var blnAll = $chk.is(':checked');
|
||
$('#card-kit-permissions').toggle(!blnAll);
|
||
if (blnAll) {
|
||
$('.perm-checkbox').prop('checked', false);
|
||
}
|
||
// MSIN-4478 — Kit total = jamais délégable (invitation ne doit pas donner tout).
|
||
var $deleg = $('#role_delegable');
|
||
if ($deleg.length && !$deleg.prop('disabled')) {
|
||
if (blnAll) {
|
||
$deleg.prop('checked', false).prop('disabled', true);
|
||
} else {
|
||
$deleg.prop('disabled', false);
|
||
}
|
||
}
|
||
}
|
||
|
||
$('#role_grants_all').on('change', syncGrantsAllUi);
|
||
syncGrantsAllUi();
|
||
|
||
$('#btn-perm-all').on('click', function () {
|
||
$('.perm-checkbox').prop('checked', true);
|
||
});
|
||
$('#btn-perm-none').on('click', function () {
|
||
$('.perm-checkbox').prop('checked', false);
|
||
});
|
||
$('.perm-group-block').each(function () {
|
||
var $block = $(this);
|
||
$block.find('.btn-group-all').on('click', function () {
|
||
$block.find('.perm-checkbox').prop('checked', true);
|
||
});
|
||
$block.find('.btn-group-none').on('click', function () {
|
||
$block.find('.perm-checkbox').prop('checked', false);
|
||
});
|
||
});
|
||
$('#role_label_fr').on('blur', function () {
|
||
var $code = $('#role_code');
|
||
if ($code.length && !$code.prop('readonly') && $.trim($code.val()) === '') {
|
||
var slug = $.trim($(this).val()).toLowerCase()
|
||
.normalize('NFD').replace(/[\u0300-\u036f]/g, '')
|
||
.replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '').substr(0, 32);
|
||
if (slug.length >= 2) {
|
||
$code.val(slug);
|
||
}
|
||
}
|
||
});
|
||
})();
|
||
</script>
|
||
<?php
|
||
}
|
||
|
||
function fxEveAccesAdminRenderMigrationPage($strFlash = '')
|
||
{
|
||
if (!fxEveAccesIsEnabled()) {
|
||
echo '<div class="alert alert-warning">Tables acces v2 non installees.</div>';
|
||
return;
|
||
}
|
||
|
||
$intRoleId = fxEveAccesGetMigrationLegacyRoleId();
|
||
$arrStats = fxEveAccesMigrationGetStats();
|
||
$intTotal = intval($arrStats['total_legacy']);
|
||
$intPendingEvents = intval($arrStats['pending_events']);
|
||
|
||
if ($strFlash !== '') {
|
||
echo '<div class="alert alert-success">' . htmlspecialchars($strFlash, ENT_QUOTES, 'UTF-8') . '</div>';
|
||
}
|
||
if (!empty($_GET['err'])) {
|
||
echo '<div class="alert alert-danger">' . htmlspecialchars((string)$_GET['err'], ENT_QUOTES, 'UTF-8') . '</div>';
|
||
}
|
||
?>
|
||
<h1 class="mb-3">Migration promoteur legacy → v2</h1>
|
||
<p class="text-muted mb-3">
|
||
Action <strong>unique et globale</strong> : parcourt <strong>tous</strong> les comptes avec
|
||
<code>com_eve_promoteur</code>, assigne le kit <code>migration_legacy</code> une fois par événement
|
||
(tampon journal), puis ne redemande plus. Le champ legacy n'est pas modifié.
|
||
Gérer les kits ensuite sur chaque <a href="index.php?t=<?= urlencode(base64_encode('2')) ?>&a=list">fiche compte</a>.
|
||
</p>
|
||
|
||
<div class="card mb-3">
|
||
<div class="card-body py-3">
|
||
<div class="row text-center">
|
||
<div class="col-md-6">
|
||
<div class="h4 mb-0"><?= $intTotal ?></div>
|
||
<div class="small text-muted">Comptes promoteur legacy</div>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<div class="h4 mb-0<?= $intPendingEvents > 0 ? ' text-warning' : ' text-success' ?>"><?= $intPendingEvents ?></div>
|
||
<div class="small text-muted">Événements sans tampon migration</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<?php if ($intRoleId <= 0) { ?>
|
||
<div class="alert alert-warning mb-0">
|
||
Kit <code>migration_legacy</code> introuvable —
|
||
exécuter <code>sql/MSIN-eve-acces-v2-phase4-role-grants-all.sql</code>.
|
||
</div>
|
||
<?php } elseif ($intPendingEvents > 0) { ?>
|
||
<p class="mb-0">
|
||
<a class="btn btn-warning btn-lg"
|
||
href="index.php?action=migrateveacceslegacyall"
|
||
onclick="return confirm('Migrer <?= $intPendingEvents ?> evenement(s) sur <?= $intTotal ?> compte(s) promoteur legacy ?');">
|
||
<i class="fa fa-exchange"></i> Migrer tous les promoteurs legacy
|
||
</a>
|
||
</p>
|
||
<?php } else { ?>
|
||
<div class="alert alert-success mb-0">
|
||
<i class="fa fa-check"></i> Migration terminée — aucun événement legacy en attente.
|
||
</div>
|
||
<?php } ?>
|
||
<?php
|
||
}
|
||
|
||
/** Affichage date/heure rapport migration (vide → tiret). */
|
||
function fxEveAccesAdminFormatReportDatetime($strDt)
|
||
{
|
||
$strDt = trim((string)$strDt);
|
||
if ($strDt === '' || strpos($strDt, '0000-00-00') === 0) {
|
||
return '—';
|
||
}
|
||
|
||
return substr($strDt, 0, 16);
|
||
}
|