'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 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); file_put_contents(SERVICES_FILE, json_encode($services, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); }