diff --git a/web/admin/groups.php b/web/admin/groups.php
new file mode 100644
index 0000000..0a64b27
--- /dev/null
+++ b/web/admin/groups.php
@@ -0,0 +1,127 @@
+getMessage(); }
+ }
+ }
+
+ if ($action === 'delete') {
+ $group_id = $_POST['group_id'] ?? '';
+ if ($group_id) {
+ try {
+ kc_delete_group($group_id);
+ set_flash('success', 'Groupe supprimé.');
+ header('Location: /admin/groups.php'); exit;
+ } catch (Exception $e) { $errors[] = $e->getMessage(); }
+ }
+ }
+}
+
+$groups = kc_list_groups();
+$services = services_list();
+
+// Indexe les services par groupe requis
+$services_by_group = [];
+foreach ($services as $s) {
+ foreach ($s['groups'] ?? [] as $g) {
+ $services_by_group[$g][] = $s['name'];
+ }
+}
+
+$title = 'Gestion des groupes';
+require __DIR__ . '/../views/layout.php';
+?>
+
+
+
+
+
+
- = htmlspecialchars($e) ?>
+
+
+
+
+
Groupes Keycloak (= count($groups) ?>)
+
+
Aucun groupe trouvé.
+
+
+
+ | Nom | Membres | Services associés | Actions |
+
+
+
+
+ | = htmlspecialchars($g['name']) ?> |
+ = count($members) ?> |
+
+
+
+ = htmlspecialchars($svc) ?>
+
+
+ —
+
+ |
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/web/admin/members.php b/web/admin/members.php
index b47bad3..5bfc1e2 100644
--- a/web/admin/members.php
+++ b/web/admin/members.php
@@ -28,6 +28,7 @@ require __DIR__ . '/../views/layout.php';
Gestion des membres
diff --git a/web/admin/services.php b/web/admin/services.php
index e7828f9..7c5ca84 100644
--- a/web/admin/services.php
+++ b/web/admin/services.php
@@ -2,36 +2,39 @@
require_once __DIR__ . '/../inc/config.php';
require_once __DIR__ . '/../inc/auth.php';
require_once __DIR__ . '/../inc/services.php';
+require_once __DIR__ . '/../inc/keycloak.php';
session_start_safe();
require_admin();
+$kc_groups = kc_list_groups();
+$group_names = array_column($kc_groups, 'name');
+
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$updated = [];
foreach ($_POST as $key => $val) {
if (!str_starts_with($key, 'name_')) continue;
$idx = substr($key, 5);
$updated[] = [
- 'name' => trim($val),
- 'url' => trim($_POST["url_$idx"] ?? ''),
- 'description' => trim($_POST["description_$idx"] ?? ''),
- 'requires_adherent' => isset($_POST["requires_$idx"]),
- 'visible' => isset($_POST["visible_$idx"]),
+ 'name' => trim($val),
+ 'url' => trim($_POST["url_$idx"] ?? ''),
+ 'description' => trim($_POST["description_$idx"] ?? ''),
+ 'groups' => (array)($_POST["groups_$idx"] ?? []),
+ 'visible' => isset($_POST["visible_$idx"]),
];
}
- // Ajout d'un nouveau service si rempli
$new_name = trim($_POST['new_name'] ?? '');
if ($new_name) {
$updated[] = [
- 'name' => $new_name,
- 'url' => trim($_POST['new_url'] ?? ''),
- 'description' => trim($_POST['new_description'] ?? ''),
- 'requires_adherent' => isset($_POST['new_requires']),
- 'visible' => isset($_POST['new_visible']),
+ 'name' => $new_name,
+ 'url' => trim($_POST['new_url'] ?? ''),
+ 'description' => trim($_POST['new_description'] ?? ''),
+ 'groups' => (array)($_POST['new_groups'] ?? []),
+ 'visible' => isset($_POST['new_visible']),
];
}
services_save($updated);
- set_flash('success', 'Configuration des services sauvegardée.');
+ set_flash('success', 'Services sauvegardés.');
header('Location: /admin/services.php');
exit;
}
@@ -46,16 +49,12 @@ require __DIR__ . '/../views/layout.php';
Paramétrage des services
-
- Définissez quels services sont accessibles aux simples inscrits
- et lesquels nécessitent une adhésion validée.
-
-
diff --git a/web/assets/style.css b/web/assets/style.css
index ca565d7..3f7ec2c 100644
--- a/web/assets/style.css
+++ b/web/assets/style.css
@@ -256,6 +256,8 @@ td.center { text-align: center; }
padding: .3rem .5rem; font-size: .85rem;
}
.new-row td { background: #eef1ff; }
+.group-checks { display: flex; flex-direction: column; gap: .2rem; }
+.group-check-label { display: flex; align-items: center; gap: .4rem; font-size: .8rem; cursor: pointer; white-space: nowrap; }
/* ── Helpers ──────────────────────────────────────────────────────── */
.text-success { color: var(--success); }
diff --git a/web/inc/keycloak.php b/web/inc/keycloak.php
index ab229d0..bc958c2 100644
--- a/web/inc/keycloak.php
+++ b/web/inc/keycloak.php
@@ -174,6 +174,29 @@ function kc_list_users(int $max = 200): array {
return $users;
}
+function kc_list_groups(): array {
+ $resp = _kc_request('GET', '/groups?max=200&briefRepresentation=false');
+ if ($resp['status'] !== 200) return [];
+ return json_decode($resp['body'], true) ?? [];
+}
+
+function kc_create_group(string $name): void {
+ $resp = _kc_request('POST', '/groups', ['name' => $name]);
+ if ($resp['status'] === 409) throw new RuntimeException("Le groupe « $name » existe déjà.");
+ if ($resp['status'] !== 201) throw new RuntimeException("Erreur création groupe ({$resp['status']})");
+}
+
+function kc_delete_group(string $group_id): void {
+ $resp = _kc_request('DELETE', "/groups/$group_id");
+ if ($resp['status'] >= 300) throw new RuntimeException("Erreur suppression groupe ({$resp['status']})");
+}
+
+function kc_group_members(string $group_id, int $max = 200): array {
+ $resp = _kc_request('GET', "/groups/$group_id/members?max=$max");
+ if ($resp['status'] !== 200) return [];
+ return json_decode($resp['body'], true) ?? [];
+}
+
function _kc_group_id(string $group_name): string {
$resp = _kc_request('GET', '/groups?search=' . urlencode($group_name));
$groups = json_decode($resp['body'], true) ?? [];
diff --git a/web/inc/services.php b/web/inc/services.php
index 8604554..67710d3 100644
--- a/web/inc/services.php
+++ b/web/inc/services.php
@@ -2,23 +2,38 @@
require_once __DIR__ . '/config.php';
const DEFAULT_SERVICES = [
- ['name' => 'Wiki', 'url' => 'https://wiki.alpinux.org', 'description' => 'Documentation et guides', 'requires_adherent' => false, 'visible' => true],
- ['name' => 'Gitea', 'url' => 'https://gitea.alpinux.org', 'description' => 'Forge de code', 'requires_adherent' => false, 'visible' => true],
- ['name' => 'Quiz interactifs','url' => 'https://dynamic.alpinux.org', 'description' => 'Jeux et quiz', 'requires_adherent' => false, 'visible' => true],
- ['name' => 'Install Party', 'url' => 'https://installparty.alpinux.org', 'description' => 'Événements et ateliers', 'requires_adherent' => false, 'visible' => true],
- ['name' => 'Nextcloud', 'url' => 'https://cloud.alpinux.org', 'description' => 'Stockage et collaboration', 'requires_adherent' => true, 'visible' => true],
- ['name' => 'Dolibarr', 'url' => 'https://dolibarr.alpinux.org', 'description' => 'Gestion de l\'association', 'requires_adherent' => true, 'visible' => true],
+ ['name' => 'Wiki', 'url' => 'https://wiki.alpinux.org', 'description' => 'Documentation et guides', 'groups' => [], 'visible' => true],
+ ['name' => 'Gitea', 'url' => 'https://gitea.alpinux.org', 'description' => 'Forge de code', 'groups' => [], 'visible' => true],
+ ['name' => 'Quiz interactifs','url' => 'https://dynamic.alpinux.org', 'description' => 'Jeux et quiz', 'groups' => [], 'visible' => true],
+ ['name' => 'Install Party', 'url' => 'https://installparty.alpinux.org', 'description' => 'Événements et ateliers', 'groups' => [], 'visible' => true],
+ ['name' => 'Nextcloud', 'url' => 'https://cloud.alpinux.org', 'description' => 'Stockage et collaboration', 'groups' => ['adherents'], 'visible' => true],
+ ['name' => 'Dolibarr', 'url' => 'https://dolibarr.alpinux.org', 'description' => 'Gestion de l\'association', 'groups' => ['adherents'], 'visible' => true],
];
function services_list(): array {
$file = SERVICES_FILE;
if (is_file($file)) {
$data = json_decode(file_get_contents($file), true);
- if (is_array($data)) return $data;
+ if (is_array($data)) return array_map('_service_normalize', $data);
}
return DEFAULT_SERVICES;
}
+function _service_normalize(array $s): array {
+ // Migre l'ancien champ requires_adherent vers groups
+ if (!array_key_exists('groups', $s)) {
+ $s['groups'] = ($s['requires_adherent'] ?? false) ? [ADHERENT_GROUP] : [];
+ }
+ unset($s['requires_adherent']);
+ return $s;
+}
+
+function service_accessible(array $service, array $user_groups, bool $is_admin): bool {
+ if ($is_admin) return true;
+ $required = $service['groups'] ?? [];
+ return empty($required) || (bool) array_intersect($required, $user_groups);
+}
+
function services_save(array $services): void {
$dir = dirname(SERVICES_FILE);
if (!is_dir($dir)) mkdir($dir, 0755, true);
diff --git a/web/index.php b/web/index.php
index a1b5cf6..e063a59 100644
--- a/web/index.php
+++ b/web/index.php
@@ -9,10 +9,9 @@ $user = current_user();
$title = 'Portail Alpinux';
$services = services_list();
-$is_adherent = $user && (
- $user['is_adherent'] ||
- ($user['is_admin'] ?? false)
-);
+$is_admin = $user && ($user['is_admin'] ?? false);
+$is_adherent = $user && ($user['is_adherent'] || $is_admin);
+$user_groups = $user['groups'] ?? [];
require __DIR__ . '/views/layout.php';
?>
@@ -69,7 +68,7 @@ require __DIR__ . '/views/layout.php';
Nos services
+ $can_access = service_accessible($s, $user_groups, $is_admin); ?>