From 310279084260a68e34f97f896fb4a37736dc489a Mon Sep 17 00:00:00 2001 From: Lars Gebhardt-Kusche Date: Mon, 2 Mar 2026 01:45:57 +0100 Subject: [PATCH] commit --- config/fileload.php | 67 +++++++++-------- public/page/index.php | 21 +++++- public/page/kea_dashboard.php | 74 +++++++++++++++++++ public/page/layout_end.php | 11 +++ public/page/layout_start.php | 38 ++++++++++ src/App/Config.php | 59 ++------------- src/App/functions.php | 28 ++++++++ src/Repository/KeaHostRepository.php | 104 +++++++++++++++++++++++++++ 8 files changed, 317 insertions(+), 85 deletions(-) create mode 100644 public/page/kea_dashboard.php create mode 100644 public/page/layout_end.php create mode 100644 public/page/layout_start.php create mode 100644 src/App/functions.php create mode 100644 src/Repository/KeaHostRepository.php diff --git a/config/fileload.php b/config/fileload.php index 1d94f93..56cc528 100755 --- a/config/fileload.php +++ b/config/fileload.php @@ -1,41 +1,48 @@ session()->start(); -$clientId = $app->session()->ensureClientId(); - -// Optionally expose a single global for templates if desired -$GLOBALS['client_id'] = $clientId; +// Globales Config Objekt erstellen +global $appConfig; +$dbEnabled = defined('APP_DB_ENABLED') ? APP_DB_ENABLED : true; +$appConfig = new \App\Config($dbConfig, $dbEnabled); \ No newline at end of file diff --git a/public/page/index.php b/public/page/index.php index df960db..d0765bb 100755 --- a/public/page/index.php +++ b/public/page/index.php @@ -1,3 +1,22 @@ findAll(50); + } catch (\Exception $e) { + $error = "Datenbankfehler: " . $e->getMessage(); + } +} else { + $error = "Datenbankverbindung ist nicht konfiguriert oder deaktiviert."; +} + +tpl('kea_dashboard', 'landing', compact('hosts', 'error')); \ No newline at end of file diff --git a/public/page/kea_dashboard.php b/public/page/kea_dashboard.php new file mode 100644 index 0000000..b3bffff --- /dev/null +++ b/public/page/kea_dashboard.php @@ -0,0 +1,74 @@ + +
+
+

KEA DHCP Hosts

+ +
+ + + + + +
+
+

+ Registrierte Geräte +

+

