diff --git a/php/inc_fx_eve_acces.php b/php/inc_fx_eve_acces.php
new file mode 100644
index 0000000..8614d55
--- /dev/null
+++ b/php/inc_fx_eve_acces.php
@@ -0,0 +1,441 @@
+fxGetResults("SHOW TABLES LIKE 'inscriptions_eve_acces'");
+ $blnEnabled = ($tab != null && count($tab) > 0);
+
+ return $blnEnabled;
+}
+
+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);
+}
+
+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 v_eve_acces_actif WHERE com_id = " . intval($intComId);
+ $intNb = $objDatabase->fxGetVar($sql);
+
+ return ($intNb != null && intval($intNb) > 0);
+}
+
+function fxEveAccesGetEventIds($intComId)
+{
+ global $objDatabase;
+
+ if (!fxEveAccesIsEnabled()) {
+ return array();
+ }
+
+ $sql = "SELECT eve_id FROM v_eve_acces_actif 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;
+}
+
+function fxEveAccesHasPermission($intComId, $intEveId, $strPermKey)
+{
+ global $objDatabase;
+
+ if (!fxEveAccesIsEnabled()) {
+ return false;
+ }
+
+ $sql = "SELECT COUNT(*) FROM v_eve_acces_permissions
+ 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 fxEveAccesGrant($intComId, $intEveId, $intRoleId, $intExpireDays, $intGrantedBy, $strNote = '')
+{
+ 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);
+
+ 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, 'actif', $strExpires, $intExpireDaysStore, $strGrantedBy, '$strNote')
+ ON DUPLICATE KEY UPDATE
+ role_id = VALUES(role_id),
+ ea_statut = 'actif',
+ 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 LIMIT 1"));
+
+ fxEveAccesWriteLog($intEaId, $intComId, $intEveId, $intRoleId, 'create', 'Grant / mise a jour acces v2', $intGrantedBy);
+
+ return array('state' => 'success', 'ea_id' => $intEaId);
+}
+
+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 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 v_eve_acces_permissions
+ WHERE com_id = " . intval($intComId) . "
+ AND eve_id = " . intval($intEveId) . "
+ ORDER BY perm_group, perm_key";
+
+ return $objDatabase->fxGetResults($sql);
+}
+
+function fxEveAccesShowCompteForm($intComId)
+{
+ global $objDatabase;
+
+ if (!fxEveAccesIsEnabled()) {
+ echo '
Tables acces v2 non installees. Executer les SQL MSIN-eve-acces-v2-phase1.
';
+ return;
+ }
+
+ $arrAcces = fxEveAccesListByComId($intComId);
+ $arrRoles = fxEveAccesGetRoles(true);
+ $strT = urlencode($_GET['t'] ?? '');
+ $intComId = intval($intComId);
+ ?>
+ Acces v2 (pilote mobile)
+
+ Systeme parallele au legacy com_eve_promoteur.
+ Seuls les comptes listes ici utilisent les permissions v2 pour l'API mobile.
+
+
+
+
+
+
+
+ | Evenement |
+ Role |
+ Statut |
+ Expire |
+ Cree |
+ |
+
+
+
+ Aucun acces v2 pour ce compte. | ';
+ } else {
+ foreach ($arrAcces as $row) {
+ $blnActif = ($row['ea_statut'] === 'actif'
+ && (empty($row['ea_expires_at']) || strtotime($row['ea_expires_at']) > time()));
+ $strStatut = $blnActif ? 'actif' : '' . htmlspecialchars($row['ea_statut']) . '';
+ $strExpire = !empty($row['ea_expires_at']) ? htmlspecialchars($row['ea_expires_at']) : '—';
+ ?>
+
+ |
+ = htmlspecialchars($row['eve_nom_fr'] ?? ('eve_id ' . $row['eve_id'])) ?>
+ (#= intval($row['eve_id']) ?>)
+ |
+ = htmlspecialchars($row['role_label_fr']) ?> (= htmlspecialchars($row['role_code']) ?>) |
+ = $strStatut ?> |
+ = $strExpire ?> |
+ = htmlspecialchars($row['ea_created_at']) ?> |
+
+
+
+
+
+
+ |
+
+ 0) {
+ $arrKeys = array();
+ foreach ($arrPerms as $p) {
+ $arrKeys[] = $p['perm_key'];
+ }
+ echo '| Permissions : ' . htmlspecialchars(implode(', ', $arrKeys)) . ' |
';
+ }
+ }
+ }
+ }
+ ?>
+
+
+
+
+
diff --git a/v3_ci4/app/Controllers/Api/V1/Events.php b/v3_ci4/app/Controllers/Api/V1/Events.php
index 69149b5..8f6943b 100644
--- a/v3_ci4/app/Controllers/Api/V1/Events.php
+++ b/v3_ci4/app/Controllers/Api/V1/Events.php
@@ -2,34 +2,33 @@
namespace App\Controllers\Api\V1;
+use App\Libraries\EventAccess;
use CodeIgniter\RESTful\ResourceController;
class Events extends ResourceController
{
protected $helpers = ['text'];
+ protected function eventAccess(): EventAccess
+ {
+ return new EventAccess();
+ }
public function index()
{
$db = \Config\Database::connect();
+ $comId = (int) $this->request->com_id;
+ $access = $this->eventAccess();
- $comId = $this->request->com_id;
+ $eventIds = $access->getAuthorizedEventIds($comId);
- // récupérer la liste d'événements du promoteur
- $compte = $db->table('inscriptions_comptes')
- ->select('com_eve_promoteur')
- ->where('com_id', $comId)
- ->get()
- ->getRow();
-
- if (!$compte) {
+ if (empty($eventIds)) {
return $this->respond([
- 'events' => []
+ 'events' => [],
+ 'access_mode' => $access->hasV2Access($comId) ? 'v2' : 'legacy',
]);
}
- $eventIds = explode(',', $compte->com_eve_promoteur);
-
$startDate = $this->request->getGet('start_date');
$endDate = $this->request->getGet('end_date');
$updatedSince = $this->request->getGet('updated_since');
@@ -50,12 +49,9 @@ class Events extends ResourceController
$builder->where('last_update >', $updatedSince);
}
- $events = $builder
- ->get()
- ->getResultArray();
+ $events = $builder->get()->getResultArray();
foreach ($events as &$event) {
-
$categories = $db->table('api_v1_categories')
->where('eve_id', $event['eve_id'])
->get()
@@ -64,37 +60,35 @@ class Events extends ResourceController
$event['categories'] = $categories;
}
+ unset($event);
+
+ if ($access->hasV2Access($comId)) {
+ $events = array_values(array_filter($events, function ($e) use ($access, $comId) {
+ return $access->hasPermission($comId, (int) $e['eve_id'], 'events.list');
+ }));
+ }
+
$events = clean_text_fields($events);
return $this->respond([
'events' => $events,
- 'total' => count($events)
+ 'total' => count($events),
+ 'access_mode' => $access->hasV2Access($comId) ? 'v2' : 'legacy',
]);
}
+
public function show($id = null)
{
$db = \Config\Database::connect();
+ $comId = (int) $this->request->com_id;
+ $access = $this->eventAccess();
+ $id = (string) $id;
- $comId = $this->request->com_id;
-
- // récupérer les événements autorisés
- $compte = $db->table('inscriptions_comptes')
- ->select('com_eve_promoteur')
- ->where('com_id', $comId)
- ->get()
- ->getRow();
-
- if (!$compte) {
- return $this->respond(['error' => 'account_not_found'], 404);
- }
-
- $eventIds = explode(',', $compte->com_eve_promoteur);
-
- // sécurité
- if (!in_array($id, $eventIds)) {
+ if (!$access->assertEventPermission($comId, (int) $id, 'events.view')) {
return $this->respond([
'error' => 'event_not_allowed',
- 'requested_event' => $id
+ 'requested_event' => $id,
+ 'access_mode' => $access->hasV2Access($comId) ? 'v2' : 'legacy',
], 403);
}
@@ -111,48 +105,46 @@ class Events extends ResourceController
$event['categories'] = $categories;
$event = clean_text_fields($event);
+
return $this->respond([
- 'event' => $event
+ 'event' => $event,
+ 'access_mode' => $access->hasV2Access($comId) ? 'v2' : 'legacy',
]);
}
+
public function categories($event_id)
{
$db = \Config\Database::connect();
+ $comId = (int) $this->request->com_id;
+ $access = $this->eventAccess();
+
+ if (!$access->assertEventPermission($comId, (int) $event_id, 'events.view')) {
+ return $this->respond(['error' => 'event_not_allowed'], 403);
+ }
$rows = $db->table('api_v1_categories')
->where('eve_id', $event_id)
->get()
->getResultArray();
$rows = clean_text_fields($rows);
+
return $this->response->setJSON([
'event_id' => (int)$event_id,
- 'categories' => $rows
+ 'categories' => $rows,
]);
}
public function registrations($event_id)
{
$db = \Config\Database::connect();
+ $comId = (int) $this->request->com_id;
+ $access = $this->eventAccess();
- $comId = $this->request->com_id;
-
- // vérifier que l'événement appartient au promoteur
- $compte = $db->table('inscriptions_comptes')
- ->select('com_eve_promoteur')
- ->where('com_id', $comId)
- ->get()
- ->getRow();
-
- if (!$compte) {
- return $this->respond(['error' => 'account_not_found'], 404);
- }
-
- $eventIds = explode(',', $compte->com_eve_promoteur);
-
- if (!in_array($event_id, $eventIds)) {
+ if (!$access->assertEventPermission($comId, (int) $event_id, 'registrations.view')) {
return $this->respond([
'error' => 'event_not_allowed',
- 'requested_event' => $event_id
+ 'requested_event' => $event_id,
+ 'access_mode' => $access->hasV2Access($comId) ? 'v2' : 'legacy',
], 403);
}
@@ -178,16 +170,12 @@ class Events extends ResourceController
$registrations = [];
foreach ($rows as $row) {
-
- // clé unique pour 1 participant inscrit à 1 épreuve
$key = $row['pec_id'].'_'.$row['par_id'];
if (!isset($registrations[$key])) {
-
$registrations[$key] = $row;
$registrations[$key]['custom_questions'] = [];
- // enlever les champs techniques des questions
unset(
$registrations[$key]['que_id'],
$registrations[$key]['que_question_fr'],
@@ -198,15 +186,13 @@ class Events extends ResourceController
);
}
- // ajouter la réponse dans custom_questions
if (!empty($row['que_id'])) {
-
$registrations[$key]['custom_questions'][] = [
'que_id' => $row['que_id'],
'que_question_fr' => $row['que_question_fr'],
'que_question_en' => $row['que_question_en'],
'que_choix_fr' => $row['que_choix_fr'],
- 'que_choix_en' => $row['que_choix_en']
+ 'que_choix_en' => $row['que_choix_en'],
];
}
}
@@ -215,7 +201,8 @@ class Events extends ResourceController
return $this->respond([
'registrations' => $registrations,
- 'total' => count($registrations)
+ 'total' => count($registrations),
+ 'access_mode' => $access->hasV2Access($comId) ? 'v2' : 'legacy',
]);
}
-}
\ No newline at end of file
+}
diff --git a/v3_ci4/app/Libraries/EventAccess.php b/v3_ci4/app/Libraries/EventAccess.php
new file mode 100644
index 0000000..e66ee3b
--- /dev/null
+++ b/v3_ci4/app/Libraries/EventAccess.php
@@ -0,0 +1,135 @@
+db = Database::connect();
+ }
+
+ public function isEnabled(): bool
+ {
+ static $enabled = null;
+
+ if ($enabled !== null) {
+ return $enabled;
+ }
+
+ try {
+ $row = $this->db->query("SHOW TABLES LIKE 'inscriptions_eve_acces'")->getRow();
+ $enabled = ($row !== null);
+ } catch (\Throwable $e) {
+ $enabled = false;
+ }
+
+ return $enabled;
+ }
+
+ public function hasV2Access(int $comId): bool
+ {
+ if (!$this->isEnabled()) {
+ return false;
+ }
+
+ $count = $this->db->table('v_eve_acces_actif')
+ ->where('com_id', $comId)
+ ->countAllResults();
+
+ return $count > 0;
+ }
+
+ public function getEventIds(int $comId): array
+ {
+ if (!$this->isEnabled()) {
+ return [];
+ }
+
+ $rows = $this->db->table('v_eve_acces_actif')
+ ->select('eve_id')
+ ->where('com_id', $comId)
+ ->get()
+ ->getResultArray();
+
+ return array_map(static fn($r) => (string) $r['eve_id'], $rows);
+ }
+
+ public function hasPermission(int $comId, int $eveId, string $permKey): bool
+ {
+ if (!$this->isEnabled()) {
+ return false;
+ }
+
+ $count = $this->db->table('v_eve_acces_permissions')
+ ->where('com_id', $comId)
+ ->where('eve_id', $eveId)
+ ->where('perm_key', $permKey)
+ ->countAllResults();
+
+ return $count > 0;
+ }
+
+ public function canAccessEvent(int $comId, int $eveId): bool
+ {
+ if (!$this->isEnabled()) {
+ return false;
+ }
+
+ $count = $this->db->table('v_eve_acces_actif')
+ ->where('com_id', $comId)
+ ->where('eve_id', $eveId)
+ ->countAllResults();
+
+ return $count > 0;
+ }
+
+ /**
+ * Legacy : com_eve_promoteur CSV
+ */
+ public function getLegacyEventIds(int $comId): array
+ {
+ $compte = $this->db->table('inscriptions_comptes')
+ ->select('com_eve_promoteur')
+ ->where('com_id', $comId)
+ ->get()
+ ->getRow();
+
+ if (!$compte || empty(trim($compte->com_eve_promoteur ?? ''))) {
+ return [];
+ }
+
+ $ids = array_filter(array_map('trim', explode(',', $compte->com_eve_promoteur)));
+
+ return array_values($ids);
+ }
+
+ public function getAuthorizedEventIds(int $comId): array
+ {
+ if ($this->hasV2Access($comId)) {
+ return $this->getEventIds($comId);
+ }
+
+ return $this->getLegacyEventIds($comId);
+ }
+
+ public function assertEventPermission(int $comId, int $eveId, ?string $permKey = null): bool
+ {
+ if ($this->hasV2Access($comId)) {
+ if ($permKey !== null) {
+ return $this->hasPermission($comId, $eveId, $permKey);
+ }
+
+ return $this->canAccessEvent($comId, $eveId);
+ }
+
+ return in_array((string) $eveId, $this->getLegacyEventIds($comId), true);
+ }
+}