feat: add routes, lang, tests, stubs, docs, and docker configurations
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Permission;
|
||||
use App\Models\Role;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\WithFaker;
|
||||
|
||||
uses(WithFaker::class);
|
||||
|
||||
function grantManageAccessRights(User $user): void
|
||||
{
|
||||
$perm = Permission::firstOrCreate(['name' => 'manage access rights', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'view access rights', 'guard_name' => 'web']);
|
||||
$user->givePermissionTo($perm);
|
||||
}
|
||||
|
||||
test('guest cannot access roles index', function () {
|
||||
$this->get('/roles')->assertRedirect('/login');
|
||||
});
|
||||
|
||||
test('authenticated user without permission gets 403 on roles index', function () {
|
||||
$user = User::factory()->create();
|
||||
$this->actingAs($user)->get('/roles')->assertForbidden();
|
||||
});
|
||||
|
||||
test('user with manage access rights can store a new role', function () {
|
||||
$user = User::factory()->create();
|
||||
grantManageAccessRights($user);
|
||||
$p = Permission::firstOrCreate(['name' => 'view dashboard', 'guard_name' => 'web']);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->postJson('/roles', [
|
||||
'name' => 'editor-role',
|
||||
'guard_name' => 'web',
|
||||
'permissions' => [$p->id],
|
||||
]);
|
||||
|
||||
$response->assertOk()->assertJson(['success' => true]);
|
||||
$this->assertDatabaseHas('roles', ['name' => 'editor-role']);
|
||||
|
||||
$role = Role::where('name', 'editor-role')->first();
|
||||
expect($role->hasPermissionTo('view dashboard'))->toBeTrue();
|
||||
});
|
||||
|
||||
test('store rejects duplicate role name', function () {
|
||||
$user = User::factory()->create();
|
||||
grantManageAccessRights($user);
|
||||
$p = Permission::firstOrCreate(['name' => 'view dashboard', 'guard_name' => 'web']);
|
||||
Role::create(['name' => 'dup-role', 'guard_name' => 'web']);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->postJson('/roles', [
|
||||
'name' => 'dup-role',
|
||||
'guard_name' => 'web',
|
||||
'permissions' => [$p->id],
|
||||
]);
|
||||
|
||||
$response->assertStatus(422);
|
||||
});
|
||||
|
||||
test('store rejects empty permissions array', function () {
|
||||
$user = User::factory()->create();
|
||||
grantManageAccessRights($user);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->postJson('/roles', [
|
||||
'name' => 'no-perm-role',
|
||||
'guard_name' => 'web',
|
||||
'permissions' => [],
|
||||
]);
|
||||
|
||||
$response->assertStatus(422);
|
||||
});
|
||||
|
||||
test('store rejects invalid characters in role name', function () {
|
||||
$user = User::factory()->create();
|
||||
grantManageAccessRights($user);
|
||||
$p = Permission::firstOrCreate(['name' => 'view dashboard', 'guard_name' => 'web']);
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->postJson('/roles', [
|
||||
'name' => 'role with space!',
|
||||
'guard_name' => 'web',
|
||||
'permissions' => [$p->id],
|
||||
]);
|
||||
|
||||
$response->assertStatus(422);
|
||||
});
|
||||
|
||||
test('update replaces role permissions', function () {
|
||||
$user = User::factory()->create();
|
||||
grantManageAccessRights($user);
|
||||
$p1 = Permission::firstOrCreate(['name' => 'view dashboard', 'guard_name' => 'web']);
|
||||
$p2 = Permission::firstOrCreate(['name' => 'view user directory', 'guard_name' => 'web']);
|
||||
$role = Role::create(['name' => 'original-role', 'guard_name' => 'web']);
|
||||
$role->givePermissionTo('view dashboard');
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->putJson("/roles/{$role->id}", [
|
||||
'name' => 'renamed-role',
|
||||
'guard_name' => 'web',
|
||||
'permissions' => [$p2->id],
|
||||
]);
|
||||
|
||||
$response->assertOk();
|
||||
$role->refresh();
|
||||
expect($role->name)->toBe('renamed-role');
|
||||
expect($role->hasPermissionTo('view user directory'))->toBeTrue();
|
||||
expect($role->hasPermissionTo('view dashboard'))->toBeFalse();
|
||||
});
|
||||
|
||||
test('toggleStatus activates and deactivates role', function () {
|
||||
$user = User::factory()->create();
|
||||
grantManageAccessRights($user);
|
||||
$role = Role::create(['name' => 'toggleable', 'guard_name' => 'web', 'is_active' => true]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->postJson('/roles/toggle-status', ['id' => $role->id, 'status' => 'deactivate'])
|
||||
->assertOk();
|
||||
expect((bool) $role->fresh()->is_active)->toBeFalse();
|
||||
|
||||
$this->actingAs($user)
|
||||
->postJson('/roles/toggle-status', ['id' => $role->id, 'status' => 'activate'])
|
||||
->assertOk();
|
||||
expect((bool) $role->fresh()->is_active)->toBeTrue();
|
||||
});
|
||||
|
||||
test('destroy soft deletes role when no users assigned', function () {
|
||||
$user = User::factory()->create();
|
||||
grantManageAccessRights($user);
|
||||
$role = Role::create(['name' => 'doomed', 'guard_name' => 'web']);
|
||||
|
||||
$this->actingAs($user)
|
||||
->deleteJson("/roles/{$role->id}")
|
||||
->assertOk();
|
||||
|
||||
expect(Role::withTrashed()->find($role->id)->trashed())->toBeTrue();
|
||||
});
|
||||
|
||||
test('destroy blocks deletion when role is still assigned to a user', function () {
|
||||
$admin = User::factory()->create();
|
||||
grantManageAccessRights($admin);
|
||||
$role = Role::create(['name' => 'in-use', 'guard_name' => 'web']);
|
||||
$victim = User::factory()->create();
|
||||
$victim->assignRole($role);
|
||||
|
||||
$this->actingAs($admin)
|
||||
->deleteJson("/roles/{$role->id}")
|
||||
->assertStatus(422)
|
||||
->assertJson(['success' => false]);
|
||||
|
||||
expect(Role::find($role->id))->not->toBeNull();
|
||||
});
|
||||
|
||||
test('restore brings back a soft-deleted role', function () {
|
||||
$user = User::factory()->create();
|
||||
grantManageAccessRights($user);
|
||||
$role = Role::create(['name' => 'restorable', 'guard_name' => 'web']);
|
||||
$role->delete();
|
||||
|
||||
$this->actingAs($user)
|
||||
->postJson("/roles/{$role->id}/restore")
|
||||
->assertOk();
|
||||
|
||||
expect(Role::find($role->id)->trashed())->toBeFalse();
|
||||
});
|
||||
|
||||
test('forceDelete permanently removes role', function () {
|
||||
$user = User::factory()->create();
|
||||
grantManageAccessRights($user);
|
||||
$role = Role::create(['name' => 'gone-forever', 'guard_name' => 'web']);
|
||||
$role->delete();
|
||||
|
||||
$this->actingAs($user)
|
||||
->deleteJson("/roles/{$role->id}/force")
|
||||
->assertOk();
|
||||
|
||||
expect(Role::withTrashed()->find($role->id))->toBeNull();
|
||||
});
|
||||
|
||||
test('forceDelete blocks when role has users assigned', function () {
|
||||
$admin = User::factory()->create();
|
||||
grantManageAccessRights($admin);
|
||||
$role = Role::create(['name' => 'sticky', 'guard_name' => 'web']);
|
||||
$victim = User::factory()->create();
|
||||
$victim->assignRole($role);
|
||||
|
||||
$this->actingAs($admin)
|
||||
->deleteJson("/roles/{$role->id}/force")
|
||||
->assertStatus(422);
|
||||
|
||||
expect(Role::find($role->id))->not->toBeNull();
|
||||
});
|
||||
Reference in New Issue
Block a user