Files
ms1inscription-v5/php/inc_fx_eve_acces.php

2118 lines
73 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* Acces evenement v2 — parallele au legacy com_eve_promoteur.
* Ne modifie jamais les champs legacy.
*/
function fxEveAccesIsEnabled()
{
static $blnEnabled = null;
global $objDatabase;
if (!isset($objDatabase)) {
return false;
}
if ($blnEnabled !== null) {
return $blnEnabled;
}
$tab = $objDatabase->fxGetResults("SHOW TABLES LIKE 'inscriptions_eve_acces'");
$blnEnabled = ($tab != null && count($tab) > 0);
return $blnEnabled;
}
/**
* Super admin connecte (canal usa_id).
* MSIN-4401 — N'accorde AUCUN droit metier v2 (kits / permissions).
* Sert uniquement aux outils admin (inspecteur cadenas, edition kits, etc.).
*/
function fxEveAccesIsSuperAdminSession()
{
return !empty($_SESSION['usa_id']);
}
/**
* Corps SELECT des acces actifs (remplace l'ancienne vue v_eve_acces_actif).
* Pas de vue stockee : evite le DEFINER non copiable par Navicat / releve.
*/
function fxEveAccesActifBody()
{
return "SELECT ea.ea_id, ea.com_id, ea.eve_id, ea.role_id,
r.role_code, r.role_label_fr, r.role_label_en,
ea.ea_statut, ea.ea_expires_at, ea.ea_expire_days,
ea.ea_granted_by, ea.ea_created_at
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.ea_statut = 'actif'
AND (ea.ea_expires_at IS NULL OR ea.ea_expires_at > NOW())";
}
/** Sous-requete aliasee, equivalente a l'ancienne vue v_eve_acces_actif. */
function fxEveAccesActifSql()
{
return "(" . fxEveAccesActifBody() . ") v_eve_acces_actif";
}
/**
* Sous-requete aliasee, equivalente a l'ancienne vue v_eve_acces_permissions
* (kits via roles + permissions extra individuelles).
*/
function fxEveAccesPermSql()
{
return "((SELECT v.ea_id, v.com_id, v.eve_id, v.role_id, v.role_code,
erp.perm_key, p.perm_group, p.perm_scope, p.perm_label_fr, p.perm_phase
FROM (" . fxEveAccesActifBody() . ") v
INNER JOIN inscriptions_eve_role_permissions erp ON erp.role_id = v.role_id
INNER JOIN inscriptions_eve_permissions p ON p.perm_key = erp.perm_key AND p.perm_actif = 1)
UNION
(SELECT NULL AS ea_id, ae.com_id, ae.eve_id, NULL AS role_id, 'extra' AS role_code,
ae.perm_key, p.perm_group, p.perm_scope, p.perm_label_fr, p.perm_phase
FROM inscriptions_eve_acces_extra ae
INNER JOIN inscriptions_eve_permissions p ON p.perm_key = ae.perm_key AND p.perm_actif = 1
WHERE ae.ae_statut = 'actif')) v_eve_acces_permissions";
}
function fxEveAccesGetRoles($blnActifOnly = true)
{
global $objDatabase;
if (!fxEveAccesIsEnabled()) {
return array();
}
$sql = "SELECT role_id, role_code, role_label_fr, role_label_en, role_description_fr
FROM inscriptions_eve_roles";
if ($blnActifOnly) {
$sql .= " WHERE role_actif = 1";
}
$sql .= " ORDER BY role_tri ASC, role_label_fr ASC";
return $objDatabase->fxGetResults($sql);
}
/** Kits proposables par un promoteur (role_delegable = 1, hors migration_legacy / kit total). */
function fxEveAccesGetDelegableRoles()
{
global $objDatabase;
if (!fxEveAccesIsEnabled()) {
return array();
}
$blnHasDelegable = false;
$tabCol = $objDatabase->fxGetResults("SHOW COLUMNS FROM inscriptions_eve_roles LIKE 'role_delegable'");
if ($tabCol != null && count($tabCol) > 0) {
$blnHasDelegable = true;
}
if (!$blnHasDelegable) {
return array();
}
// MSIN-4478 — jamais offrir un kit total (rapports / argent / tout) en invitation promoteur.
$strNoGrantsAll = '';
if (fxEveAccesHasGrantsAllColumn()) {
$strNoGrantsAll = ' AND role_grants_all = 0';
}
$sql = "SELECT role_id, role_code, role_label_fr, role_label_en, role_description_fr
FROM inscriptions_eve_roles
WHERE role_actif = 1
AND role_delegable = 1
AND role_code <> 'migration_legacy'
$strNoGrantsAll
ORDER BY role_tri ASC, role_label_fr ASC";
$tab = $objDatabase->fxGetResults($sql);
return ($tab != null) ? $tab : array();
}
/** Le kit est-il délégable (invite promoteur) ? */
function fxEveAccesRoleIsDelegable($intRoleId)
{
global $objDatabase;
$intRoleId = intval($intRoleId);
if ($intRoleId <= 0 || !fxEveAccesIsEnabled()) {
return false;
}
$tabCol = $objDatabase->fxGetResults("SHOW COLUMNS FROM inscriptions_eve_roles LIKE 'role_delegable'");
if ($tabCol == null || count($tabCol) === 0) {
return false;
}
$strGrantsCol = fxEveAccesHasGrantsAllColumn() ? ', role_grants_all' : ', 0 AS role_grants_all';
$row = $objDatabase->fxGetRow(
"SELECT role_id, role_code, role_delegable, role_actif $strGrantsCol
FROM inscriptions_eve_roles WHERE role_id = $intRoleId LIMIT 1"
);
if ($row === null || intval($row['role_actif']) !== 1) {
return false;
}
if (($row['role_code'] ?? '') === 'migration_legacy') {
return false;
}
// MSIN-4478 — kit total = non délégable (même si la case est cochée en BD).
if (intval($row['role_grants_all'] ?? 0) === 1) {
return false;
}
return intval($row['role_delegable'] ?? 0) === 1;
}
function fxEveAccesCanTeamManage($intComId, $intEveId)
{
return fxEveAccesHasPermission(intval($intComId), intval($intEveId), 'team.manage');
}
/** Promoteur peut gérer / inviter des accès v2 sur cet événement ? */
function fxEveAccesCanTeamInvite($intComId, $intEveId)
{
return fxEveAccesHasAnyPermission(
intval($intComId),
intval($intEveId),
array('team.invite', 'team.manage')
);
}
/**
* Accès v2 actifs (et invitations) pour un événement — vue promoteur.
*
* @return array<int, array<string, mixed>>
*/
function fxEveAccesListByEveId($intEveId, $blnActifOnly = true)
{
global $objDatabase;
if (!fxEveAccesIsEnabled() || intval($intEveId) <= 0) {
return array();
}
$sql = "SELECT ea.ea_id, ea.com_id, ea.eve_id, ea.role_id, ea.ea_statut,
ea.ea_created_at, ea.ea_expires_at, ea.ea_expire_days, ea.ea_granted_by,
r.role_code, r.role_label_fr, r.role_label_en,
c.com_prenom, c.com_nom, c.com_courriel, c.com_lastvisit";
// MSIN-4401 — flag invitation (si colonne présente)
$tabInviteCol = $objDatabase->fxGetResults("SHOW COLUMNS FROM inscriptions_comptes LIKE 'com_invite_team'");
if ($tabInviteCol != null && count($tabInviteCol) > 0) {
$sql .= ', c.com_invite_team';
}
$sql .= "
FROM inscriptions_eve_acces ea
INNER JOIN inscriptions_eve_roles r ON r.role_id = ea.role_id
INNER JOIN inscriptions_comptes c ON c.com_id = ea.com_id
WHERE ea.eve_id = " . intval($intEveId);
if ($blnActifOnly) {
$sql .= " AND ea.ea_statut IN ('actif', 'invite')
AND (ea.ea_expires_at IS NULL OR ea.ea_expires_at > NOW())";
}
$sql .= " ORDER BY FIELD(ea.ea_statut, 'actif', 'invite', 'revoke'),
c.com_nom ASC, c.com_prenom ASC, r.role_label_fr ASC";
$tab = $objDatabase->fxGetResults($sql);
return ($tab != null) ? $tab : array();
}
function fxEveAccesListByComId($intComId)
{
global $objDatabase;
if (!fxEveAccesIsEnabled()) {
return array();
}
$sql = "SELECT ea.ea_id, ea.com_id, ea.eve_id, ea.role_id, ea.ea_statut,
ea.ea_expires_at, ea.ea_expire_days, ea.ea_granted_by, ea.ea_note,
ea.ea_created_at, ea.ea_revoked_at,
r.role_code, r.role_label_fr,
e.eve_nom_fr, e.eve_date_fin
FROM inscriptions_eve_acces ea
INNER JOIN inscriptions_eve_roles r ON r.role_id = ea.role_id
LEFT JOIN inscriptions_evenements e ON e.eve_id = ea.eve_id
WHERE ea.com_id = " . intval($intComId) . "
ORDER BY ea.ea_statut ASC, e.eve_date_fin DESC, ea.ea_created_at DESC";
return $objDatabase->fxGetResults($sql);
}
function fxEveAccesComHasV2($intComId)
{
global $objDatabase;
if (!fxEveAccesIsEnabled()) {
return false;
}
$sql = "SELECT COUNT(*) FROM " . fxEveAccesActifSql() . " WHERE com_id = " . intval($intComId);
$intNb = $objDatabase->fxGetVar($sql);
return ($intNb != null && intval($intNb) > 0);
}
function fxEveAccesComHasV2ForEvent($intComId, $intEveId)
{
global $objDatabase;
if (!fxEveAccesIsEnabled()) {
return false;
}
$sql = "SELECT COUNT(*) FROM " . fxEveAccesActifSql() . "
WHERE com_id = " . intval($intComId) . "
AND eve_id = " . intval($intEveId);
$intNb = $objDatabase->fxGetVar($sql);
return ($intNb != null && intval($intNb) > 0);
}
function fxEveAccesGetEventIds($intComId)
{
global $objDatabase;
if (!fxEveAccesIsEnabled()) {
return array();
}
$sql = "SELECT eve_id FROM " . fxEveAccesActifSql() . " WHERE com_id = " . intval($intComId);
$tab = $objDatabase->fxGetResults($sql);
$arrIds = array();
if ($tab != null) {
foreach ($tab as $row) {
$arrIds[] = (string) intval($row['eve_id']);
}
}
return $arrIds;
}
/** Acces web gestion inscriptions : page V2 OU au moins une action inscriptions_gestion.* */
function fxEveAccesHasInscrGestionWebAccess($intComId, $intEveId)
{
if (fxEveAccesComEventHasGrantsAllKit(intval($intComId), intval($intEveId))) {
return true;
}
// MSIN-4401 — plus de registrations.view (ancienne clé API) : uniquement la page / actions V2
if (fxEveAccesHasPermission(intval($intComId), intval($intEveId), 'inscriptions_gestion.view')) {
return true;
}
global $objDatabase;
if (!fxEveAccesIsEnabled()) {
return false;
}
$sql = "SELECT COUNT(*) FROM " . fxEveAccesPermSql() . "
WHERE com_id = " . intval($intComId) . "
AND eve_id = " . intval($intEveId) . "
AND perm_key LIKE 'inscriptions_gestion.%'";
$intNb = $objDatabase->fxGetVar($sql);
return ($intNb != null && intval($intNb) > 0);
}
function fxEveAccesGetEventIdsWithInscrGestionAccess($intComId)
{
global $objDatabase;
if (!fxEveAccesIsEnabled()) {
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 (
perm_key = 'inscriptions_gestion.view'
OR perm_key LIKE 'inscriptions_gestion.%'
)
ORDER BY eve_id ASC";
$tab = $objDatabase->fxGetResults($sql);
if ($tab != null) {
foreach ($tab as $row) {
$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);
}
/** MSIN-4401 — Colonne kit role_fiche_sections_open presente ? */
function fxEveAccesHasFicheSectionsOpenColumn()
{
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;
}
/**
* MSIN-4401 — Au moins un kit actif du compte force les sections de la fiche inscriptions ouvertes.
*/
function fxEveAccesComEventHasFicheSectionsOpenKit($intComId, $intEveId)
{
global $objDatabase;
if (!fxEveAccesIsEnabled() || !fxEveAccesHasFicheSectionsOpenColumn()) {
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_fiche_sections_open = 1";
$intNb = $objDatabase->fxGetVar($sql);
return ($intNb != null && intval($intNb) > 0);
}
function fxEveAccesHasPermission($intComId, $intEveId, $strPermKey)
{
// MSIN-4401 — Pas de bypass super-admin : seuls kits / extras (ou grants_all) comptent.
global $objDatabase;
if (!fxEveAccesIsEnabled()) {
return false;
}
if (fxEveAccesComEventHasGrantsAllKit($intComId, $intEveId)) {
return fxEveAccesCatalogPermIsActive($strPermKey);
}
$sql = "SELECT COUNT(*) FROM " . fxEveAccesPermSql() . "
WHERE com_id = " . intval($intComId) . "
AND eve_id = " . intval($intEveId) . "
AND perm_key = '" . $objDatabase->fxEscape($strPermKey) . "'";
$intNb = $objDatabase->fxGetVar($sql);
return ($intNb != null && intval($intNb) > 0);
}
function fxEveAccesHasAnyPermission($intComId, $intEveId, $arrPermKeys)
{
global $objDatabase;
if (!fxEveAccesIsEnabled() || empty($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) . "'";
}
$sql = "SELECT COUNT(*) FROM " . fxEveAccesPermSql() . "
WHERE com_id = " . intval($intComId) . "
AND eve_id = " . intval($intEveId) . "
AND perm_key IN (" . implode(',', $arrEsc) . ")";
$intNb = $objDatabase->fxGetVar($sql);
return ($intNb != null && intval($intNb) > 0);
}
function fxEveAccesGetEventIdsWithAnyPermission($intComId, $arrPermKeys)
{
global $objDatabase;
if (!fxEveAccesIsEnabled() || empty($arrPermKeys)) {
return array();
}
$arrEsc = array();
foreach ($arrPermKeys as $strKey) {
$arrEsc[] = "'" . $objDatabase->fxEscape($strKey) . "'";
}
$sql = "SELECT DISTINCT eve_id FROM " . fxEveAccesPermSql() . "
WHERE com_id = " . intval($intComId) . "
AND perm_key IN (" . implode(',', $arrEsc) . ")
ORDER BY eve_id ASC";
$tab = $objDatabase->fxGetResults($sql);
$arrIds = array();
if ($tab != null) {
foreach ($tab as $row) {
$arrIds[] = intval($row['eve_id']);
}
}
return $arrIds;
}
/** Outil debug QR — permission v2 tools.qr_test (pas de bypass super-admin). */
function fxEveAccesCanQrTest($intComId)
{
if (!fxEveAccesIsEnabled() || intval($intComId) <= 0) {
return false;
}
global $objDatabase;
$sql = "SELECT COUNT(*) FROM " . fxEveAccesPermSql() . "
WHERE com_id = " . intval($intComId) . "
AND perm_key = 'tools.qr_test'";
$intNb = $objDatabase->fxGetVar($sql);
return ($intNb != null && intval($intNb) > 0);
}
function fxEveAccesGetCatalogPermissions($strScope = null, $blnActifOnly = true)
{
global $objDatabase;
if (!fxEveAccesIsEnabled()) {
return array();
}
$sql = "SELECT perm_key, perm_group, perm_scope, perm_label_fr, perm_label_en, perm_phase, perm_tri
FROM inscriptions_eve_permissions";
$arrWhere = array();
if ($blnActifOnly) {
$arrWhere[] = 'perm_actif = 1';
}
if ($strScope !== null && $strScope !== '') {
$arrWhere[] = "perm_scope = '" . $objDatabase->fxEscape($strScope) . "'";
}
if (!empty($arrWhere)) {
$sql .= ' WHERE ' . implode(' AND ', $arrWhere);
}
$sql .= ' ORDER BY perm_group ASC, perm_tri ASC, perm_key ASC';
return $objDatabase->fxGetResults($sql);
}
function fxEveAccesListExtraByComId($intComId)
{
global $objDatabase;
if (!fxEveAccesIsEnabled()) {
return array();
}
$sql = "SELECT ae.ae_id, ae.com_id, ae.eve_id, ae.perm_key, ae.ae_statut, ae.ae_created_at,
p.perm_label_fr, p.perm_scope,
e.eve_nom_fr
FROM inscriptions_eve_acces_extra ae
INNER JOIN inscriptions_eve_permissions p ON p.perm_key = ae.perm_key
LEFT JOIN inscriptions_evenements e ON e.eve_id = ae.eve_id
WHERE ae.com_id = " . intval($intComId) . "
ORDER BY ae.ae_statut ASC, e.eve_date_fin DESC, p.perm_group ASC, p.perm_tri ASC";
return $objDatabase->fxGetResults($sql);
}
function fxEveAccesGrantExtra($intComId, $intEveId, $strPermKey, $intGrantedBy, $strNote = '')
{
global $objDatabase;
if (!fxEveAccesIsEnabled()) {
return array('state' => 'error', 'message' => 'Tables v2 non installees');
}
$intComId = intval($intComId);
$intEveId = intval($intEveId);
$strPermKey = trim((string)$strPermKey);
if ($intComId <= 0 || $intEveId <= 0 || $strPermKey === '') {
return array('state' => 'error', 'message' => 'Parametres invalides');
}
$tabPerm = $objDatabase->fxGetRow(
"SELECT perm_key FROM inscriptions_eve_permissions
WHERE perm_key = '" . $objDatabase->fxEscape($strPermKey) . "' AND perm_actif = 1 LIMIT 1"
);
if ($tabPerm == null) {
return array('state' => 'error', 'message' => 'Permission invalide');
}
$intNbKits = intval($objDatabase->fxGetVar(
"SELECT COUNT(*) FROM inscriptions_eve_acces
WHERE com_id = $intComId AND eve_id = $intEveId AND ea_statut = 'actif'"
));
if ($intNbKits <= 0) {
return array('state' => 'error', 'message' => 'Assigner au moins un kit avant un droit individuel.');
}
$strNote = $objDatabase->fxEscape(trim($strNote));
$strGrantedBy = (intval($intGrantedBy) > 0) ? intval($intGrantedBy) : 'NULL';
$sql = "INSERT INTO inscriptions_eve_acces_extra
(com_id, eve_id, perm_key, ae_statut, ae_granted_by, ae_note)
VALUES
($intComId, $intEveId, '" . $objDatabase->fxEscape($strPermKey) . "', 'actif', $strGrantedBy, '$strNote')
ON DUPLICATE KEY UPDATE
ae_statut = 'actif',
ae_granted_by = VALUES(ae_granted_by),
ae_note = VALUES(ae_note),
ae_revoked_at = NULL,
ae_updated_at = NOW()";
$objDatabase->fxQuery($sql);
$intAeId = intval($objDatabase->fxGetVar(
"SELECT ae_id FROM inscriptions_eve_acces_extra
WHERE com_id = $intComId AND eve_id = $intEveId
AND perm_key = '" . $objDatabase->fxEscape($strPermKey) . "' LIMIT 1"
));
fxEveAccesWriteLog(null, $intComId, $intEveId, null, 'extra_grant', 'Grant extra: ' . $strPermKey, $intGrantedBy);
return array('state' => 'success', 'ae_id' => $intAeId);
}
function fxEveAccesRevokeExtra($intAeId, $intRevokedBy)
{
global $objDatabase;
if (!fxEveAccesIsEnabled()) {
return array('state' => 'error', 'message' => 'Tables v2 non installees');
}
$intAeId = intval($intAeId);
$tab = $objDatabase->fxGetRow("SELECT * FROM inscriptions_eve_acces_extra WHERE ae_id = " . $intAeId . " LIMIT 1");
if ($tab == null) {
return array('state' => 'error', 'message' => 'Grant extra introuvable');
}
$sql = "UPDATE inscriptions_eve_acces_extra
SET ae_statut = 'revoke',
ae_revoked_at = NOW(),
ae_updated_at = NOW()
WHERE ae_id = " . $intAeId;
$objDatabase->fxQuery($sql);
fxEveAccesWriteLog(null, $tab['com_id'], $tab['eve_id'], null, 'extra_revoke', 'Revoke extra: ' . $tab['perm_key'], $intRevokedBy);
return array('state' => 'success');
}
function fxEveAccesResolveEveIdFromParId($intParId)
{
global $objDatabase;
$intParId = intval($intParId);
if ($intParId <= 0) {
return 0;
}
$intEveId = intval($objDatabase->fxGetVar(
'SELECT eve_id FROM resultats_participants WHERE par_id = ' . $intParId . ' LIMIT 1'
));
return ($intEveId > 0) ? $intEveId : 0;
}
/**
* Gate AJAX promoteur : legacy promoteur OU permission v2 explicite.
* Si le compte a deja des acces v2 actifs, exige la permission demandee.
*/
function fxEveAccesAssertPromoteurAction($intComId, $intEveId, $strPermKey)
{
$intComId = intval($intComId);
$intEveId = intval($intEveId);
if ($intComId <= 0 || $intEveId <= 0) {
return false;
}
if (!fxEveAccesComHasV2ForEvent($intComId, $intEveId)) {
if (!function_exists('fxIsPromoteur')) {
require_once __DIR__ . '/inc_fonctions.php';
}
return fxIsPromoteur($intComId, $intEveId);
}
return fxEveAccesHasPermission($intComId, $intEveId, $strPermKey);
}
function fxEveAccesGrant($intComId, $intEveId, $intRoleId, $intExpireDays, $intGrantedBy, $strNote = '', $strStatut = 'actif')
{
global $objDatabase;
if (!fxEveAccesIsEnabled()) {
return array('state' => 'error', 'message' => 'Tables v2 non installees');
}
$intComId = intval($intComId);
$intEveId = intval($intEveId);
$intRoleId = intval($intRoleId);
$intGrantedBy = intval($intGrantedBy);
$strStatut = ($strStatut === 'invite') ? 'invite' : 'actif';
if ($intComId <= 0 || $intEveId <= 0 || $intRoleId <= 0) {
return array('state' => 'error', 'message' => 'Parametres invalides');
}
$tabRole = $objDatabase->fxGetRow("SELECT role_id FROM inscriptions_eve_roles WHERE role_id = " . $intRoleId . " AND role_actif = 1 LIMIT 1");
if ($tabRole == null) {
return array('state' => 'error', 'message' => 'Role invalide');
}
$tabCom = $objDatabase->fxGetRow("SELECT com_id FROM inscriptions_comptes WHERE com_id = " . $intComId . " LIMIT 1");
if ($tabCom == null) {
return array('state' => 'error', 'message' => 'Compte introuvable');
}
$tabEve = $objDatabase->fxGetRow("SELECT eve_id FROM inscriptions_evenements WHERE eve_id = " . $intEveId . " LIMIT 1");
if ($tabEve == null) {
return array('state' => 'error', 'message' => 'Evenement introuvable');
}
$strExpires = 'NULL';
$intExpireDaysStore = 'NULL';
if ($intExpireDays > 0) {
$strExpires = "'" . $objDatabase->fxEscape(date('Y-m-d H:i:s', strtotime('+' . intval($intExpireDays) . ' days'))) . "'";
$intExpireDaysStore = intval($intExpireDays);
}
$strNote = $objDatabase->fxEscape(trim($strNote));
$strGrantedBy = ($intGrantedBy > 0) ? $intGrantedBy : 'NULL';
$sql = "INSERT INTO inscriptions_eve_acces
(com_id, eve_id, role_id, ea_statut, ea_expires_at, ea_expire_days, ea_granted_by, ea_note)
VALUES
($intComId, $intEveId, $intRoleId, '$strStatut', $strExpires, $intExpireDaysStore, $strGrantedBy, '$strNote')
ON DUPLICATE KEY UPDATE
role_id = VALUES(role_id),
ea_statut = VALUES(ea_statut),
ea_expires_at = VALUES(ea_expires_at),
ea_expire_days = VALUES(ea_expire_days),
ea_granted_by = VALUES(ea_granted_by),
ea_note = VALUES(ea_note),
ea_revoked_at = NULL,
ea_revoked_by = NULL,
ea_updated_at = NOW()";
$objDatabase->fxQuery($sql);
$intEaId = intval($objDatabase->fxGetVar(
"SELECT ea_id FROM inscriptions_eve_acces
WHERE com_id = $intComId AND eve_id = $intEveId AND role_id = $intRoleId
LIMIT 1"
));
if ($intEaId <= 0) {
// Repli si unique legacy (com+eve) encore en place sur certains environnements
$intEaId = intval($objDatabase->fxGetVar(
"SELECT ea_id FROM inscriptions_eve_acces
WHERE com_id = $intComId AND eve_id = $intEveId
ORDER BY ea_id DESC LIMIT 1"
));
}
if ($intEaId <= 0) {
return array('state' => 'error', 'message' => 'Acces non enregistre');
}
fxEveAccesWriteLog($intEaId, $intComId, $intEveId, $intRoleId, 'create', 'Grant / mise a jour acces v2', $intGrantedBy);
return array('state' => 'success', 'ea_id' => $intEaId);
}
/**
* MSIN-4401 — active les accès encore en statut invite après création du mot de passe.
*/
function fxEveAccesActivateInvitesForCompte($intComId)
{
global $objDatabase;
$intComId = intval($intComId);
if ($intComId <= 0 || !fxEveAccesIsEnabled()) {
return;
}
$objDatabase->fxQuery(
"UPDATE inscriptions_eve_acces
SET ea_statut = 'actif',
ea_updated_at = NOW()
WHERE com_id = $intComId
AND ea_statut = 'invite'"
);
}
function fxEveAccesRevoke($intEaId, $intRevokedBy)
{
global $objDatabase;
if (!fxEveAccesIsEnabled()) {
return array('state' => 'error', 'message' => 'Tables v2 non installees');
}
$intEaId = intval($intEaId);
$tab = $objDatabase->fxGetRow("SELECT * FROM inscriptions_eve_acces WHERE ea_id = " . $intEaId . " LIMIT 1");
if ($tab == null) {
return array('state' => 'error', 'message' => 'Acces introuvable');
}
$sql = "UPDATE inscriptions_eve_acces
SET ea_statut = 'revoke',
ea_revoked_at = NOW(),
ea_revoked_by = " . intval($intRevokedBy) . ",
ea_updated_at = NOW()
WHERE ea_id = " . $intEaId;
$objDatabase->fxQuery($sql);
fxEveAccesWriteLog($intEaId, $tab['com_id'], $tab['eve_id'], $tab['role_id'], 'revoke', 'Revoke manuel super admin', $intRevokedBy);
return array('state' => 'success');
}
function fxEveAccesRowIsActif($row)
{
if ($row['ea_statut'] !== 'actif') {
return false;
}
if (!empty($row['ea_expires_at']) && strtotime($row['ea_expires_at']) <= time()) {
return false;
}
return true;
}
function fxEveAccesReactivate($intEaId, $intGrantedBy)
{
global $objDatabase;
if (!fxEveAccesIsEnabled()) {
return array('state' => 'error', 'message' => 'Tables v2 non installees');
}
$tab = $objDatabase->fxGetRow("SELECT * FROM inscriptions_eve_acces WHERE ea_id = " . intval($intEaId) . " LIMIT 1");
if ($tab == null) {
return array('state' => 'error', 'message' => 'Acces introuvable');
}
$intExpireDays = intval($tab['ea_expire_days'] ?? 0);
return fxEveAccesGrant(
intval($tab['com_id']),
intval($tab['eve_id']),
intval($tab['role_id']),
$intExpireDays,
intval($intGrantedBy),
'Reactivation super admin'
);
}
function fxEveAccesReactivateExtra($intAeId, $intGrantedBy)
{
global $objDatabase;
if (!fxEveAccesIsEnabled()) {
return array('state' => 'error', 'message' => 'Tables v2 non installees');
}
$tab = $objDatabase->fxGetRow("SELECT * FROM inscriptions_eve_acces_extra WHERE ae_id = " . intval($intAeId) . " LIMIT 1");
if ($tab == null) {
return array('state' => 'error', 'message' => 'Grant extra introuvable');
}
return fxEveAccesGrantExtra(
intval($tab['com_id']),
intval($tab['eve_id']),
$tab['perm_key'],
intval($intGrantedBy),
'Reactivation super admin'
);
}
function fxEveAccesWriteLog($intEaId, $intComId, $intEveId, $intRoleId, $strAction, $strDetail, $intByComId)
{
global $objDatabase;
if (!fxEveAccesIsEnabled()) {
return;
}
$intEaId = ($intEaId > 0) ? intval($intEaId) : 'NULL';
$intRoleId = ($intRoleId > 0) ? intval($intRoleId) : 'NULL';
$intByComId = ($intByComId > 0) ? intval($intByComId) : 'NULL';
$sql = "INSERT INTO inscriptions_eve_acces_log
(ea_id, com_id, eve_id, role_id, log_action, log_detail, log_by_com_id)
VALUES
($intEaId, " . intval($intComId) . ", " . intval($intEveId) . ", $intRoleId,
'" . $objDatabase->fxEscape($strAction) . "',
'" . $objDatabase->fxEscape($strDetail) . "',
$intByComId)";
$objDatabase->fxQuery($sql);
}
function fxEveAccesGetPermissionsForComEvent($intComId, $intEveId)
{
global $objDatabase;
if (!fxEveAccesIsEnabled()) {
return array();
}
$sql = "SELECT perm_key, perm_group, perm_label_fr
FROM " . fxEveAccesPermSql() . "
WHERE com_id = " . intval($intComId) . "
AND eve_id = " . intval($intEveId) . "
ORDER BY perm_group, perm_key";
return $objDatabase->fxGetResults($sql);
}
/** Regroupe kits et extras actifs par eve_id pour la fiche compte super admin. */
function fxEveAccesCompteFormGroupByEvent($arrAcces, $arrExtras)
{
$arrGroups = array();
if ($arrAcces != null) {
foreach ($arrAcces as $row) {
if (!fxEveAccesRowIsActif($row)) {
continue;
}
$intEveId = intval($row['eve_id']);
if (!isset($arrGroups[$intEveId])) {
$arrGroups[$intEveId] = array(
'eve_id' => $intEveId,
'eve_nom_fr' => $row['eve_nom_fr'] ?? ('Événement #' . $intEveId),
'kits' => array(),
'extras' => array(),
);
}
$arrGroups[$intEveId]['kits'][] = $row;
}
}
if ($arrExtras != null) {
foreach ($arrExtras as $row) {
if (($row['ae_statut'] ?? '') !== 'actif') {
continue;
}
$intEveId = intval($row['eve_id']);
if (!isset($arrGroups[$intEveId])) {
$arrGroups[$intEveId] = array(
'eve_id' => $intEveId,
'eve_nom_fr' => $row['eve_nom_fr'] ?? ('Événement #' . $intEveId),
'kits' => array(),
'extras' => array(),
);
}
$arrGroups[$intEveId]['extras'][] = $row;
}
}
uasort($arrGroups, function ($a, $b) {
return strcasecmp($a['eve_nom_fr'], $b['eve_nom_fr']);
});
return $arrGroups;
}
/** URL fiche compte super admin (section acces v2). */
function fxEveAccesCompteAdminUrl($intComId, $intFocusEveId = 0)
{
$strUrl = 'index.php?t=' . urlencode(base64_encode('2'))
. '&a=mod&id=' . intval($intComId);
if (intval($intFocusEveId) > 0) {
$strUrl .= '&eve_acces_focus=' . intval($intFocusEveId);
}
return $strUrl . '#eve-acces-v2';
}
/** Regroupe kits et extras actifs par com_id pour la fiche evenement super admin. */
function fxEveAccesEventFormGroupByCom($intEveId)
{
global $objDatabase;
if (!fxEveAccesIsEnabled()) {
return array();
}
$intEveId = intval($intEveId);
$arrGroups = array();
$sqlKits = "SELECT ea.ea_id, ea.com_id, ea.role_id, ea.ea_statut, ea.ea_expires_at,
r.role_label_fr,
c.com_prenom, c.com_nom, c.com_courriel, c.com_telephone1
FROM inscriptions_eve_acces ea
INNER JOIN inscriptions_eve_roles r ON r.role_id = ea.role_id
INNER JOIN inscriptions_comptes c ON c.com_id = ea.com_id
WHERE ea.eve_id = $intEveId
AND ea.ea_statut = 'actif'
AND (ea.ea_expires_at IS NULL OR ea.ea_expires_at > NOW())
ORDER BY c.com_nom ASC, c.com_prenom ASC, r.role_tri ASC";
$arrKits = $objDatabase->fxGetResults($sqlKits);
if ($arrKits != null) {
foreach ($arrKits as $row) {
$intComId = intval($row['com_id']);
if (!isset($arrGroups[$intComId])) {
$arrGroups[$intComId] = array(
'com_id' => $intComId,
'com_prenom' => $row['com_prenom'],
'com_nom' => $row['com_nom'],
'com_courriel' => $row['com_courriel'],
'com_telephone1' => $row['com_telephone1'],
'kits' => array(),
'extras' => array(),
);
}
$arrGroups[$intComId]['kits'][] = $row;
}
}
$sqlExtras = "SELECT ae.ae_id, ae.com_id, ae.perm_key,
p.perm_label_fr,
c.com_prenom, c.com_nom, c.com_courriel, c.com_telephone1
FROM inscriptions_eve_acces_extra ae
INNER JOIN inscriptions_eve_permissions p ON p.perm_key = ae.perm_key
INNER JOIN inscriptions_comptes c ON c.com_id = ae.com_id
WHERE ae.eve_id = $intEveId
AND ae.ae_statut = 'actif'
ORDER BY c.com_nom ASC, c.com_prenom ASC, p.perm_tri ASC";
$arrExtras = $objDatabase->fxGetResults($sqlExtras);
if ($arrExtras != null) {
foreach ($arrExtras as $row) {
$intComId = intval($row['com_id']);
if (!isset($arrGroups[$intComId])) {
$arrGroups[$intComId] = array(
'com_id' => $intComId,
'com_prenom' => $row['com_prenom'],
'com_nom' => $row['com_nom'],
'com_courriel' => $row['com_courriel'],
'com_telephone1' => $row['com_telephone1'],
'kits' => array(),
'extras' => array(),
);
}
$arrGroups[$intComId]['extras'][] = $row;
}
}
uasort($arrGroups, function ($a, $b) {
$cmp = strcasecmp($a['com_nom'], $b['com_nom']);
if ($cmp !== 0) {
return $cmp;
}
return strcasecmp($a['com_prenom'], $b['com_prenom']);
});
return $arrGroups;
}
function fxEveAccesShowEventAccessPanel($intEveId)
{
if (!fxEveAccesIsEnabled()) {
return;
}
$intEveId = intval($intEveId);
$arrGroups = fxEveAccesEventFormGroupByCom($intEveId);
$intNb = count($arrGroups);
require_once __DIR__ . '/inc_fx_superadm_v2_ui.php';
$strHeaderExtra = '';
if ($intNb > 0) {
$strHeaderExtra = '<span class="superadm-v2-panel__header-extra ml-2">'
. '<span class="badge badge-light">' . intval($intNb) . '</span></span>';
}
fxSuperadmV2PanelOpen('Accès v2 — cet événement', array(
'collapse_id' => 'tableEveAccesV2',
'zone_class' => 'superadm-content-v2-zone mt-3 mb-2',
'header_extra' => $strHeaderExtra,
));
?>
<div id="pick-eve-acces-compte" class="position-relative mb-2" style="max-width:420px;">
<label class="small text-muted mb-0" for="pp-eve-acces-compte-email">
Rechercher un compte par courriel pour lui assigner des accès
</label>
<input type="text" class="form-control form-control-sm mt-1" id="pp-eve-acces-compte-email"
placeholder="Tapez un e-mail…" autocomplete="off">
<div id="pp-results-eve-acces-compte" class="list-group d-none mt-1"
style="position:absolute;left:0;right:0;z-index:1000;max-height:220px;overflow:auto;"></div>
</div>
<table class="table table-sm table-striped mt-2 mb-3">
<thead>
<tr>
<th style="width:20px">#</th>
<th>Prénom</th>
<th>Nom</th>
<th>Courriel</th>
<th>Droits</th>
<th style="width:90px" class="text-center">Compte</th>
</tr>
</thead>
<tbody>
<?php
if ($intNb === 0) {
echo '<tr><td colspan="6" class="text-muted">Aucun accès v2 sur cet événement.</td></tr>';
} else {
$intIdx = 0;
foreach ($arrGroups as $arrGroup) {
?>
<tr>
<td class="text-muted"><?= $intIdx ?></td>
<td><?= htmlspecialchars($arrGroup['com_prenom'], ENT_QUOTES, 'UTF-8') ?></td>
<td><?= htmlspecialchars($arrGroup['com_nom'], ENT_QUOTES, 'UTF-8') ?></td>
<td><?= htmlspecialchars($arrGroup['com_courriel'], ENT_QUOTES, 'UTF-8') ?></td>
<td>
<?php
foreach ($arrGroup['kits'] as $rowKit) { ?>
<span class="badge badge-primary mr-1 mb-1 py-1 px-2">
<?= htmlspecialchars($rowKit['role_label_fr'], ENT_QUOTES, 'UTF-8') ?>
</span>
<?php }
foreach ($arrGroup['extras'] as $rowExtra) { ?>
<span class="badge mr-1 mb-1 py-1 px-2" style="background-color:#e67e22;color:#fff;">
<?= htmlspecialchars($rowExtra['perm_label_fr'], ENT_QUOTES, 'UTF-8') ?>
</span>
<?php }
if (count($arrGroup['kits']) === 0 && count($arrGroup['extras']) === 0) {
echo '<span class="text-muted">—</span>';
}
?>
</td>
<td class="text-center">
<a href="<?= htmlspecialchars(fxEveAccesCompteAdminUrl($arrGroup['com_id'], $intEveId), ENT_QUOTES, 'UTF-8') ?>"
class="btn btn-sm btn-outline-primary py-0"
title="Ouvrir la fiche compte">
<i class="fa fa-user"></i>
</a>
</td>
</tr>
<?php
$intIdx++;
}
}
?>
</tbody>
<?php if ($intNb > 0) { ?>
<tfoot>
<tr>
<th colspan="6" class="text-muted small font-weight-normal">
<?= $intNb ?> compte<?= $intNb > 1 ? 's' : '' ?> avec accès v2
</th>
</tr>
</tfoot>
<?php } ?>
</table>
<?php
fxSuperadmV2PanelClose(array('collapse_id' => 'tableEveAccesV2'));
?>
<script>
(function($){
var intFocusEveId = <?= $intEveId ?>;
var strCompteAccesBase = <?= json_encode('index.php?t=' . urlencode(base64_encode('2')) . '&a=mod&id=') ?>;
function compteAccesUrl(intComId) {
var url = strCompteAccesBase + encodeURIComponent(intComId);
if (intFocusEveId > 0) {
url += '&eve_acces_focus=' + encodeURIComponent(intFocusEveId);
}
return url + '#eve-acces-v2';
}
var $wrap = $('#pick-eve-acces-compte');
var $in = $('#pp-eve-acces-compte-email');
var $list = $('#pp-results-eve-acces-compte');
var timer = null, xhr = null;
function renderComptePick(items) {
$list.empty();
if (!items || !items.length) {
$list.addClass('d-none');
return;
}
items.forEach(function(it) {
var intComId = it.id || it.com_id;
var strLabel = it.email || it.com_courriel || '';
if (it.com_prenom || it.com_nom) {
strLabel = $.trim((it.com_prenom || '') + ' ' + (it.com_nom || ''))
+ ' — ' + strLabel;
}
$('<a href="#" class="list-group-item list-group-item-action"></a>')
.text(strLabel)
.data('comId', intComId)
.appendTo($list);
});
$list.removeClass('d-none');
}
$in.on('input', function() {
var q = $.trim(this.value);
$list.addClass('d-none').empty();
if (q.length < 2) {
return;
}
clearTimeout(timer);
timer = setTimeout(function() {
if (xhr) {
xhr.abort();
}
xhr = $.getJSON('ajax_newpromoteur.php', { action: 'search_email', q: q, eve_id: 0 }, renderComptePick)
.fail(function() { renderComptePick([]); });
}, 200);
});
$list.on('click', '.list-group-item', function(e) {
e.preventDefault();
var intComId = $(this).data('comId');
if (!intComId) {
return;
}
window.location.href = compteAccesUrl(intComId);
});
$(document).on('click', function(e) {
if (!$(e.target).closest($wrap).length) {
$list.addClass('d-none');
}
});
})(jQuery);
</script>
<?php
}
/** IDs evenements depuis inscriptions_comptes.com_eve_promoteur (CSV). */
function fxEveAccesParseLegacyPromoteurCsv($strCsv)
{
$strCsv = trim((string)$strCsv);
if ($strCsv === '') {
return array();
}
$arrIds = array();
foreach (explode(',', $strCsv) as $strPart) {
$intId = intval(trim($strPart));
if ($intId > 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);
}
/**
* Tampon historique migration legacy (ponctuelle) par compte × evenement.
* Ne depend pas du kit migration_legacy encore actif — journal + note de migration.
*
* @return array<int, string> eve_id => migrated_at (datetime)
*/
function fxEveAccesLegacyMigratedMapForCom($intComId)
{
global $objDatabase;
static $arrCache = array();
$intComId = intval($intComId);
if ($intComId <= 0) {
return array();
}
if (isset($arrCache[$intComId])) {
return $arrCache[$intComId];
}
$arrCache[$intComId] = array();
if (!fxEveAccesIsEnabled()) {
return $arrCache[$intComId];
}
$sql = "SELECT l.eve_id, MIN(l.log_created_at) AS migrated_at
FROM inscriptions_eve_acces_log l
INNER JOIN inscriptions_eve_roles r ON r.role_id = l.role_id
AND r.role_code = 'migration_legacy'
WHERE l.com_id = $intComId
AND l.log_action IN ('legacy_migrated', 'create')
GROUP BY l.eve_id";
$tab = $objDatabase->fxGetResults($sql);
if ($tab != null) {
foreach ($tab as $row) {
$intEveId = intval($row['eve_id']);
if ($intEveId > 0) {
$arrCache[$intComId][$intEveId] = (string)$row['migrated_at'];
}
}
}
$sqlNote = "SELECT eve_id, MIN(ea_created_at) AS migrated_at
FROM inscriptions_eve_acces
WHERE com_id = $intComId
AND ea_note LIKE 'Migration depuis com_eve_promoteur%'
GROUP BY eve_id";
$tabNote = $objDatabase->fxGetResults($sqlNote);
if ($tabNote != null) {
foreach ($tabNote as $row) {
$intEveId = intval($row['eve_id']);
if ($intEveId > 0 && !isset($arrCache[$intComId][$intEveId])) {
$arrCache[$intComId][$intEveId] = (string)$row['migrated_at'];
}
}
}
$sqlEa = "SELECT ea.eve_id, MIN(ea.ea_created_at) AS migrated_at
FROM inscriptions_eve_acces ea
INNER JOIN inscriptions_eve_roles r ON r.role_id = ea.role_id
AND r.role_code = 'migration_legacy'
WHERE ea.com_id = $intComId
GROUP BY ea.eve_id";
$tabEa = $objDatabase->fxGetResults($sqlEa);
if ($tabEa != null) {
foreach ($tabEa as $row) {
$intEveId = intval($row['eve_id']);
if ($intEveId > 0 && !isset($arrCache[$intComId][$intEveId])) {
$arrCache[$intComId][$intEveId] = (string)$row['migrated_at'];
}
}
}
return $arrCache[$intComId];
}
/** Migration legacy deja effectuee pour cet evenement (tampon ponctuel, pas etat temps reel). */
function fxEveAccesComEventWasLegacyMigrated($intComId, $intEveId, $arrMigratedMap = null)
{
$intComId = intval($intComId);
$intEveId = intval($intEveId);
if ($intComId <= 0 || $intEveId <= 0) {
return false;
}
if ($arrMigratedMap === null) {
$arrMigratedMap = fxEveAccesLegacyMigratedMapForCom($intComId);
}
return isset($arrMigratedMap[$intEveId]);
}
/**
* 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'];
}
}
$arrMigratedMap = fxEveAccesLegacyMigratedMapForCom($intComId);
foreach ($arrEveIds as $intEveId) {
$blnMigrated = fxEveAccesComEventWasLegacyMigrated($intComId, $intEveId, $arrMigratedMap);
$arrOut['events'][] = array(
'eve_id' => $intEveId,
'eve_nom_fr' => $arrEveNames[$intEveId] ?? ('Événement #' . $intEveId),
'migrated' => $blnMigrated,
'migrated_at' => $arrMigratedMap[$intEveId] ?? null,
);
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++;
fxEveAccesWriteLog(
intval($arrResult['ea_id'] ?? 0),
$intComId,
$intEveId,
$intRoleId,
'legacy_migrated',
'Migration promoteur legacy (ponctuelle)',
$intGrantedBy
);
} 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 : tampon historique en place pour tous les evenements legacy.',
'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(),
);
}
/** Tous les comptes avec com_eve_promoteur non vide. */
function fxEveAccesMigrationListAllLegacyComptes()
{
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);
return ($tab != null) ? $tab : array();
}
/** @deprecated Utiliser fxEveAccesMigrationListAllLegacyComptes + filtre pending si besoin. */
function fxEveAccesMigrationListComptesPending()
{
$arrRows = array();
foreach (fxEveAccesMigrationListAllLegacyComptes() 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;
}
/** Nombre d'evenements legacy encore sans tampon migration (tous comptes). */
function fxEveAccesMigrationCountPendingEvents()
{
$intPending = 0;
foreach (fxEveAccesMigrationListAllLegacyComptes() as $row) {
$arrStatus = fxEveAccesMigrationStatusForCom(intval($row['com_id']));
$intPending += intval($arrStatus['pending_count']);
}
return $intPending;
}
/** Totaux migration legacy (affichage super admin). */
function fxEveAccesMigrationGetStats()
{
global $objDatabase;
$arrOut = array(
'total_legacy' => 0,
'pending_events' => 0,
);
if (!fxEveAccesIsEnabled()) {
return $arrOut;
}
$arrOut['total_legacy'] = count(fxEveAccesMigrationListAllLegacyComptes());
$arrOut['pending_events'] = fxEveAccesMigrationCountPendingEvents();
return $arrOut;
}
function fxEveAccesShowCompteForm($intComId)
{
global $objDatabase;
if (!fxEveAccesIsEnabled()) {
echo '<div class="alert alert-warning">Tables acces v2 non installees. Executer les SQL MSIN-eve-acces-v2-phase1.</div>';
return;
}
$arrAcces = fxEveAccesListByComId($intComId);
$arrExtras = fxEveAccesListExtraByComId($intComId);
$arrRoles = fxEveAccesGetRoles(true);
$arrActionPerms = fxEveAccesGetCatalogPermissions('action');
$strT = urlencode($_GET['t'] ?? '');
$intComId = intval($intComId);
global $vDomaine;
$arrAccesRevoke = array();
$arrExtrasRevoke = array();
if ($arrAcces != null) {
foreach ($arrAcces as $row) {
if (!fxEveAccesRowIsActif($row)) {
if (($row['ea_statut'] ?? '') === 'revoke') {
$arrAccesRevoke[] = $row;
}
}
}
}
if ($arrExtras != null) {
foreach ($arrExtras as $row) {
if (($row['ae_statut'] ?? '') !== 'actif') {
$arrExtrasRevoke[] = $row;
}
}
}
$arrGroups = fxEveAccesCompteFormGroupByEvent($arrAcces, $arrExtras);
$intFocusEveId = intval($_GET['eve_acces_focus'] ?? 0);
$strFocusEveNom = '';
if ($intFocusEveId > 0) {
$tabFocusEve = $objDatabase->fxGetRow(
"SELECT eve_nom_fr FROM inscriptions_evenements WHERE eve_id = $intFocusEveId LIMIT 1"
);
if ($tabFocusEve != null) {
$strFocusEveNom = $tabFocusEve['eve_nom_fr'];
} else {
$intFocusEveId = 0;
}
}
$strRoleOptions = '<option value="">—</option>';
if ($arrRoles != null) {
foreach ($arrRoles as $rowRole) {
$strRoleOptions .= '<option value="' . intval($rowRole['role_id']) . '">'
. htmlspecialchars($rowRole['role_label_fr'], ENT_QUOTES, 'UTF-8') . '</option>';
}
}
$strPermOptions = '<option value="">—</option>';
if ($arrActionPerms != null) {
foreach ($arrActionPerms as $rowPerm) {
$strPermOptions .= '<option value="' . htmlspecialchars($rowPerm['perm_key'], ENT_QUOTES, 'UTF-8') . '">'
. htmlspecialchars($rowPerm['perm_label_fr'], ENT_QUOTES, 'UTF-8') . '</option>';
}
}
require_once __DIR__ . '/inc_fx_superadm_v2_ui.php';
fxSuperadmV2PanelOpen('Accès aux événements', array(
'zone_id' => 'eve-acces-v2',
'zone_class' => 'superadm-content-v2-zone mt-4 mb-3',
));
?>
<p class="text-muted small mb-2">
<a href="<?= htmlspecialchars($vDomaine, ENT_QUOTES, 'UTF-8') ?>/superadm/eve_acces.php?p=kits">Gérer les kits</a>
</p>
<table class="table table-sm table-striped mb-2">
<thead>
<tr>
<th style="width:32%">Événement</th>
<th>Assigné</th>
<th class="text-right text-nowrap" style="width:130px">Ajouter un kit</th>
<th class="text-right text-nowrap" style="width:130px">Ajouter un droit</th>
</tr>
</thead>
<tbody>
<?php
if (count($arrGroups) === 0) {
echo '<tr><td colspan="4" class="text-muted">Aucun accès.</td></tr>';
} else {
foreach ($arrGroups as $arrGroup) {
$intEveId = intval($arrGroup['eve_id']);
$blnHasKit = count($arrGroup['kits']) > 0;
?>
<tr>
<td class="align-middle">
<strong><?= htmlspecialchars($arrGroup['eve_nom_fr'], ENT_QUOTES, 'UTF-8') ?></strong>
<span class="text-muted small">(#<?= $intEveId ?>)</span>
</td>
<td class="align-middle">
<?php
if (!$blnHasKit && count($arrGroup['extras']) === 0) {
echo '<span class="text-muted">—</span>';
} else {
foreach ($arrGroup['kits'] as $rowKit) { ?>
<span class="badge badge-primary mr-1 mb-1 py-1 px-2">
<?= htmlspecialchars($rowKit['role_label_fr'], ENT_QUOTES, 'UTF-8') ?>
<a href="index.php?t=<?= $strT ?>&amp;a=mod&amp;id=<?= $intComId ?>&amp;action=revokeveacces&amp;ea_id=<?= intval($rowKit['ea_id']) ?>"
class="text-white ml-1"
title="Retirer ce kit"
onclick="return confirm('Retirer ce kit ?');">&times;</a>
</span>
<?php }
foreach ($arrGroup['extras'] as $rowExtra) { ?>
<span class="badge mr-1 mb-1 py-1 px-2" style="background-color:#e67e22;color:#fff;">
<?= htmlspecialchars($rowExtra['perm_label_fr'], ENT_QUOTES, 'UTF-8') ?>
<a href="index.php?t=<?= $strT ?>&amp;a=mod&amp;id=<?= $intComId ?>&amp;action=revokeveaccesextra&amp;ae_id=<?= intval($rowExtra['ae_id']) ?>"
class="text-white ml-1"
title="Retirer ce droit"
onclick="return confirm('Retirer ce droit ?');">&times;</a>
</span>
<?php }
}
?>
</td>
<td class="align-middle text-right text-nowrap">
<select id="eve-role-<?= $intEveId ?>" class="custom-select custom-select-sm d-inline-block" style="width:96px;vertical-align:middle;" aria-label="Kit">
<?= $strRoleOptions ?>
</select>
<button type="button" class="btn btn-outline-primary btn-sm py-0 btn-eve-add-kit" data-eve-id="<?= $intEveId ?>" title="Ajouter un kit">+</button>
</td>
<td class="align-middle text-right text-nowrap">
<?php if ($blnHasKit) { ?>
<select id="eve-extra-<?= $intEveId ?>" class="custom-select custom-select-sm d-inline-block" style="width:96px;vertical-align:middle;" aria-label="Droit individuel">
<?= $strPermOptions ?>
</select>
<button type="button" class="btn btn-outline-warning btn-sm py-0 btn-eve-add-extra" data-eve-id="<?= $intEveId ?>" title="Ajouter un droit individuel" style="border-color:#e67e22;color:#e67e22;">+</button>
<?php } else { ?>
<span class="text-muted small">—</span>
<?php } ?>
</td>
</tr>
<?php
}
}
?>
</tbody>
</table>
<details class="mb-2">
<summary class="small" style="cursor:pointer;">Ajouter un événement</summary>
<div class="border rounded p-2 mt-2 bg-light">
<div class="form-row align-items-end">
<div class="form-group col-md-5 mb-2">
<label class="small mb-0" for="pp-eve-acces-v2">Événement</label>
<div id="pick-eve-acces-v2">
<input id="pp-eve-acces-v2" type="text" class="form-control form-control-sm" placeholder="Rechercher…" autocomplete="off">
<input type="hidden" id="pp-eve-acces-v2-id" value="">
<!-- MSIN-4457 — En flux (pas absolute) pour eviter le clip du parent ; hauteur utile. -->
<div id="pp-results-eve-acces-v2" class="list-group d-none mt-1"
style="max-height:min(60vh, 480px);overflow:auto;border:1px solid #ced4da;"></div>
</div>
</div>
<div class="form-group col-md-3 mb-2">
<label class="small mb-0" for="pp-eve-acces-v2-role">Kit</label>
<select id="pp-eve-acces-v2-role" class="form-control form-control-sm">
<option value="">— Choisir —</option>
<?php
if ($arrRoles != null) {
foreach ($arrRoles as $row) {
echo '<option value="' . intval($row['role_id']) . '">'
. htmlspecialchars($row['role_label_fr']) . '</option>';
}
}
?>
</select>
</div>
<div class="form-group col-md-2 mb-2">
<!-- MSIN-4457 — Libelle explicite (ex. J. trop opaque). -->
<label class="small mb-0" for="pp-eve-acces-v2-days" title="Vide = sans expiration">Jours</label>
<input type="number" id="pp-eve-acces-v2-days" class="form-control form-control-sm" min="0" placeholder="∞">
</div>
<div class="form-group col-md-2 mb-2">
<button type="button" class="btn btn-success btn-sm btn-block" id="btn-eve-acces-v2-add">
<i class="fa fa-plus"></i> Ajouter
</button>
</div>
</div>
</div>
</details>
<?php if (count($arrAccesRevoke) > 0 || count($arrExtrasRevoke) > 0) { ?>
<details class="mb-3">
<summary class="text-muted small" style="cursor:pointer;">
Historique — kits et permissions retirés
(<?= count($arrAccesRevoke) + count($arrExtrasRevoke) ?>)
</summary>
<table class="table table-sm table-borderless mt-2 mb-0">
<tbody>
<?php foreach ($arrAccesRevoke as $row) { ?>
<tr class="text-muted">
<td><?= htmlspecialchars($row['eve_nom_fr'] ?? ('#' . $row['eve_id']), ENT_QUOTES, 'UTF-8') ?></td>
<td>Kit : <?= htmlspecialchars($row['role_label_fr'], ENT_QUOTES, 'UTF-8') ?></td>
<td class="text-right">
<a href="index.php?t=<?= $strT ?>&amp;a=mod&amp;id=<?= $intComId ?>&amp;action=reactivateveacces&amp;ea_id=<?= intval($row['ea_id']) ?>"
class="btn btn-sm btn-outline-success">Réactiver</a>
</td>
</tr>
<?php } ?>
<?php foreach ($arrExtrasRevoke as $row) { ?>
<tr class="text-muted">
<td><?= htmlspecialchars($row['eve_nom_fr'] ?? ('#' . $row['eve_id']), ENT_QUOTES, 'UTF-8') ?></td>
<td><?= htmlspecialchars($row['perm_label_fr'], ENT_QUOTES, 'UTF-8') ?></td>
<td class="text-right">
<a href="index.php?t=<?= $strT ?>&amp;a=mod&amp;id=<?= $intComId ?>&amp;action=reactivateveaccesextra&amp;ae_id=<?= intval($row['ae_id']) ?>"
class="btn btn-sm btn-outline-success">Réactiver</a>
</td>
</tr>
<?php } ?>
</tbody>
</table>
</details>
<?php } ?>
<script>
(function($){
function renderEvePick($box, items){
$box.empty();
if (!items || !items.length){
$box.addClass('d-none');
return;
}
items.forEach(function(it){
var id = it.eve_id || it.eveId || it.id;
var label = it.eve_nom_fr || it.nom || ('#' + id);
$('<a href="#" class="list-group-item list-group-item-action"></a>')
.text(label + ' (#' + id + ')')
.data('item', it)
.appendTo($box);
});
$box.removeClass('d-none');
}
function bindEveSearch(inputSel, resultsSel, hiddenSel){
var timer = null, xhr = null;
$(inputSel).on('input', function(){
var q = $(this).val().trim();
var $box = $(resultsSel);
if (q.length < 2) {
$box.addClass('d-none').empty();
return;
}
clearTimeout(timer);
timer = setTimeout(function(){
if (xhr) xhr.abort();
xhr = $.getJSON('ajax_newpromoteur.php', { action: 'search_evenement', q: q }, function(items){
renderEvePick($box, items);
}).fail(function(){ renderEvePick($box, []); });
}, 200);
});
$(resultsSel).on('click', '.list-group-item', function(e){
e.preventDefault();
var item = $(this).data('item') || {};
var id = item.eve_id || item.eveId || item.id;
var label = item.eve_nom_fr || $(this).text();
$(hiddenSel).val(id);
$(inputSel).val(label);
$(resultsSel).addClass('d-none').empty();
});
}
bindEveSearch('#pp-eve-acces-v2', '#pp-results-eve-acces-v2', '#pp-eve-acces-v2-id');
$('#btn-eve-acces-v2-add').on('click', function(){
var eveId = $('#pp-eve-acces-v2-id').val();
var roleId = $('#pp-eve-acces-v2-role').val();
var days = $('#pp-eve-acces-v2-days').val() || 0;
if (!eveId || !roleId) {
alert('Choisir un événement et un kit.');
return;
}
var p = new URLSearchParams(window.location.search);
window.location.href = 'index.php'
+ '?t=' + encodeURIComponent(p.get('t') || '')
+ '&a=mod'
+ '&id=' + encodeURIComponent(p.get('id') || '0')
+ '&action=addeveacces'
+ '&evenement_id=' + encodeURIComponent(eveId)
+ '&role_id=' + encodeURIComponent(roleId)
+ '&expire_days=' + encodeURIComponent(days)
+ '#eve-acces-v2';
});
$('.btn-eve-add-kit').on('click', function(){
var intEveId = $(this).data('eveId');
var roleId = $('#eve-role-' + intEveId).val();
if (!roleId) {
alert('Choisir un kit.');
return;
}
var p = new URLSearchParams(window.location.search);
window.location.href = 'index.php'
+ '?t=' + encodeURIComponent(p.get('t') || '')
+ '&a=mod'
+ '&id=' + encodeURIComponent(p.get('id') || '0')
+ '&action=addeveacces'
+ '&evenement_id=' + encodeURIComponent(intEveId)
+ '&role_id=' + encodeURIComponent(roleId)
+ '&expire_days=0'
+ '#eve-acces-v2';
});
$('.btn-eve-add-extra').on('click', function(){
var intEveId = $(this).data('eveId');
var permKey = $('#eve-extra-' + intEveId).val();
if (!permKey) {
alert('Choisir un droit.');
return;
}
var p = new URLSearchParams(window.location.search);
window.location.href = 'index.php'
+ '?t=' + encodeURIComponent(p.get('t') || '')
+ '&a=mod'
+ '&id=' + encodeURIComponent(p.get('id') || '0')
+ '&action=addeveaccesextra'
+ '&evenement_id=' + encodeURIComponent(intEveId)
+ '&perm_key=' + encodeURIComponent(permKey)
+ '#eve-acces-v2';
});
(function(){
var focusEve = <?= $intFocusEveId ?>;
var focusNom = <?= json_encode($strFocusEveNom, JSON_UNESCAPED_UNICODE) ?>;
if (focusEve <= 0) {
return;
}
var $sel = $('#eve-role-' + focusEve);
if (!$sel.length) {
$sel = $('#eve-extra-' + focusEve);
}
if ($sel.length) {
var $row = $sel.closest('tr');
setTimeout(function(){
$('html, body').animate({ scrollTop: $row.offset().top - 100 }, 300);
$row.addClass('table-info');
setTimeout(function(){ $row.removeClass('table-info'); }, 2500);
}, 100);
return;
}
if (focusNom) {
var $det = $('details').has('#pp-eve-acces-v2').first();
if ($det.length) {
$det.prop('open', true);
$('#pp-eve-acces-v2-id').val(String(focusEve));
$('#pp-eve-acces-v2').val(focusNom + ' (#' + focusEve + ')');
setTimeout(function(){
$('html, body').animate({ scrollTop: $det.offset().top - 100 }, 300);
}, 100);
}
}
})();
})(jQuery);
</script>
<?php
fxSuperadmV2PanelClose();
}
/**
* 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 '<span class="ms1-perm-inspect-badge" title="' . htmlspecialchars($strTitle, ENT_QUOTES, 'UTF-8') . '">'
. '<i class="fa fa-lock" aria-hidden="true"></i> '
. '<code>' . htmlspecialchars($strPermKey, ENT_QUOTES, 'UTF-8') . '</code></span>';
}
/** 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') . '"';
}
/**
* En mode inspecteur : badge apres un controle visible, ou seul si le controle est masque.
*/
function fxEveAccesPermInspectMark($strPermKey, $strHtml = '', $strContext = 'v2')
{
if (!function_exists('fxAdminPermInspectModeActive') || !fxAdminPermInspectModeActive()) {
return $strHtml;
}
$strBadge = fxEveAccesPermInspectBadge($strPermKey, $strContext);
if ($strHtml === '') {
return '<span class="ms1-perm-inspect-slot">' . $strBadge . '</span>';
}
return $strHtml . ' ' . $strBadge;
}