466 lines
17 KiB
PHP
Executable File
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;
|
|
}
|
|
}
|