feat(authorization): implement AuthorizationSeeder with roles and permissions, add tests
This commit is contained in:
173
database/seeders/AuthorizationSeeder.php
Normal file
173
database/seeders/AuthorizationSeeder.php
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Domains\Authorization\Models\Permission;
|
||||||
|
use App\Domains\Authorization\Models\Role;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
class AuthorizationSeeder extends Seeder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array<string, array{nombre: string, descripcion: string}>
|
||||||
|
*/
|
||||||
|
private const PERMISSIONS = [
|
||||||
|
'tenant.ver' => [
|
||||||
|
'nombre' => 'Ver configuración del tenant',
|
||||||
|
'descripcion' => 'Permite consultar la configuración general de un tenant.',
|
||||||
|
],
|
||||||
|
'tenant.editar' => [
|
||||||
|
'nombre' => 'Editar configuración del tenant',
|
||||||
|
'descripcion' => 'Permite modificar los datos generales, dominio, colores y recursos visuales del tenant.',
|
||||||
|
],
|
||||||
|
'usuarios.ver' => [
|
||||||
|
'nombre' => 'Ver usuarios',
|
||||||
|
'descripcion' => 'Permite consultar los usuarios asociados al tenant.',
|
||||||
|
],
|
||||||
|
'usuarios.gestionar' => [
|
||||||
|
'nombre' => 'Gestionar usuarios',
|
||||||
|
'descripcion' => 'Permite invitar, editar, desactivar y asignar roles permitidos a los usuarios del tenant.',
|
||||||
|
],
|
||||||
|
'roles.ver' => [
|
||||||
|
'nombre' => 'Ver roles',
|
||||||
|
'descripcion' => 'Permite consultar los roles y sus permisos.',
|
||||||
|
],
|
||||||
|
'roles.gestionar' => [
|
||||||
|
'nombre' => 'Gestionar roles',
|
||||||
|
'descripcion' => 'Permite crear, modificar y asignar permisos a roles.',
|
||||||
|
],
|
||||||
|
'catalogo.ver' => [
|
||||||
|
'nombre' => 'Ver catálogo',
|
||||||
|
'descripcion' => 'Permite consultar administrativamente productos, variantes, categorías, marcas y bundles.',
|
||||||
|
],
|
||||||
|
'catalogo.gestionar' => [
|
||||||
|
'nombre' => 'Gestionar catálogo',
|
||||||
|
'descripcion' => 'Permite crear, modificar, archivar y eliminar productos, variantes, categorías, marcas y bundles.',
|
||||||
|
],
|
||||||
|
'inventario.ver' => [
|
||||||
|
'nombre' => 'Ver inventario',
|
||||||
|
'descripcion' => 'Permite consultar el stock y la información de inventario.',
|
||||||
|
],
|
||||||
|
'inventario.ajustar' => [
|
||||||
|
'nombre' => 'Ajustar inventario',
|
||||||
|
'descripcion' => 'Permite modificar el stock disponible.',
|
||||||
|
],
|
||||||
|
'pedidos.ver' => [
|
||||||
|
'nombre' => 'Ver pedidos',
|
||||||
|
'descripcion' => 'Permite consultar los pedidos del tenant.',
|
||||||
|
],
|
||||||
|
'pedidos.gestionar' => [
|
||||||
|
'nombre' => 'Gestionar pedidos',
|
||||||
|
'descripcion' => 'Permite modificar estados y datos operativos de los pedidos.',
|
||||||
|
],
|
||||||
|
'pedidos.cancelar' => [
|
||||||
|
'nombre' => 'Cancelar pedidos',
|
||||||
|
'descripcion' => 'Permite cancelar pedidos y liberar sus reservas de inventario.',
|
||||||
|
],
|
||||||
|
'pagos.ver' => [
|
||||||
|
'nombre' => 'Ver pagos',
|
||||||
|
'descripcion' => 'Permite consultar el estado y la información de los pagos.',
|
||||||
|
],
|
||||||
|
'pagos.gestionar' => [
|
||||||
|
'nombre' => 'Gestionar pagos',
|
||||||
|
'descripcion' => 'Permite confirmar, rechazar o devolver pagos.',
|
||||||
|
],
|
||||||
|
'tickets.ver' => [
|
||||||
|
'nombre' => 'Ver tickets',
|
||||||
|
'descripcion' => 'Permite consultar los tickets emitidos.',
|
||||||
|
],
|
||||||
|
'tickets.gestionar' => [
|
||||||
|
'nombre' => 'Gestionar tickets',
|
||||||
|
'descripcion' => 'Permite emitir, invalidar o regenerar tickets.',
|
||||||
|
],
|
||||||
|
'contenido.gestionar' => [
|
||||||
|
'nombre' => 'Gestionar contenido',
|
||||||
|
'descripcion' => 'Permite administrar menús, carruseles, destacados y redes sociales.',
|
||||||
|
],
|
||||||
|
'integraciones.ver' => [
|
||||||
|
'nombre' => 'Ver integraciones',
|
||||||
|
'descripcion' => 'Permite consultar la configuración y el estado de las integraciones.',
|
||||||
|
],
|
||||||
|
'integraciones.gestionar' => [
|
||||||
|
'nombre' => 'Gestionar integraciones',
|
||||||
|
'descripcion' => 'Permite configurar credenciales y proveedores de integraciones.',
|
||||||
|
],
|
||||||
|
'reportes.ver' => [
|
||||||
|
'nombre' => 'Ver reportes',
|
||||||
|
'descripcion' => 'Permite consultar reportes de ventas y métricas.',
|
||||||
|
],
|
||||||
|
'reportes.exportar' => [
|
||||||
|
'nombre' => 'Exportar reportes',
|
||||||
|
'descripcion' => 'Permite descargar reportes e información comercial.',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array<string, array{nombre: string, descripcion: string, permisos: list<string>}>
|
||||||
|
*/
|
||||||
|
private const ROLES = [
|
||||||
|
'admin' => [
|
||||||
|
'nombre' => 'Administrador general',
|
||||||
|
'descripcion' => 'Administra la plataforma y todos sus tenants.',
|
||||||
|
'permisos' => [],
|
||||||
|
],
|
||||||
|
'tenant_admin' => [
|
||||||
|
'nombre' => 'Administrador del tenant',
|
||||||
|
'descripcion' => 'Administra la operación de su propio tenant.',
|
||||||
|
'permisos' => [
|
||||||
|
'tenant.ver',
|
||||||
|
'tenant.editar',
|
||||||
|
'usuarios.ver',
|
||||||
|
'usuarios.gestionar',
|
||||||
|
'roles.ver',
|
||||||
|
'catalogo.ver',
|
||||||
|
'catalogo.gestionar',
|
||||||
|
'inventario.ver',
|
||||||
|
'inventario.ajustar',
|
||||||
|
'pedidos.ver',
|
||||||
|
'pedidos.gestionar',
|
||||||
|
'pedidos.cancelar',
|
||||||
|
'pagos.ver',
|
||||||
|
'pagos.gestionar',
|
||||||
|
'tickets.ver',
|
||||||
|
'tickets.gestionar',
|
||||||
|
'contenido.gestionar',
|
||||||
|
'integraciones.ver',
|
||||||
|
'integraciones.gestionar',
|
||||||
|
'reportes.ver',
|
||||||
|
'reportes.exportar',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'user' => [
|
||||||
|
'nombre' => 'Usuario',
|
||||||
|
'descripcion' => 'Cliente final limitado a sus propios datos y operaciones.',
|
||||||
|
'permisos' => [],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
foreach (self::PERMISSIONS as $code => $attributes) {
|
||||||
|
Permission::query()->updateOrCreate(
|
||||||
|
['codigo' => $code],
|
||||||
|
$attributes
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (self::ROLES as $code => $attributes) {
|
||||||
|
$role = Role::query()->updateOrCreate(
|
||||||
|
['codigo' => $code],
|
||||||
|
[
|
||||||
|
'nombre' => $attributes['nombre'],
|
||||||
|
'descripcion' => $attributes['descripcion'],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$permissionCodes = $code === 'admin'
|
||||||
|
? array_keys(self::PERMISSIONS)
|
||||||
|
: $attributes['permisos'];
|
||||||
|
|
||||||
|
$role->permissions()->sync($permissionCodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@ class DatabaseSeeder extends Seeder
|
|||||||
|
|
||||||
$this->call([
|
$this->call([
|
||||||
WebsiteTypeSeeder::class,
|
WebsiteTypeSeeder::class,
|
||||||
|
AuthorizationSeeder::class,
|
||||||
SocialMediaSeeder::class,
|
SocialMediaSeeder::class,
|
||||||
TenantSeeder::class,
|
TenantSeeder::class,
|
||||||
AttributeSeeder::class,
|
AttributeSeeder::class,
|
||||||
|
|||||||
85
docs/authorization.md
Normal file
85
docs/authorization.md
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
# Roles y permisos
|
||||||
|
|
||||||
|
El sistema utiliza control de acceso basado en roles. Los códigos son identificadores
|
||||||
|
estables para uso interno; los nombres y las descripciones pueden modificarse sin
|
||||||
|
afectar las reglas de autorización.
|
||||||
|
|
||||||
|
Los permisos administrativos deben evaluarse siempre dentro del tenant correspondiente.
|
||||||
|
El rol `admin` es la única excepción porque su alcance es toda la plataforma.
|
||||||
|
|
||||||
|
## Roles
|
||||||
|
|
||||||
|
| Código | Nombre | Alcance |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `admin` | Administrador general | Administra la plataforma, todos los tenants, roles y permisos. Tiene todos los permisos. |
|
||||||
|
| `tenant_admin` | Administrador del tenant | Administra usuarios y la operación de su tenant. No puede gestionar la definición de roles. |
|
||||||
|
| `user` | Usuario | Cliente final. No tiene permisos administrativos y solamente puede operar sobre sus propios datos, carrito, pedidos y tickets. |
|
||||||
|
|
||||||
|
## Permisos
|
||||||
|
|
||||||
|
| Código | Nombre | Descripción |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `tenant.ver` | Ver configuración del tenant | Consultar la configuración general de un tenant. |
|
||||||
|
| `tenant.editar` | Editar configuración del tenant | Modificar datos generales, dominio, colores y recursos visuales. |
|
||||||
|
| `usuarios.ver` | Ver usuarios | Consultar los usuarios asociados al tenant. |
|
||||||
|
| `usuarios.gestionar` | Gestionar usuarios | Invitar, editar, desactivar y asignar roles permitidos a usuarios del tenant. |
|
||||||
|
| `roles.ver` | Ver roles | Consultar los roles y sus permisos. |
|
||||||
|
| `roles.gestionar` | Gestionar roles | Crear, modificar y asignar permisos a roles. |
|
||||||
|
| `catalogo.ver` | Ver catálogo | Consultar productos, variantes, categorías, marcas y bundles administrativamente. |
|
||||||
|
| `catalogo.gestionar` | Gestionar catálogo | Crear, modificar, archivar y eliminar productos, variantes, categorías, marcas y bundles. |
|
||||||
|
| `inventario.ver` | Ver inventario | Consultar stock e información de inventario. |
|
||||||
|
| `inventario.ajustar` | Ajustar inventario | Modificar el stock disponible. |
|
||||||
|
| `pedidos.ver` | Ver pedidos | Consultar los pedidos del tenant. |
|
||||||
|
| `pedidos.gestionar` | Gestionar pedidos | Modificar estados y datos operativos de pedidos. |
|
||||||
|
| `pedidos.cancelar` | Cancelar pedidos | Cancelar pedidos y liberar sus reservas de inventario. |
|
||||||
|
| `pagos.ver` | Ver pagos | Consultar el estado y la información de pagos. |
|
||||||
|
| `pagos.gestionar` | Gestionar pagos | Confirmar, rechazar o devolver pagos. |
|
||||||
|
| `tickets.ver` | Ver tickets | Consultar tickets emitidos. |
|
||||||
|
| `tickets.gestionar` | Gestionar tickets | Emitir, invalidar o regenerar tickets. |
|
||||||
|
| `contenido.gestionar` | Gestionar contenido | Administrar menús, carruseles, destacados y redes sociales. |
|
||||||
|
| `integraciones.ver` | Ver integraciones | Consultar la configuración y el estado de integraciones. |
|
||||||
|
| `integraciones.gestionar` | Gestionar integraciones | Configurar credenciales y proveedores de integraciones. |
|
||||||
|
| `reportes.ver` | Ver reportes | Consultar reportes de ventas y métricas. |
|
||||||
|
| `reportes.exportar` | Exportar reportes | Descargar reportes e información comercial. |
|
||||||
|
|
||||||
|
## Matriz de asignación
|
||||||
|
|
||||||
|
| Permiso | `admin` | `tenant_admin` | `user` |
|
||||||
|
| --- | :---: | :---: | :---: |
|
||||||
|
| `tenant.ver` | Sí | Sí | No |
|
||||||
|
| `tenant.editar` | Sí | Sí | No |
|
||||||
|
| `usuarios.ver` | Sí | Sí | No |
|
||||||
|
| `usuarios.gestionar` | Sí | Sí | No |
|
||||||
|
| `roles.ver` | Sí | Sí | No |
|
||||||
|
| `roles.gestionar` | Sí | No | No |
|
||||||
|
| `catalogo.ver` | Sí | Sí | No |
|
||||||
|
| `catalogo.gestionar` | Sí | Sí | No |
|
||||||
|
| `inventario.ver` | Sí | Sí | No |
|
||||||
|
| `inventario.ajustar` | Sí | Sí | No |
|
||||||
|
| `pedidos.ver` | Sí | Sí | No |
|
||||||
|
| `pedidos.gestionar` | Sí | Sí | No |
|
||||||
|
| `pedidos.cancelar` | Sí | Sí | No |
|
||||||
|
| `pagos.ver` | Sí | Sí | No |
|
||||||
|
| `pagos.gestionar` | Sí | Sí | No |
|
||||||
|
| `tickets.ver` | Sí | Sí | No |
|
||||||
|
| `tickets.gestionar` | Sí | Sí | No |
|
||||||
|
| `contenido.gestionar` | Sí | Sí | No |
|
||||||
|
| `integraciones.ver` | Sí | Sí | No |
|
||||||
|
| `integraciones.gestionar` | Sí | Sí | No |
|
||||||
|
| `reportes.ver` | Sí | Sí | No |
|
||||||
|
| `reportes.exportar` | Sí | Sí | No |
|
||||||
|
|
||||||
|
## Carga inicial
|
||||||
|
|
||||||
|
El seeder `Database\Seeders\AuthorizationSeeder` crea o actualiza este catálogo y
|
||||||
|
sincroniza sus asignaciones. Puede ejecutarse de manera independiente:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php artisan db:seed --class=AuthorizationSeeder
|
||||||
|
```
|
||||||
|
|
||||||
|
También se ejecuta como parte de `DatabaseSeeder`.
|
||||||
|
|
||||||
|
Las acciones del rol `user` no se representan como permisos administrativos. El
|
||||||
|
acceso al perfil, carrito, pedidos y tickets se autoriza comprobando que el recurso
|
||||||
|
pertenezca al usuario autenticado y al tenant actual.
|
||||||
49
tests/Feature/Seeders/AuthorizationSeederTest.php
Normal file
49
tests/Feature/Seeders/AuthorizationSeederTest.php
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Feature\Seeders;
|
||||||
|
|
||||||
|
use App\Domains\Authorization\Models\Permission;
|
||||||
|
use App\Domains\Authorization\Models\Role;
|
||||||
|
use Database\Seeders\AuthorizationSeeder;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class AuthorizationSeederTest extends TestCase
|
||||||
|
{
|
||||||
|
use RefreshDatabase;
|
||||||
|
|
||||||
|
public function test_it_creates_the_initial_roles_and_permissions(): void
|
||||||
|
{
|
||||||
|
$this->seed(AuthorizationSeeder::class);
|
||||||
|
|
||||||
|
$this->assertSame(
|
||||||
|
['admin', 'tenant_admin', 'user'],
|
||||||
|
Role::query()->orderBy('codigo')->pluck('codigo')->all()
|
||||||
|
);
|
||||||
|
$this->assertCount(22, Permission::query()->get());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_it_assigns_the_expected_permissions_to_each_role(): void
|
||||||
|
{
|
||||||
|
$this->seed(AuthorizationSeeder::class);
|
||||||
|
|
||||||
|
$admin = Role::query()->where('codigo', 'admin')->firstOrFail();
|
||||||
|
$tenantAdmin = Role::query()->where('codigo', 'tenant_admin')->firstOrFail();
|
||||||
|
$user = Role::query()->where('codigo', 'user')->firstOrFail();
|
||||||
|
|
||||||
|
$this->assertCount(22, $admin->permissions);
|
||||||
|
$this->assertCount(21, $tenantAdmin->permissions);
|
||||||
|
$this->assertFalse($tenantAdmin->permissions->contains('codigo', 'roles.gestionar'));
|
||||||
|
$this->assertCount(0, $user->permissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_it_can_run_more_than_once_without_creating_duplicates(): void
|
||||||
|
{
|
||||||
|
$this->seed(AuthorizationSeeder::class);
|
||||||
|
$this->seed(AuthorizationSeeder::class);
|
||||||
|
|
||||||
|
$this->assertCount(3, Role::query()->get());
|
||||||
|
$this->assertCount(22, Permission::query()->get());
|
||||||
|
$this->assertDatabaseCount('roles_permisos', 43);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user