Files
dockerfluxodecaixapro/app/Controllers/BaseAdminController.php
T
2026-09-01 10:46:29 -03:00

466 lines
17 KiB
PHP
Executable File

<?php
namespace App\Controllers;
use Kernel\View;
use Modules\Auth\Models\User;
use App\Models\Module;
use Modules\Company\Models\Company;
use Illuminate\Database\Capsule\Manager as DB;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
abstract class BaseAdminController
{
protected View $view;
public function __construct(View $view)
{
$this->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;
}
}