feat(auth): enable event-scoped admin access and backfill staff assignments

This commit is contained in:
2026-09-30 15:31:53 -03:00
parent 44bf67bd12
commit a770d435eb
5 changed files with 77 additions and 7 deletions

View File

@@ -23,7 +23,9 @@ class AdminAppContextService
$user->load('event');
if (! $user->isTenantAdministrator()) {
$tenant->setRelation('menues', $tenant->menues->where('code', 'main.adminapp')->values());
$allowed = ['main.adminapp', 'adminapp.inicio', 'adminapp.event',
'adminapp.catalog', 'adminapp.ventas', 'adminapp.staff'];
$tenant->setRelation('menues', $tenant->menues->whereIn('code', $allowed)->values());
}
return $user;

View File

@@ -0,0 +1,24 @@
<?php
namespace App\Domains\Core\Auth\Services;
use App\Domains\Core\Auth\Enums\AdminScope;
use App\Domains\Core\Auth\Models\User;
use Illuminate\Auth\Access\AuthorizationException;
class EventScopeService
{
public function eventId(User $user): ?int
{
if ($user->admin_scope === AdminScope::Event->value || $user->event_id !== null) {
if ($user->event_id === null
|| ! $user->event()->where('tenant_code', $user->tenant_codigo)->exists()) {
throw new AuthorizationException;
}
return $user->event_id;
}
return null;
}
}

View File

@@ -25,8 +25,8 @@ class EnsureAdminAppTenant
|| $user->rol_codigo !== RoleCode::AdminApp->value
|| ! $user->tenant_codigo
|| ! $this->accessService->hasValidScope($user)
// Tenant operations remain unavailable until they implement event authorization.
|| ($access !== 'context' && ! $user->isTenantAdministrator())
// Only routes implementing event authorization may accept event administrators.
|| (! in_array($access, ['context', 'event'], true) && ! $user->isTenantAdministrator())
) {
throw new AuthorizationException;
}

View File

@@ -0,0 +1,44 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;
return new class extends Migration
{
public function up(): void
{
DB::transaction(function (): void {
DB::table('tenants')
->join('events', 'events.id', '=', 'tenants.active_event_id')
->whereColumn('events.tenant_code', 'tenants.codigo')
->select('tenants.codigo', 'tenants.active_event_id')
->get()
->each(function (object $tenant): void {
DB::table('users')
->whereIn('rol_codigo', ['adminapp', 'scanner'])
->where('tenant_codigo', $tenant->codigo)
->where('admin_scope', 'tenant')
->whereNull('event_id')
->whereNull('deleted_at')
->update([
'admin_scope' => 'event',
'event_id' => $tenant->active_event_id,
'updated_at' => now(),
]);
});
// Missing or mismatched active events must not leave legacy staff with tenant-wide access.
DB::table('users')
->whereIn('rol_codigo', ['adminapp', 'scanner'])
->where('admin_scope', 'tenant')
->whereNull('event_id')
->whereNull('deleted_at')
->update(['admin_scope' => 'event', 'updated_at' => now()]);
});
}
public function down(): void
{
// Do not broaden permissions or overwrite subsequent assignments on rollback.
}
};

View File

@@ -93,9 +93,9 @@ class AdminAppEventScopeTest extends TestCase
$this->user = User::query()->findOrFail(1);
DB::table('menues')->insert([
['code' => 'main.adminapp', 'label' => 'Administración', 'route' => '/', 'parent_menu_code' => null],
['code' => 'onticket.adminapp.ventas', 'label' => 'Ventas', 'route' => '/admin/ventas', 'parent_menu_code' => 'main.adminapp'],
['code' => 'adminapp.ventas', 'label' => 'Ventas', 'route' => '/admin/ventas', 'parent_menu_code' => 'main.adminapp'],
]);
foreach (['main.adminapp', 'onticket.adminapp.ventas'] as $code) {
foreach (['main.adminapp', 'adminapp.ventas'] as $code) {
DB::table('roles_menues')->insert(['rol_codigo' => 'adminapp', 'menu_codigo' => $code]);
DB::table('tenants_menues')->insert(['tenant_code' => 'onticket', 'menu_code' => $code]);
}
@@ -132,7 +132,7 @@ class AdminAppEventScopeTest extends TestCase
$this->withToken($token)->getJson('/api/v1/adminapp/me')->assertOk()
->assertJsonPath('data.event.id', 1)->assertJsonPath('data.event.title', 'Evento A')
->assertJsonPath('data.tenant.codigo', 'onticket')
->assertJsonCount(0, 'data.tenant.menues.0.submenues');
->assertJsonCount(1, 'data.tenant.menues.0.submenues');
$this->assertSame(['adminapp'], $this->user->tokens()->sole()->abilities);
}
@@ -156,7 +156,7 @@ class AdminAppEventScopeTest extends TestCase
{
$this->user->update(['admin_scope' => 'event', 'event_id' => 1]);
$token = $this->login()->assertOk()->json('token');
foreach (['tenant/sales', 'tenant/tickets', 'tenant/event', 'tenant/administrators', 'forms/event'] as $path) {
foreach (['tenant/tickets', 'tenant/administrators', 'tenant/website-extras', 'forms/tickets-filter'] as $path) {
$this->withToken($token)->getJson('/api/v1/adminapp/'.$path)->assertForbidden();
}
$this->withToken($token)->postJson('/api/v1/adminapp/tenant/administrators', [])->assertForbidden();