feat(auth): enable event-scoped admin access and backfill staff assignments
This commit is contained in:
@@ -23,7 +23,9 @@ class AdminAppContextService
|
|||||||
$user->load('event');
|
$user->load('event');
|
||||||
|
|
||||||
if (! $user->isTenantAdministrator()) {
|
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;
|
return $user;
|
||||||
|
|||||||
24
app/Domains/Core/Auth/Services/EventScopeService.php
Normal file
24
app/Domains/Core/Auth/Services/EventScopeService.php
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,8 +25,8 @@ class EnsureAdminAppTenant
|
|||||||
|| $user->rol_codigo !== RoleCode::AdminApp->value
|
|| $user->rol_codigo !== RoleCode::AdminApp->value
|
||||||
|| ! $user->tenant_codigo
|
|| ! $user->tenant_codigo
|
||||||
|| ! $this->accessService->hasValidScope($user)
|
|| ! $this->accessService->hasValidScope($user)
|
||||||
// Tenant operations remain unavailable until they implement event authorization.
|
// Only routes implementing event authorization may accept event administrators.
|
||||||
|| ($access !== 'context' && ! $user->isTenantAdministrator())
|
|| (! in_array($access, ['context', 'event'], true) && ! $user->isTenantAdministrator())
|
||||||
) {
|
) {
|
||||||
throw new AuthorizationException;
|
throw new AuthorizationException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -93,9 +93,9 @@ class AdminAppEventScopeTest extends TestCase
|
|||||||
$this->user = User::query()->findOrFail(1);
|
$this->user = User::query()->findOrFail(1);
|
||||||
DB::table('menues')->insert([
|
DB::table('menues')->insert([
|
||||||
['code' => 'main.adminapp', 'label' => 'Administración', 'route' => '/', 'parent_menu_code' => null],
|
['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('roles_menues')->insert(['rol_codigo' => 'adminapp', 'menu_codigo' => $code]);
|
||||||
DB::table('tenants_menues')->insert(['tenant_code' => 'onticket', 'menu_code' => $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()
|
$this->withToken($token)->getJson('/api/v1/adminapp/me')->assertOk()
|
||||||
->assertJsonPath('data.event.id', 1)->assertJsonPath('data.event.title', 'Evento A')
|
->assertJsonPath('data.event.id', 1)->assertJsonPath('data.event.title', 'Evento A')
|
||||||
->assertJsonPath('data.tenant.codigo', 'onticket')
|
->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);
|
$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]);
|
$this->user->update(['admin_scope' => 'event', 'event_id' => 1]);
|
||||||
$token = $this->login()->assertOk()->json('token');
|
$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)->getJson('/api/v1/adminapp/'.$path)->assertForbidden();
|
||||||
}
|
}
|
||||||
$this->withToken($token)->postJson('/api/v1/adminapp/tenant/administrators', [])->assertForbidden();
|
$this->withToken($token)->postJson('/api/v1/adminapp/tenant/administrators', [])->assertForbidden();
|
||||||
|
|||||||
Reference in New Issue
Block a user