+ Übersicht der statischen Reservierungen und bekannten Clients. +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
HostnameIP AdresseMAC AdresseKontext + Edit +
Keine Hosts gefunden.
+ + + + + + + + + Bearbeiten +
+
+
+
\ No newline at end of file diff --git a/public/page/layout_end.php b/public/page/layout_end.php new file mode 100644 index 0000000..91179a6 --- /dev/null +++ b/public/page/layout_end.php @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/public/page/layout_start.php b/public/page/layout_start.php new file mode 100644 index 0000000..5be8f93 --- /dev/null +++ b/public/page/layout_start.php @@ -0,0 +1,38 @@ + + + + + + Nexus Control Panel + + + + + + + +
+
\ No newline at end of file diff --git a/src/App/Config.php b/src/App/Config.php index 4f02ea5..22438be 100755 --- a/src/App/Config.php +++ b/src/App/Config.php @@ -3,60 +3,11 @@ declare(strict_types=1); namespace App; -final class Config +class Config { public function __construct( - public readonly string $env, - public readonly string $prefix, - public readonly string $primaryDomain, - public readonly string $primaryUrl, - public readonly string $apiBase, - public readonly string $assetVersion, - public readonly bool $dbEnabled, - public readonly array $db, - ) {} - - public static function fromPhpConstants(string $configDir): self - { - // config.php defines these constants. - $env = defined('APP_ENV') ? (string) APP_ENV : 'prod'; - $prefix = defined('APP_PREFIX') ? (string) APP_PREFIX : 'app'; - $primaryDom = defined('APP_DOMAIN_PRIMARY') ? (string) APP_DOMAIN_PRIMARY : 'example.test'; - $primaryUrl = defined('APP_URL_PRIMARY') ? (string) APP_URL_PRIMARY : 'https://example.test'; - $apiBase = defined('APP_API_BASE') ? (string) APP_API_BASE : ($primaryUrl . '/api'); - $assetVersion = defined('ASSET_VERSION') ? (string) ASSET_VERSION : ''; - - $dbEnabled = defined('APP_DB_ENABLED') ? (bool) APP_DB_ENABLED : false; - - $dbFileRoot = rtrim($configDir, '/\\') . DIRECTORY_SEPARATOR . 'db.php'; - $dbFileEnv = rtrim($configDir, '/\\') . DIRECTORY_SEPARATOR . $env . DIRECTORY_SEPARATOR . 'db.php'; - $dbFile = file_exists($dbFileRoot) ? $dbFileRoot : (file_exists($dbFileEnv) ? $dbFileEnv : null); - $db = $dbFile ? (array) require $dbFile : []; - - return new self( - env: $env, - prefix: $prefix, - primaryDomain: $primaryDom, - primaryUrl: rtrim($primaryUrl, '/'), - apiBase: rtrim($apiBase, '/'), - assetVersion: $assetVersion, - dbEnabled: $dbEnabled, - db: $db - ); + public array $db, + public bool $dbEnabled = true + ) { } - - public function cookiePrefix(): string - { - // Example: add suffix for staging - if ($this->env === 'staging') { - return $this->prefix . '_stg_'; - } - return $this->prefix . '_'; - } - - public function cookieDomain(): string - { - // Leading dot for subdomain-wide cookies - return '.' . ltrim($this->primaryDomain, '.'); - } -} +} \ No newline at end of file diff --git a/src/App/functions.php b/src/App/functions.php new file mode 100644 index 0000000..d9a63b2 --- /dev/null +++ b/src/App/functions.php @@ -0,0 +1,28 @@ +"; + } +} + +/** + * HTML Escaping Helper. + */ +function e(?string $string): string +{ + return htmlspecialchars($string ?? '', ENT_QUOTES, 'UTF-8'); +} \ No newline at end of file diff --git a/src/Repository/KeaHostRepository.php b/src/Repository/KeaHostRepository.php new file mode 100644 index 0000000..2260729 --- /dev/null +++ b/src/Repository/KeaHostRepository.php @@ -0,0 +1,104 @@ +pdo->prepare( + 'SELECT host_id, dhcp_identifier, ipv4_address, hostname, user_context + FROM hosts + ORDER BY host_id DESC + LIMIT :limit' + ); + $stmt->bindValue(':limit', $limit, PDO::PARAM_INT); + $stmt->execute(); + + return $stmt->fetchAll(PDO::FETCH_ASSOC); + } + + /** + * Sucht einen Host anhand der MAC-Adresse (dhcp_identifier). + */ + public function findByMac(string $mac): ?array + { + // Hinweis: KEA speichert MACs in PostgreSQL oft als BYTEA. + // Je nach Treiber-Konfiguration muss $mac hier ggf. als Hex-String (z.B. '\x...') + // formatiert übergeben werden. + $stmt = $this->pdo->prepare( + 'SELECT host_id, dhcp_identifier, ipv4_address, hostname, user_context + FROM hosts + WHERE dhcp_identifier = :mac + LIMIT 1' + ); + $stmt->execute(['mac' => $mac]); + + $row = $stmt->fetch(PDO::FETCH_ASSOC); + return $row ?: null; + } + + /** + * Erstellt eine neue Host-Reservierung inkl. Metadaten. + * + * @param string $mac MAC-Adresse + * @param string $ip IPv4-Adresse + * @param int $subnetId Die ID des Subnets (dhcp4_subnet_id), in dem die IP liegt + * @param string|null $hostname Optionaler Hostname + * @param array $metadata Zusätzliche Infos (Standort, Verantwortlicher etc.) für 'user_context' + */ + public function create(string $mac, string $ip, int $subnetId, ?string $hostname = null, array $metadata = []): int + { + // Metadaten werden im KEA-Standardfeld 'user_context' als JSON gespeichert + $userContextJson = json_encode($metadata, JSON_THROW_ON_ERROR); + + // dhcp_identifier_type 1 = HW_ADDRESS (Ethernet) + $stmt = $this->pdo->prepare( + 'INSERT INTO hosts (dhcp_identifier, dhcp_identifier_type, dhcp4_subnet_id, ipv4_address, hostname, user_context) + VALUES (:mac, 1, :subnetId, :ip, :hostname, :user_context)' + ); + + $stmt->execute([ + 'mac' => $mac, + 'subnetId' => $subnetId, + 'ip' => $ip, + 'hostname' => $hostname, + 'user_context' => $userContextJson, + ]); + + return $this->lastInsertIdSafe(); + } + + private function driver(): string + { + return (string)$this->pdo->getAttribute(PDO::ATTR_DRIVER_NAME); + } + + private function lastInsertIdSafe(): int + { + $driver = $this->driver(); + + if ($driver === 'pgsql') { + // KEA Standard-Sequenz für die hosts Tabelle + $id = $this->pdo->lastInsertId('hosts_host_id_seq'); + if ($id !== '') { + return (int)$id; + } + } + + return (int)$this->pdo->lastInsertId(); + } +} \ No newline at end of file