From 262ff6a00e3a914c06a0aaff29e476b904e45c25 Mon Sep 17 00:00:00 2001 From: billz Date: Tue, 5 Nov 2024 09:12:19 -0800 Subject: [PATCH] Initial commit --- src/RaspAP/Plugins/PluginInterface.php | 31 +++++++ src/RaspAP/Plugins/PluginManager.php | 120 +++++++++++++++++++++++++ src/RaspAP/UI/Sidebar.php | 98 ++++++++++++++++++++ 3 files changed, 249 insertions(+) create mode 100644 src/RaspAP/Plugins/PluginInterface.php create mode 100644 src/RaspAP/Plugins/PluginManager.php create mode 100644 src/RaspAP/UI/Sidebar.php diff --git a/src/RaspAP/Plugins/PluginInterface.php b/src/RaspAP/Plugins/PluginInterface.php new file mode 100644 index 00000000..7413a2e9 --- /dev/null +++ b/src/RaspAP/Plugins/PluginInterface.php @@ -0,0 +1,31 @@ + + * @license https://github.com/raspap/raspap-webgui/blob/master/LICENSE + * @see + */ + +declare(strict_types=1); + +namespace RaspAP\Plugins; + +use RaspAP\UI\Sidebar; + +interface PluginInterface { + /** + * Initialize the plugin + * @param Sidebar $sidebar Sidebar instance for adding items + */ + public function initialize(Sidebar $sidebar): void; + + /** + * Provide template data for rendering + * @return array + */ + public function getTemplateData(): array; +} + diff --git a/src/RaspAP/Plugins/PluginManager.php b/src/RaspAP/Plugins/PluginManager.php new file mode 100644 index 00000000..cfd54276 --- /dev/null +++ b/src/RaspAP/Plugins/PluginManager.php @@ -0,0 +1,120 @@ + + * @license https://github.com/raspap/raspap-webgui/blob/master/LICENSE + */ + +declare(strict_types=1); + +namespace RaspAP\Plugins; + +use RaspAP\UI\Sidebar; + +class PluginManager { + private static $instance = null; + private $plugins = []; + private $sidebar; + + private function __construct() { + $this->pluginPath = 'plugins'; + $this->sidebar = new Sidebar(); + $this->autoloadPlugins(); // autoload plugins on instantiation + } + + // Get the single instance of PluginManager + public static function getInstance(): PluginManager { + if (self::$instance === null) { + self::$instance = new PluginManager(); + } + return self::$instance; + } + + // Autoload plugins found in pluginPath + private function autoloadPlugins(): void { + if (!is_dir($this->pluginPath)) { + return; + } + $directories = array_filter(glob($this->pluginPath . '/*'), 'is_dir'); + foreach ($directories as $dir) { + $pluginName = basename($dir); + $pluginFile = "$dir/$pluginName.php"; + + if (file_exists($pluginFile)) { + require_once $pluginFile; + $className = "RaspAP\\Plugins\\$pluginName\\$pluginName"; // Fully qualified class name + if (class_exists($className)) { + $plugin = new $className(); + $this->registerPlugin($plugin); + } + } + } + } + + // Registers a plugin by its interface implementation + private function registerPlugin(PluginInterface $plugin) { + $plugin->initialize($this->sidebar); // pass sidebar to initialize method + $this->plugins[] = $plugin; // store the plugin instance + } + + /** + * Renders a template from inside a plugin directory + * @param string $pluginName + * @param string $templateName + * @param array $__data + */ + public function renderTemplate(string $pluginName, string $templateName, array $__data = []): string { + // Construct the file path for the template + $templateFile = "{$this->pluginPath}/{$pluginName}/templates/{$templateName}.php"; + + if (!file_exists($templateFile)) { + return "Template file {$templateFile} not found."; + } + + // Extract the data for use in the template + if (!empty($__data)) { + extract($__data); + } + + // Start output buffering to capture the template output + ob_start(); + include $templateFile; + return ob_get_clean(); // return the output + } + + // Returns the sidebar + public function getSidebar(): Sidebar { + return $this->sidebar; + } + + // Forwards the page to the responsible plugin + public function handlePageAction(string $page): void { + foreach ($this->getInstalledPlugins() as $plugin) { + if (str_starts_with($page, "/plugin__" . $plugin . "__")) { + require_once($this->pluginPath . "/" . $plugin . "/functions.php"); + $function = '\\' . $plugin . '\\pluginHandlePageAction'; + $function($page); + } + } + } + + // Returns all installed plugins + public function getInstalledPlugins(): array { + $plugins = []; + if (file_exists($this->pluginPath)) { + $files = scandir($this->pluginPath); + foreach ($files as $file) { + if ($file === "." || $file === "..") continue; + $filePath = $this->pluginPath . '/' . $file; + if (is_dir($filePath)) { + $plugins[] = $file; + } + } + } + return $plugins; + } +} + diff --git a/src/RaspAP/UI/Sidebar.php b/src/RaspAP/UI/Sidebar.php new file mode 100644 index 00000000..0a0aa4b3 --- /dev/null +++ b/src/RaspAP/UI/Sidebar.php @@ -0,0 +1,98 @@ + + * @license https://github.com/raspap/raspap-webgui/blob/master/LICENSE + */ + +namespace RaspAP\UI; + +class Sidebar { + private $items = []; + + public function __construct() { + // Load default sidebar items + $this->addItem(_('Dashboard'), 'fa-solid fa-gauge-high', 'wlan0_info', 10); + $this->addItem(_('Hotspot'), 'far fa-dot-circle', 'hostapd_conf', 20, + fn() => defined('RASPI_HOTSPOT_ENABLED') && RASPI_HOTSPOT_ENABLED + ); + $this->addItem(_('DHCP Server'), 'fas fa-exchange-alt', 'dhcpd_conf', 30, + fn() => defined('RASPI_DHCP_ENABLED') && RASPI_DHCP_ENABLED && !$_SESSION["bridgedEnabled"] + ); + $this->addItem(_('Ad Blocking'), 'far fa-hand-paper', 'adblock_conf', 40, + fn() => defined('RASPI_ADBLOCK_ENABLED') && RASPI_HOTSPOT_ENABLED && !$_SESSION["bridgedEnabled"] + ); + $this->addItem(_('Networking'), 'fas fa-network-wired', 'network_conf', 50, + fn() => defined('RASPI_NETWORK_ENABLED') && RASPI_NETWORK_ENABLED + ); + $this->addItem(_('WiFi client'), 'fas fa-wifi', 'wpa_conf', 60, + fn() => defined('RASPI_WIFICLIENT_ENABLED') && RASPI_WIFICLIENT_ENABLED && !$_SESSION["bridgedEnabled"] + ); + $this->addItem(_('OpenVPN'), 'fas fa-key', 'openvpn_conf', 70, + fn() => defined('RASPI_OPENVPN_ENABLED') && RASPI_OPENVPN_ENABLED + ); + $this->addItem(_('WireGuard'), 'ra-wireguard', 'wg_conf', 80, + fn() => defined('RASPI_WIREGUARD_ENABLED') && RASPI_WIREGUARD_ENABLED + ); + $this->addItem(_(getProviderValue($_SESSION["providerID"], "name")), 'fas fa-shield-alt', 'provider_conf', 90, + fn() => defined('RASPI_VPN_PROVIDER_ENABLED') && RASPI_VPN_PROVIDER_ENABLED + ); + $this->addItem(_('Authentication'), 'fas fa-user-lock', 'auth_conf', 100, + fn() => defined('RASPI_CONFAUTH_ENABLED') && RASPI_CONFAUTH_ENABLED + ); + $this->addItem(_('Data usage'), 'fas fa-chart-area', 'data_use', 110, + fn() => defined('RASPI_VNSTAT_ENABLED') && RASPI_VNSTAT_ENABLED + ); + $this->addItem(_('RestAPI'), 'fas fa-puzzle-piece', 'restapi_conf', 120, + fn() => defined('RASPI_VNSTAT_ENABLED') && RASPI_VNSTAT_ENABLED + ); + $this->addItem(_('System'), 'fas fa-cube', 'data_use', 130, + fn() => defined('RASPI_SYSTEM_ENABLED') && RASPI_SYSTEM_ENABLED + ); + $this->addItem(_('About RaspAP'), 'fas fa-info-circle', 'about', 140); + } + + /** + * Adds an item to the sidebar + * @param string $label + * @param string $iconClass + * @param string $link + * @param int $priority + * @param callable $condition + */ + public function addItem(string $label, string $iconClass, string $link, int $priority, callable $condition = null) { + $this->items[] = [ + 'label' => $label, + 'icon' => $iconClass, + 'link' => $link, + 'priority' => $priority, + 'condition' => $condition + ]; + } + + public function getItems(): array { + // Sort items by priority and filter by enabled condition + $filteredItems = array_filter($this->items, function ($item) { + return $item['condition'] === null || call_user_func($item['condition']); + }); + usort($filteredItems, function ($a, $b) { + return $a['priority'] <=> $b['priority']; + }); + return $filteredItems; + } + + public function render() { + foreach ($this->getItems() as $item) { + echo ""; + } + } +} +