view = $view; } /** * Render an admin view with common data (sidebar, user, etc). * * @param string $viewName * @param array $data * @return Response */ protected function renderAdminView(string $viewName, array $data = []): Response { $user = $this->getCurrentUser(); if (!$user) { return new Response('', 302, ['Location' => url('/login')]); } // Get flash messages $flashMessages = []; if (isset($_SESSION['flash'])) { $flashMessages = $_SESSION['flash']; unset($_SESSION['flash']); } // Get enabled modules for the user's company $enabledModules = $this->getEnabledModules($user); // Build sidebar based on user permissions $sidebarItems = $this->buildUserSidebar($enabledModules, $user); // Build navbar based on user permissions $navbarItems = $this->buildUserNavbar($enabledModules, $user); // Get admin theme slug (default sb-admin) $adminThemeSlug = 'sb-admin'; // Get config pages visibility $configPagesVisibility = []; if (class_exists('Modules\Configindex\Models\ConfigPage')) { $baseDir = dirname(dirname(__DIR__)); $activeTheme = \Kernel\View::getActiveTheme() ?? 'default'; $indexViewsDir = $baseDir . '/modules/index/views'; $themeViewsDir = $baseDir . '/themes/' . $activeTheme . '/modules/index/views'; $pages = \Modules\Configindex\Models\ConfigPage::where('config_index_bus_id', $user->users_bus_id)->get(); foreach ($pages as $page) { $key = $page->config_index_key; // Verifica se o arquivo físico existe $fileExists = false; if ($key === 'index') { $fileExists = true; } else { $possiblePaths = [ $indexViewsDir . '/' . $key . '.twig', $indexViewsDir . '/' . $key . '.php', $themeViewsDir . '/' . $key . '.twig', $themeViewsDir . '/' . $key . '.php', $baseDir . '/themes/' . $activeTheme . '/' . $key . '.twig', $baseDir . '/themes/' . $activeTheme . '/' . $key . '.php', $baseDir . '/modules/' . $key . '/views/index.twig', ]; foreach ($possiblePaths as $path) { if (is_file($path)) { $fileExists = true; break; } } } $configPagesVisibility[$key] = [ 'public' => (bool)$page->config_index_show_public_nav && $fileExists, 'dashboard' => (bool)$page->config_index_show_dashboard_nav && $fileExists, 'title' => $page->config_index_title ?: ucfirst($key) ]; } // Garante que as páginas padrão tenham uma configuração inicial, mas respeita o banco de dados foreach (['about', 'contact', 'services'] as $key) { if (!isset($configPagesVisibility[$key])) { $configPagesVisibility[$key] = ['public' => false, 'dashboard' => false, 'title' => ucfirst($key)]; } } } $commonData = [ 'auth' => ['user' => $user], 'user' => $user, 'sidebar_items' => $sidebarItems, 'navbar_items' => $navbarItems, 'current_company' => $this->getCurrentCompany($user), 'admin_theme_slug' => $adminThemeSlug, 'config_pages_visibility' => $configPagesVisibility, 'flash_messages' => $flashMessages ]; return new Response($this->view->render($viewName, array_merge($commonData, $data))); } protected function redirect(string $path, int $status = 302): Response { return new RedirectResponse(url($path), $status); } /** * Get current authenticated user. * * @return User|null */ protected function getCurrentUser(): ?User { if (!isset($_SESSION['user_id'])) { return null; } try { return User::find($_SESSION['user_id']); } catch (\Exception $e) { error_log("Error loading user: " . $e->getMessage()); return null; } } /** * Check if current user can edit/delete an object. * Only author, admin or super_admin are allowed. * * @param int|string $authorId * @return bool */ protected function canEditObject($authorId): bool { $user = $this->getCurrentUser(); if (!$user) { return false; } if ($user->isSuperAdmin() || $user->isAdmin()) { return true; } return (int) $user->users_id === (int) $authorId; } /** * Get enabled modules for the user. * * @param User $user * @return \Illuminate\Database\Eloquent\Collection */ protected function getEnabledModules(User $user) { if ($user->isSuperAdmin()) { // Super Admin sees all active modules return Module::where('modules_ative', true) ->orderBy('modules_order', 'asc') ->get(); } // For other users, get modules enabled for their company $modules = Module::join('bus_modules', 'modules.modules_id', '=', 'bus_modules.bus_modules_module_id') ->where('bus_modules.bus_modules_bus_id', $user->users_bus_id) ->where('bus_modules.bus_modules_is_enabled', true) ->where('modules.modules_ative', true) ->orderBy('modules.modules_order', 'asc') ->select('modules.*', 'bus_modules.bus_modules_show_public_nav', 'bus_modules.bus_modules_show_dashboard_nav') ->get(); // If user is Admin, they see everything enabled for the company. // If user is Member or User, we MUST ensure they see modules they have explicit permissions for, // even if the module doesn't have bus_modules_show_dashboard_nav = true (if that was the blocker). // If we're missing core modules (auth, index) in the company's enabled list, // we should add them manually if they are active system-wide, // because they are essential for the dashboard to function. // We also add 'company' to ensure Admins can always manage their company details. $coreModules = Module::whereIn('modules_name', ['auth', 'index', 'company']) ->where('modules_ative', true) ->get(); foreach ($coreModules as $core) { if (!$modules->contains('modules_name', $core->modules_name)) { $modules->push($core); } } return $modules; } /** * Build user sidebar based on permissions. * * @param \Illuminate\Database\Eloquent\Collection $modules * @param User $user * @return array */ protected function buildUserSidebar($modules, User $user): array { $sidebarItems = []; // Ensure company settings link is always present for Admins if ($user->isAdmin() || $user->isSuperAdmin()) { $sidebarItems[] = [ 'icon' => 'bi bi-building', 'label' => __('company.menu.dashboard'), 'route' => 'admin/company/settings', 'order' => 30 ]; } foreach ($modules as $module) { // Skip company module if we already added it manually, or auth/index if ($module->modules_name === 'auth' || $module->modules_name === 'index' || $module->modules_name === 'company') { continue; } // Check if module is enabled for sidebar if (!$module->menu_side_bar) { continue; } $moduleConfig = $module->modules_settings ?: []; // If settings are empty, try to load from module.json file as a fallback if (empty($moduleConfig) || !isset($moduleConfig['menu'])) { $moduleJsonPath = dirname(__DIR__, 2) . '/modules/' . $module->modules_name . '/module.json'; if (file_exists($moduleJsonPath)) { $jsonContent = json_decode(file_get_contents($moduleJsonPath), true); if ($jsonContent && isset($jsonContent['menu'])) { $moduleConfig['menu'] = $jsonContent['menu']; } } } // Fix for company module if settings are still empty (due to migration issue) if ((empty($moduleConfig) || !isset($moduleConfig['menu'])) && $module->modules_name === 'company') { $moduleConfig['menu'] = [ 'dashboard' => [ 'icon' => 'bi bi-building', 'label' => 'company.menu.dashboard', 'route' => 'admin/company/settings', 'order' => 30 ] ]; } if (isset($moduleConfig['menu']['dashboard'])) { $menuItem = $moduleConfig['menu']['dashboard']; // Check if user can access this menu item // Respect company visibility preference when not super admin or admin // $companyAllows = ($user->isSuperAdmin() || $user->isAdmin()) || (isset($module->bus_modules_show_dashboard_nav) ? (bool) $module->bus_modules_show_dashboard_nav : true); // Simplified logic: if it's in the $modules list (which already filters by company enablement) // we only need to check the user's specific permissions. if ($this->userCanAccessMenuItem($user, $menuItem, $module)) { $sidebarItems[] = [ 'icon' => $menuItem['icon'] ?? $module->modules_icon, 'label' => __($menuItem['label'] ?? $module->modules_display_name), 'route' => $menuItem['route'] ?? 'admin/' . $module->modules_name, 'order' => $menuItem['order'] ?? $module->modules_order ]; } } } // Sort by order usort($sidebarItems, function ($a, $b) { return $a['order'] <=> $b['order']; }); return $sidebarItems; } /** * Build user navbar based on permissions. * * @param \Illuminate\Database\Eloquent\Collection $modules * @param User $user * @return array */ protected function buildUserNavbar($modules, User $user): array { $navbarItems = []; foreach ($modules as $module) { // Check if module is enabled for navbar if (!$module->menu_nav_bar) { continue; } $moduleConfig = $module->modules_settings ?: []; // If settings are empty, try to load from module.json file as a fallback if (empty($moduleConfig) || !isset($moduleConfig['menu'])) { $moduleJsonPath = dirname(__DIR__, 2) . '/modules/' . $module->modules_name . '/module.json'; if (file_exists($moduleJsonPath)) { $jsonContent = json_decode(file_get_contents($moduleJsonPath), true); if ($jsonContent && isset($jsonContent['menu'])) { $moduleConfig['menu'] = $jsonContent['menu']; } } } // Try to get specific navbar config, otherwise fallback to public or dashboard/general if (isset($moduleConfig['menu']['navbar'])) { $menuItem = $moduleConfig['menu']['navbar']; } elseif (isset($moduleConfig['menu']['public'])) { $menuItem = $moduleConfig['menu']['public']; } elseif (isset($moduleConfig['menu']['dashboard'])) { $menuItem = $moduleConfig['menu']['dashboard']; } else { continue; } // Check if user can access this menu item // Respect company visibility preference when not super admin or admin // $companyAllows = ($user->isSuperAdmin() || $user->isAdmin()) || (isset($module->bus_modules_show_public_nav) ? (bool) $module->bus_modules_show_public_nav : true); if ($this->userCanAccessMenuItem($user, $menuItem, $module)) { $route = $menuItem['route'] ?? $module->modules_name; $navbarItems[] = [ 'icon' => $menuItem['icon'] ?? $module->modules_icon, 'label' => __($menuItem['label'] ?? $module->modules_display_name), 'route' => $route, 'order' => $menuItem['order'] ?? $module->modules_order ]; } } // Sort by order usort($navbarItems, function ($a, $b) { return $a['order'] <=> $b['order']; }); return $navbarItems; } /** * Check if user can access a menu item. * * @param User $user * @param array $menuItem * @param Module|null $module * @return bool */ protected function userCanAccessMenuItem(User $user, array $menuItem, ?Module $module = null): bool { // Custom restriction for companies management (Must check before general admin/superadmin bypass) if (isset($menuItem['route']) && $menuItem['route'] === 'admin/companies') { return $user->isSuperAdmin(); } // Super Admin and Admin have access to everything authorized for the company if ($user->isSuperAdmin() || $user->isAdmin()) { return true; } // If specific permission defined for menu item, check it if (!empty($menuItem['permission'])) { return $user->hasPermission($menuItem['permission']); } // If no specific permission, but a module is provided if ($module) { // If the module is a core/blocked module, it's generally accessible // (like Auth or Index) if ($module->isBlocked()) { return true; } // For Member role, if no specific permission is required for the menu item, // we check if they have ANY permission for this module. // This ensures that if an Admin gave them "pagebuilder.view", the Page Builder // module link appears in the sidebar. return $this->userHasModulePermission($user, $module); } // Default to allowed for items without permissions or module context return true; } /** * Get current company for the user. * * @param User $user * @return Company|null */ protected function getCurrentCompany(User $user): ?Company { if ($user->isSuperAdmin()) { return null; // Super Admin can switch companies } return Company::find($user->users_bus_id); } /** * Check if user has permission for module. * * @param User $user * @param Module $module * @return bool */ protected function userHasModulePermission(User $user, Module $module): bool { // Super Admin and Admin have access to all modules enabled for their company if ($user->isSuperAdmin() || $user->isAdmin()) { return true; } // Core modules are accessible to all authenticated users if ($module->isBlocked()) { return true; } $modulePermissions = $module->getPermissionsAttribute(); // If module has no permissions defined and is public, it might be a general utility if (empty($modulePermissions) && $module->isPublic()) { return true; } foreach ($modulePermissions as $permission) { if ($user->hasPermission($permission)) { return true; } } return false; } /** * Add a flash message to the session. * * @param string $type success|error|info|warning * @param string $message */ protected function addFlash(string $type, string $message): void { if (session_status() === PHP_SESSION_NONE) { session_start(); } $_SESSION['flash'][$type] = $message; } }