Skip to content

Commit

Permalink
feat(provisioning): Implement role provisioning
Browse files Browse the repository at this point in the history
  • Loading branch information
pizkaz committed Dec 16, 2024
1 parent 4d80170 commit 85232a3
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 0 deletions.
9 changes: 9 additions & 0 deletions app/Console/Commands/ProvisionCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ public function handle()
if ($data->servers->wipe) {
$this->provision->server->destroy();
}
if ($data->roles->wipe) {
$this->provision->role->destroy();
}

// Add new instances
Log::notice('Provisioning {n} servers', ['n' => count($data->servers->add)]);
Expand All @@ -60,5 +63,11 @@ public function handle()
foreach ($data->room_types->add as $item) {
$this->provision->roomType->create($item);
}

Log::notice('Provisioning {n} roles', ['n' => count($data->roles->add)]);
foreach ($data->roles->add as $item) {
$item->permissions = (array) $item->permissions;
$this->provision->role->create($item);
}
}
}
47 changes: 47 additions & 0 deletions app/Services/ProvisioningService.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
namespace App\Services;

use App\Enums\ServerStatus;
use App\Models\Permission;
use App\Models\Role;
use App\Models\RoomType;
use App\Models\Server;
use App\Models\ServerPool;
Expand Down Expand Up @@ -174,6 +176,48 @@ public function destroy(array $match = [])
}
}

class RoleProvisioner extends AbstractProvisioner
{
protected string $model = Role::class;

protected array $expectedProperties = [
'name' => 'required|string',
'permissions' => 'required|array:rooms,meetings,settings,users,roles,roomTypes,servers,serverPools',
'permissions.rooms' => 'required|list',
'permissions.meetings' => 'required|list',
'permissions.settings' => 'required|list',
'permissions.users' => 'required|list',
'permissions.roles' => 'required|list',
'permissions.roomTypes' => 'required|list',
'permissions.servers' => 'required|list',
'permissions.serverPools' => 'required|list',
];

public function create(object $properties)
{
$this->createWrapper($properties, function ($role) use ($properties) {
foreach ($properties->permissions as $group => $perms) {
foreach ($perms as $item) {
$permName = "$group.$item";
$perm = Permission::firstWhere('name', $permName);
if (is_null($perm)) {
throw new RecordsNotFoundException("Could not find permission with name '$permName'");
}
$permissions[] = $perm->id;
}
}
$role->name = $properties->name;
$role->save();
$role->permissions()->sync($permissions);
});
}

public function destroy(array $match = [])
{
$this->destroyWrapper($match);
}
}

class ProvisioningService
{
public ServerProvisioner $server;
Expand All @@ -182,10 +226,13 @@ class ProvisioningService

public RoomTypeProvisioner $roomType;

public RoleProvisioner $role;

public function __construct()
{
$this->server = new ServerProvisioner;
$this->serverPool = new ServerPoolProvisioner;
$this->roomType = new RoomTypeProvisioner;
$this->role = new RoleProvisioner;
}
}
120 changes: 120 additions & 0 deletions tests/Backend/Unit/ProvisioningServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
namespace Tests\Backend\Unit;

use App\Enums\ServerStatus;
use App\Models\Role;
use App\Models\RoomType;
use App\Models\Server;
use App\Models\ServerPool;
use App\Services\ProvisioningService;
use Database\Seeders\RolesAndPermissionsSeeder;
use Illuminate\Database\RecordsNotFoundException;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\Backend\TestCase;
Expand All @@ -20,6 +22,8 @@ protected function setUp(): void
{
parent::setUp();

$this->seed(RolesAndPermissionsSeeder::class);

$this->svc = new ProvisioningService;

$this->testServer = (object) [
Expand All @@ -41,6 +45,47 @@ protected function setUp(): void
'color' => '#aaaaaa',
'server_pool' => $this->testServerPool->name,
];
$this->testRole = (object) [
'name' => 'Testrole',
'permissions' => [
'rooms' => [
'viewAll',
'manage',
],
'meetings' => [
'viewAny',
],
'settings' => [
'viewAny',
'update',
],
'users' => [
'viewAny',
'view',
'update',
'create',
'delete',
],
'roles' => [
'viewAny',
'view',
],
'roomTypes' => [
'view',
'update',
'create',
'delete',
],
'servers' => [
'viewAny',
'view',
],
'serverPools' => [
'viewAny',
'view',
],
],
];

for ($i = 1; $i <= 3; $i++) {
$server = new Server;
Expand Down Expand Up @@ -271,4 +316,79 @@ public function test_room_type_delete_named()
$this->assertNotNull(RoomType::firstWhere('name', "Existing {$this->testRoomType->name} 1"));
$this->assertNotNull(RoomType::firstWhere('name', "Existing {$this->testRoomType->name} 3"));
}

/**
* Test role creation
*/
public function test_role_create()
{
$this->svc->role->create($this->testRole);
$role = Role::firstWhere('name', $this->testRole->name);
$this->assertNotNull($role);
foreach ($this->testRole->permissions as $group => $perms) {
foreach ($perms as $perm) {
$wanted_permissions[] = "$group.$perm";
}
}
$saved_permissions = array_map(fn ($it) => $it->name, $role->permissions->all());
$this->assertEquals($wanted_permissions, $saved_permissions);
}

/**
* Test role creation with invalid permissions
*/
public function test_role_create_invalid()
{
$this->testRole->permissions['fnord'] = ['foo', 'bar'];
$this->expectException(UnexpectedValueException::class);
$this->expectExceptionMessage('Invalid role definition');
$this->svc->role->create($this->testRole);
$this->assertNull(Role::firstWhere('name', $this->testRole->name));
}

/**
* Test role creation with incomplete permissions spec
*/
public function test_role_create_incomplete()
{
unset($this->testRole->permissions['rooms']);
$this->expectException(UnexpectedValueException::class);
$this->expectExceptionMessage('Invalid role definition');
$this->svc->role->create($this->testRole);
$this->assertNull(Role::firstWhere('name', $this->testRole->name));
}

/**
* Test role creation with incomplete permissions spec
*/
public function test_role_create_non_existing_permission()
{
$this->testRole->permissions['rooms'] = ['show'];
$this->expectException(RecordsNotFoundException::class);
$this->expectExceptionMessage("Could not find permission with name 'rooms.show'");
$this->svc->role->create($this->testRole);
$this->assertNull(Role::firstWhere('name', $this->testRole->name));
}

/**
* Test deletion of all roles
*/
public function test_role_delete_all()
{
$this->assertEquals(2, count(Role::all()));
$this->svc->role->destroy();
$this->assertEquals(0, count(Role::all()));
}

/**
* Test deletion of specified role
*/
public function test_role_delete_named()
{
$this->assertEquals(2, count(Role::all()));
$this->svc->role->destroy(['name' => 'User']);
$this->assertEquals(1, count(Role::all()));
$this->assertNull(Role::firstWhere('name', 'User'));
$this->assertNotNull(Role::firstWhere('name', 'Superuser'));
}
}

0 comments on commit 85232a3

Please sign in to comment.