From 6b5e82cd2e4b611ec247b7d9c1e05b8ef98019a4 Mon Sep 17 00:00:00 2001 From: olli Date: Fri, 5 Dec 2025 15:02:42 +0100 Subject: [PATCH] feat(auth): Add hasPermission method for role-based access control feat(module-registry): Enhance module booting logic for development environment feat(menu-item-registry): Allow loading of unlicensed plugins in development mode --- assets/js/stores/auth.js | 21 +++++++++++++++++++++ src/Plugin/ModuleRegistry.php | 27 ++++++++++++++++++++++++--- src/Service/MenuItemRegistry.php | 14 ++++++++++++-- 3 files changed, 57 insertions(+), 5 deletions(-) diff --git a/assets/js/stores/auth.js b/assets/js/stores/auth.js index ee7a9af..a3efe56 100644 --- a/assets/js/stores/auth.js +++ b/assets/js/stores/auth.js @@ -15,6 +15,26 @@ export const useAuthStore = defineStore('auth', () => { return user.value.roles && user.value.roles.includes(role); }; + const hasPermission = (permission) => { + if (!user.value) return false; + + // Admin hat immer alle Permissions + if (hasRole('ROLE_ADMIN')) return true; + + // Permission format: "module.action" z.B. "billing.view" + const [module, action] = permission.split('.'); + if (!module || !action) return false; + + // Prüfe ob User die Module-Permission hat + // Dies wird serverseitig validiert, hier nur UI-Steuerung + if (!user.value.modulePermissions) return false; + + const modulePerms = user.value.modulePermissions[module]; + if (!modulePerms) return false; + + return modulePerms.includes(action); + }; + const isAdmin = computed(() => hasRole('ROLE_ADMIN')); const initializeFromElement = () => { @@ -40,6 +60,7 @@ export const useAuthStore = defineStore('auth', () => { isAuthenticated, fullName, hasRole, + hasPermission, isAdmin, initializeFromElement, logout diff --git a/src/Plugin/ModuleRegistry.php b/src/Plugin/ModuleRegistry.php index 6516170..62a15ae 100644 --- a/src/Plugin/ModuleRegistry.php +++ b/src/Plugin/ModuleRegistry.php @@ -61,17 +61,30 @@ class ModuleRegistry */ public function bootModules(): void { + $isDev = ($_ENV['APP_ENV'] ?? 'prod') === 'dev'; + foreach ($this->modules as $identifier => $module) { try { // Lizenzprüfung if (!$module->isLicensed()) { $licenseInfo = $module->getLicenseInfo(); - $this->logger->warning(sprintf( - 'Modul "%s" wird nicht gebootet: %s', + + // In Production: Module ohne Lizenz nicht booten + if (!$isDev) { + $this->logger->warning(sprintf( + 'Modul "%s" wird nicht gebootet: %s', + $identifier, + $licenseInfo['message'] ?? 'Keine gültige Lizenz' + )); + continue; + } + + // In Development: Warnung loggen, aber trotzdem booten + $this->logger->info(sprintf( + 'Modul "%s" (Development): Boot ohne Lizenz - %s', $identifier, $licenseInfo['message'] ?? 'Keine gültige Lizenz' )); - continue; } // Modul booten @@ -111,6 +124,7 @@ class ModuleRegistry /** * Prüft, ob ein Modul registriert UND lizenziert ist + * (oder in Development ohne Lizenz läuft) */ public function isModuleActive(string $identifier): bool { @@ -120,6 +134,13 @@ class ModuleRegistry return false; } + // In Development: Modul ist aktiv wenn kein Boot-Error + $isDev = ($_ENV['APP_ENV'] ?? 'prod') === 'dev'; + if ($isDev) { + return !isset($this->bootErrors[$identifier]); + } + + // In Production: Modul muss lizenziert sein return $module->isLicensed() && !isset($this->bootErrors[$identifier]); } diff --git a/src/Service/MenuItemRegistry.php b/src/Service/MenuItemRegistry.php index e2000a3..43a6f9d 100644 --- a/src/Service/MenuItemRegistry.php +++ b/src/Service/MenuItemRegistry.php @@ -36,8 +36,11 @@ class MenuItemRegistry $menuItems = []; foreach ($this->moduleRegistry->getAllModules() as $plugin) { - // Nur lizenzierte Module berücksichtigen - if (!$plugin->isLicensed()) { + // In Production: Nur lizenzierte Module + // In Development: Alle Module (für lokale Entwicklung) + $isDev = ($_ENV['APP_ENV'] ?? 'prod') === 'dev'; + + if (!$isDev && !$plugin->isLicensed()) { $this->logger->debug(sprintf( 'Plugin "%s" übersprungen: Nicht lizenziert', $plugin->getIdentifier() @@ -45,6 +48,13 @@ class MenuItemRegistry continue; } + if ($isDev && !$plugin->isLicensed()) { + $this->logger->info(sprintf( + 'Plugin "%s": Development-Modus - wird ohne Lizenz geladen', + $plugin->getIdentifier() + )); + } + try { $pluginMenuItems = $plugin->getMenuItems();