'', 'url' => '']; } if (array_key_exists($key, $cache)) { return $cache[$key]; } $pdo = dbPdo(); if ($pdo) { try { $st = $pdo->prepare('SELECT display_name, profile_url FROM user_profiles WHERE email = :e'); $st->execute([':e' => $key]); $row = $st->fetch(PDO::FETCH_ASSOC); if ($row) { $cache[$key] = [ 'name' => ($row['display_name'] !== '') ? $row['display_name'] : explode('@', $key)[0], 'url' => $row['profile_url'] ?? '', ]; return $cache[$key]; } } catch (\Throwable) { } } $cache[$key] = ['name' => explode('@', $key)[0], 'url' => '']; return $cache[$key]; } function dbPdo(): ?PDO { static $pdo = null; static $failed = false; if ($failed) { return null; } if ($pdo !== null) { return $pdo; } $dsn = $_ENV['DB_DSN'] ?? (getenv('DB_DSN') ?: ''); $user = $_ENV['DB_USER'] ?? (getenv('DB_USER') ?: ''); $pass = $_ENV['DB_PASS'] ?? (getenv('DB_PASS') ?: ''); if (!$dsn) { $failed = true; return null; } try { $pdo = new PDO($dsn, $user ?: null, $pass ?: null, [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]); } catch (\Throwable) { $failed = true; return null; } return $pdo; } function currentUserRoles(): array { if (!isLoggedIn()) { return []; } if (isset($_SESSION['user_roles'])) { return $_SESSION['user_roles']; } $pdo = dbPdo(); if (!$pdo) { $_SESSION['user_roles'] = []; return []; } try { $st = $pdo->prepare( 'SELECT r.name FROM roles r JOIN user_roles ur ON ur.role_id = r.id WHERE ur.user_email = :e' ); $st->execute([':e' => strtolower(currentUserEmail() ?? '')]); $_SESSION['user_roles'] = $st->fetchAll(PDO::FETCH_COLUMN) ?: []; } catch (\Throwable) { $_SESSION['user_roles'] = []; } return $_SESSION['user_roles']; } function hasRole(string $role): bool { return in_array($role, currentUserRoles(), true); } // Capacités connues — clé => label affiché dans l'admin const KNOWN_CAPABILITIES = [ 'propose_articles' => 'Proposer des articles', 'validate_articles_all' => 'Valider des articles', 'validate_articles_own' => 'Valider ses articles uniquement', 'publish_articles_all' => 'Publier des articles', 'publish_articles_own' => 'Publier ses articles uniquement', 'edit_articles_all' => 'Modifier des articles', 'edit_articles_own' => 'Modifier ses articles uniquement', 'rate_articles' => 'Noter des articles', 'view_previews' => 'Lire des avant-premières', 'view_drafts_all' => 'Voir tous les brouillons', 'view_drafts_own' => 'Voir ses brouillons', 'view_sources_all' => 'Voir les sources (tous les articles)', 'view_sources_own' => 'Voir les sources de ses articles', ]; // Groupes pour l'interface d'administration const CAPABILITY_GROUPS = [ 'Articles' => [ 'propose_articles', 'validate_articles_all', 'validate_articles_own', 'publish_articles_all', 'publish_articles_own', 'edit_articles_all', 'edit_articles_own', ], 'Accès & lecture' => [ 'rate_articles', 'view_previews', 'view_drafts_all', 'view_drafts_own', 'view_sources_all', 'view_sources_own', ], ]; function currentUserCapabilities(): array { if (!isLoggedIn()) { return []; } if (isset($_SESSION['user_capabilities'])) { return $_SESSION['user_capabilities']; } $pdo = dbPdo(); if (!$pdo) { $_SESSION['user_capabilities'] = []; return []; } try { $st = $pdo->prepare( 'SELECT DISTINCT rc.capability FROM role_capabilities rc JOIN user_roles ur ON ur.role_id = rc.role_id WHERE ur.user_email = :e' ); $st->execute([':e' => strtolower(currentUserEmail() ?? '')]); $_SESSION['user_capabilities'] = $st->fetchAll(PDO::FETCH_COLUMN) ?: []; } catch (\Throwable) { $_SESSION['user_capabilities'] = []; } return $_SESSION['user_capabilities']; } function hasCapability(string $cap): bool { if (isAdmin()) { return true; } return in_array($cap, currentUserCapabilities(), true); } function canDoOnArticle(string $baseCap, array $article): bool { if (isAdmin()) { return true; } if (hasCapability($baseCap . '_all')) { return true; } if (hasCapability($baseCap . '_own')) { $owner = strtolower($article['author'] ?? ''); return $owner !== '' && $owner === strtolower(currentUserEmail() ?? ''); } return false; } function isAdmin(): bool { $email = currentUserEmail(); if (!$email) { return false; } // Fallback bootstrap : var d'env $rawAdmin = $_ENV['ADMIN_EMAIL'] ?? (getenv('ADMIN_EMAIL') ?: ''); $allowed = array_filter(array_map('trim', explode(',', (string)$rawAdmin))); if (in_array(strtolower($email), array_map('strtolower', $allowed), true)) { return true; } return hasRole('admin'); } function ssoLogoutUrl(): string { $issuer = rtrim((string)($_ENV['OIDC_ISSUER'] ?? (getenv('OIDC_ISSUER') ?: '')), '/'); $clientId = (string)($_ENV['OIDC_CLIENT_ID'] ?? (getenv('OIDC_CLIENT_ID') ?: '')); $baseUrl = rtrim((string)($_ENV['APP_URL'] ?? (getenv('APP_URL') ?: '/')), '/'); $params = [ 'client_id' => $clientId, 'post_logout_redirect_uri' => $baseUrl . '/', ]; if (!empty($_SESSION['oidc']['id_token'])) { $params['id_token_hint'] = $_SESSION['oidc']['id_token']; } if (!$issuer) { return $baseUrl . '/'; } return $issuer . '/protocol/openid-connect/logout?' . http_build_query($params); }