From a087a511e0d87bf32607a1417f8349d359bd9fd8 Mon Sep 17 00:00:00 2001 From: ncoronel Date: Fri, 31 Jul 2026 08:23:18 -0300 Subject: [PATCH] feat(authorization): filter tenant menus by user roles in bootstrap process --- .../Controllers/BootstrapTenantController.php | 5 ++- .../Tenant/BootstrapTenantControllerTest.php | 42 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/app/Domains/Tenant/Controllers/BootstrapTenantController.php b/app/Domains/Tenant/Controllers/BootstrapTenantController.php index 4d7402a..0ffea8e 100644 --- a/app/Domains/Tenant/Controllers/BootstrapTenantController.php +++ b/app/Domains/Tenant/Controllers/BootstrapTenantController.php @@ -25,7 +25,10 @@ class BootstrapTenantController extends Controller ->where('dominio', $dominio) ->firstOrFail(), [ - 'menues', + 'menues' => fn ($query) => $query->whereHas( + 'roles', + fn ($query) => $query->where('codigo', 'user') + ), 'categories' => fn ($query) => $query->orderBy('nombre'), ] ) diff --git a/tests/Feature/Tenant/BootstrapTenantControllerTest.php b/tests/Feature/Tenant/BootstrapTenantControllerTest.php index 8e74b82..8fc30fa 100644 --- a/tests/Feature/Tenant/BootstrapTenantControllerTest.php +++ b/tests/Feature/Tenant/BootstrapTenantControllerTest.php @@ -4,6 +4,7 @@ namespace Tests\Feature\Tenant; use App\Domains\Attachable\Enums\AttachmentType; use App\Domains\Attachable\Models\Attachment; +use App\Domains\Authorization\Models\Role; use App\Domains\Catalog\Models\Category; use App\Domains\Menu\Models\Menu; use App\Domains\Tenant\Models\Tenant; @@ -145,6 +146,10 @@ class BootstrapTenantControllerTest extends TestCase public function test_it_returns_tenant_menus_as_a_clean_hierarchy(): void { $tenant = $this->createTenant(); + $userRole = Role::query()->create([ + 'codigo' => 'user', + 'nombre' => 'Usuario', + ]); $parent = Menu::query()->create([ 'code' => 'help', 'label' => 'Ayuda', @@ -181,6 +186,11 @@ class BootstrapTenantControllerTest extends TestCase $staticChild->code => ['static_content' => $staticContent], $dynamicChild->code, ]); + $userRole->menus()->sync([ + $parent->code, + $staticChild->code, + $dynamicChild->code, + ]); $response = $this->getJson('/api/tenants/bootstrap/acme.com'); @@ -214,6 +224,38 @@ class BootstrapTenantControllerTest extends TestCase $this->assertArrayNotHasKey('static_content', $menus[0]['submenues'][1]); } + public function test_it_returns_only_menus_assigned_to_the_user_role(): void + { + $tenant = $this->createTenant(); + $userRole = Role::query()->create([ + 'codigo' => 'user', + 'nombre' => 'Usuario', + ]); + $adminRole = Role::query()->create([ + 'codigo' => 'admin', + 'nombre' => 'Administrador', + ]); + $userMenu = Menu::query()->create([ + 'code' => 'account', + 'label' => 'Mi cuenta', + 'route' => '/mi-cuenta', + ]); + $adminMenu = Menu::query()->create([ + 'code' => 'admin.catalog', + 'label' => 'Catálogo', + 'route' => '/admin/catalog', + ]); + + $tenant->menues()->sync([$userMenu->code, $adminMenu->code]); + $userRole->menus()->sync([$userMenu->code]); + $adminRole->menus()->sync([$adminMenu->code]); + + $this->getJson('/api/tenants/bootstrap/acme.com') + ->assertOk() + ->assertJsonPath('data.menues.0.code', 'account') + ->assertJsonMissing(['code' => 'admin.catalog']); + } + public function test_it_rejects_duplicate_domains_after_normalization_when_storing(): void { $base64Image = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==';