diff --git a/assets/pasted-20260415-121622-e57fee84.png b/assets/pasted-20260415-121622-e57fee84.png new file mode 100644 index 0000000..994d2f8 Binary files /dev/null and b/assets/pasted-20260415-121622-e57fee84.png differ diff --git a/css/styles.css b/css/styles.css index c04f1fb..c0e0c36 100644 --- a/css/styles.css +++ b/css/styles.css @@ -161,8 +161,7 @@ a:hover { background-size: auto; background-color: rgb(0 0 0 / 50%); z-index: 100; - width: min(300px, calc(100vw - 50px)); - max-width: calc(100vw - 50px); + width: 300px; display: flex; /* Active le mode Flexbox */ flex-direction: column; /* Aligne les liens les uns sous les autres */ align-items: center; /* Centre verticalement */ @@ -170,7 +169,7 @@ a:hover { justify-content: center; border: solid 3px rgb(155 145 60 / 25%); border-radius: 10px; - padding: 5px 12px; + padding: 5px 0px 5px 0px; text-align: center; } @@ -184,16 +183,13 @@ a:hover { background-size: auto; background-color: rgb(0 0 0 / 50%); z-index: 100; - width: min(300px, calc(100vw - 50px)); - max-width: calc(100vw - 50px); - min-height: 35px; - height: auto; + width: 300px; + height: 35px; display: flex; /* Active le mode Flexbox */ align-items: center; /* Centre verticalement */ justify-content: center; border: solid 3px rgb(155 145 60 / 25%); border-radius: 10px; - padding: 5px 12px; text-align: center; } @@ -206,9 +202,8 @@ a:hover { background-position: center center; background-size: auto; z-index: 3; - width: min(1050px, calc(100vw - 40px)); - min-height: 80px; - height: auto; + width: 1050px; + height: 80px; text-align: center; } @@ -217,7 +212,6 @@ a:hover { justify-content: center; /* Centre les items horizontalement */ align-items: center; /* Centre verticalement */ gap: 10px; /* Espace entre les divs (modifiable) */ - flex-wrap: wrap; } .center-div-menu .menu-item { @@ -380,7 +374,7 @@ a:hover { } .center-div-menu { - width: min(900px, calc(100vw - 48px)); + width: min(1050px, calc(100vw - 40px)); } } diff --git a/database/full.sql b/database/full.sql index 8b61be4..6dc7972 100644 --- a/database/full.sql +++ b/database/full.sql @@ -18714,3 +18714,14 @@ INSERT INTO `tbl_scitemcustomstat` (`cl_scitemcustomstat_id`,`cl_scitemcustomsta ('6','3','6','','0.50','2026-04-08 22:01:49'); SET FOREIGN_KEY_CHECKS = 1; + + +CREATE TABLE IF NOT EXISTS tbl_page_access ( + cl_page_access_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + cl_page_key VARCHAR(190) NOT NULL UNIQUE, + cl_page_file VARCHAR(190) NOT NULL UNIQUE, + cl_page_label VARCHAR(190) NOT NULL, + cl_allow_admin TINYINT(1) NOT NULL DEFAULT 1, + cl_allow_member TINYINT(1) NOT NULL DEFAULT 0, + cl_updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/database/schema.sql b/database/schema.sql index a15637a..fb60b89 100644 --- a/database/schema.sql +++ b/database/schema.sql @@ -193,3 +193,14 @@ CREATE TABLE `tbl_scwebhooks` ( /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + + +CREATE TABLE IF NOT EXISTS tbl_page_access ( + cl_page_access_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + cl_page_key VARCHAR(190) NOT NULL UNIQUE, + cl_page_file VARCHAR(190) NOT NULL UNIQUE, + cl_page_label VARCHAR(190) NOT NULL, + cl_allow_admin TINYINT(1) NOT NULL DEFAULT 1, + cl_allow_member TINYINT(1) NOT NULL DEFAULT 0, + cl_updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/db/auth.php b/db/auth.php index b8ebf01..ab1d5bd 100644 --- a/db/auth.php +++ b/db/auth.php @@ -51,6 +51,18 @@ function auth_bootstrap(): void ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci" ); + $pdo->exec( + "CREATE TABLE IF NOT EXISTS tbl_page_access ( + cl_page_access_id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + cl_page_key VARCHAR(190) NOT NULL UNIQUE, + cl_page_file VARCHAR(190) NOT NULL UNIQUE, + cl_page_label VARCHAR(190) NOT NULL, + cl_allow_admin TINYINT(1) NOT NULL DEFAULT 1, + cl_allow_member TINYINT(1) NOT NULL DEFAULT 0, + cl_updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci" + ); + $sql_count_admin = "SELECT COUNT(*) FROM tbl_auth WHERE cl_auth_right = 'admin'"; $stmt_count_admin = $pdo->query($sql_count_admin); $cl_auth_admin_total = (int) $stmt_count_admin->fetchColumn(); @@ -139,6 +151,20 @@ function auth_is_admin(): bool return isset($_SESSION['role']) && $_SESSION['role'] === 'admin'; } +function auth_current_user(): string +{ + auth_start_session(); + + return isset($_SESSION['user']) ? (string) $_SESSION['user'] : ''; +} + +function auth_current_role(): string +{ + auth_start_session(); + + return isset($_SESSION['role']) ? (string) $_SESSION['role'] : ''; +} + function auth_flash_set(string $flash_type, string $flash_message): void { auth_start_session(); @@ -160,4 +186,264 @@ function auth_flash_get(): ?array unset($_SESSION['flash']); return $flash; -} \ No newline at end of file +} + +function auth_page_basename(string $page_file): string +{ + $basename = basename(trim($page_file)); + + if ($basename === '' || preg_match('/^[a-zA-Z0-9._-]+$/', $basename) !== 1) { + throw new InvalidArgumentException('Nom de page invalide.'); + } + + return $basename; +} + +function auth_page_default_member_access(string $page_file): int +{ + static $member_defaults = [ + 'scnotification.php' => 1, + 'scpreset.php' => 1, + ]; + + $page_file = auth_page_basename($page_file); + + return $member_defaults[$page_file] ?? 0; +} + +function auth_page_access_defaults(string $page_file, string $page_label = ''): array +{ + $normalized_page_file = auth_page_basename($page_file); + $normalized_page_label = trim($page_label) !== '' ? trim($page_label) : $normalized_page_file; + + return [ + 'cl_page_key' => pathinfo($normalized_page_file, PATHINFO_FILENAME), + 'cl_page_file' => $normalized_page_file, + 'cl_page_label' => $normalized_page_label, + 'cl_allow_admin' => 1, + 'cl_allow_member' => auth_page_default_member_access($normalized_page_file), + ]; +} + +function auth_page_access_ensure(string $page_file, string $page_label = ''): array +{ + auth_bootstrap(); + + $defaults = auth_page_access_defaults($page_file, $page_label); + $pdo = db(); + + $stmt = $pdo->prepare( + 'SELECT cl_page_access_id, cl_page_key, cl_page_file, cl_page_label, cl_allow_admin, cl_allow_member + FROM tbl_page_access + WHERE cl_page_file = :cl_page_file + LIMIT 1' + ); + $stmt->execute([ + 'cl_page_file' => $defaults['cl_page_file'], + ]); + $row = $stmt->fetch(); + + if (!$row) { + $stmt_insert = $pdo->prepare( + 'INSERT INTO tbl_page_access (cl_page_key, cl_page_file, cl_page_label, cl_allow_admin, cl_allow_member) + VALUES (:cl_page_key, :cl_page_file, :cl_page_label, :cl_allow_admin, :cl_allow_member)' + ); + $stmt_insert->execute($defaults); + + $stmt->execute([ + 'cl_page_file' => $defaults['cl_page_file'], + ]); + $row = $stmt->fetch(); + } elseif ($defaults['cl_page_label'] !== '' && (string) $row['cl_page_label'] !== $defaults['cl_page_label']) { + $stmt_update_label = $pdo->prepare( + 'UPDATE tbl_page_access SET cl_page_label = :cl_page_label WHERE cl_page_file = :cl_page_file' + ); + $stmt_update_label->execute([ + 'cl_page_label' => $defaults['cl_page_label'], + 'cl_page_file' => $defaults['cl_page_file'], + ]); + $row['cl_page_label'] = $defaults['cl_page_label']; + } + + if (!$row) { + throw new RuntimeException('Impossible d\'initialiser la configuration d\'accès de la page.'); + } + + $row['cl_allow_admin'] = (int) ($row['cl_allow_admin'] ?? 1); + $row['cl_allow_member'] = (int) ($row['cl_allow_member'] ?? 0); + + return $row; +} + +function auth_user_can_access_page(string $page_file, string $page_label = ''): bool +{ + auth_start_session(); + auth_bootstrap(); + + if (!auth_is_logged_in()) { + return false; + } + + if (auth_is_admin()) { + return true; + } + + if (auth_current_role() !== 'member') { + return false; + } + + $row = auth_page_access_ensure($page_file, $page_label); + + return (int) $row['cl_allow_member'] === 1; +} + +function auth_require_page_access(string $page_file, string $page_label = ''): void +{ + if (!auth_is_logged_in()) { + header('Location: index.php'); + exit; + } + + if (auth_is_admin()) { + auth_page_access_ensure($page_file, $page_label); + return; + } + + if (auth_user_can_access_page($page_file, $page_label)) { + return; + } + + auth_flash_set('error', 'Accès refusé : cette page n\'est pas ouverte aux membres.'); + header('Location: index.php'); + exit; +} + +function auth_handle_page_access_post(string $page_file, string $page_label = ''): void +{ + auth_start_session(); + auth_bootstrap(); + + if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') { + return; + } + + if (!isset($_POST['page_access_action'])) { + return; + } + + $redirect_target = auth_page_basename($page_file); + + if (!auth_is_admin()) { + auth_flash_set('error', 'Seul un administrateur peut modifier les accès de page.'); + header('Location: index.php'); + exit; + } + + $csrf_token = isset($_POST['csrf_token']) ? (string) $_POST['csrf_token'] : null; + if (!auth_validate_csrf($csrf_token)) { + auth_flash_set('error', 'Jeton CSRF invalide.'); + header('Location: ' . $redirect_target); + exit; + } + + $row = auth_page_access_ensure($page_file, $page_label); + $cl_allow_member = isset($_POST['cl_allow_member']) ? 1 : 0; + + $stmt = db()->prepare( + 'UPDATE tbl_page_access + SET cl_page_label = :cl_page_label, + cl_allow_admin = 1, + cl_allow_member = :cl_allow_member + WHERE cl_page_file = :cl_page_file' + ); + $stmt->execute([ + 'cl_page_label' => $row['cl_page_label'], + 'cl_allow_member' => $cl_allow_member, + 'cl_page_file' => $row['cl_page_file'], + ]); + + auth_flash_set('success', 'Accès mis à jour pour ' . $row['cl_page_label'] . '.'); + header('Location: ' . $redirect_target); + exit; +} + +function auth_render_page_access_widget(string $page_file, string $page_label = ''): string +{ + if (!auth_is_admin()) { + return ''; + } + + $row = auth_page_access_ensure($page_file, $page_label); + $csrf_token = auth_csrf_token(); + $action = htmlspecialchars($row['cl_page_file'], ENT_QUOTES, 'UTF-8'); + $label = htmlspecialchars((string) $row['cl_page_label'], ENT_QUOTES, 'UTF-8'); + $csrf = htmlspecialchars($csrf_token, ENT_QUOTES, 'UTF-8'); + $member_checked = (int) $row['cl_allow_member'] === 1 ? 'checked' : ''; + + return << +
+ +HTML; +} + +function auth_navigation_items(): array +{ + return [ + ['file' => 'admin.php', 'label' => 'Utilisateurs', 'admin_only' => true], + ['file' => 'scwebhook.php', 'label' => 'WEBHOOK'], + ['file' => 'scnotification.php', 'label' => 'NOTIF DISCORD'], + ['file' => 'scitems.php', 'label' => 'Base d\'Objets'], + ['file' => 'scstatsitem.php', 'label' => 'Stats Item'], + ['file' => 'scitemcustom.php', 'label' => 'Item Custom'], + ['file' => 'scmining.php', 'label' => 'Scanner Minage'], + ['file' => 'scmanufactures.php', 'label' => 'Manufactures'], + ['file' => 'scvaisseaux.php', 'label' => 'Vaisseaux'], + ['file' => 'scpreset.php', 'label' => 'Presets Vaisseau'], + ]; +} + +function auth_render_app_nav(string $current_page): string +{ + if (!auth_is_logged_in()) { + return ''; + } + + $current_page = auth_page_basename($current_page); + $html = ''; + + return $html; +} diff --git a/index-en.php b/index-en.php index c0efc58..45f9587 100644 --- a/index-en.php +++ b/index-en.php @@ -38,7 +38,7 @@ $has_member_access = $is_authenticated && in_array($session_cl_auth_right, ['mem diff --git a/index.php b/index.php index 9ca0aad..6256ab3 100644 --- a/index.php +++ b/index.php @@ -1005,7 +1005,7 @@ if ($has_member_access) { diff --git a/scitemcustom.php b/scitemcustom.php index ac032ce..3e3ed06 100644 --- a/scitemcustom.php +++ b/scitemcustom.php @@ -6,14 +6,11 @@ require_once __DIR__ . '/db/scitemcustom.php'; auth_start_session(); auth_bootstrap(); +auth_handle_page_access_post('scitemcustom.php', 'Item Custom'); +auth_require_page_access('scitemcustom.php', 'Item Custom'); scstatsitem_bootstrap(); scitemcustom_bootstrap(); -if (!auth_is_admin()) { - header('Location: index.php'); - exit; -} - function scitemcustom_normalize_sign(?string $sign): string { if ($sign === '-') { @@ -755,6 +752,7 @@ $current_session_user = $_SESSION['user'] ?? ''; +