Skip to content

Commit

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

// Add new instances
Log::notice('Provisioning {n} servers', ['n' => count($data->servers->add)]);
Expand All @@ -69,5 +72,10 @@ public function handle()
$item->permissions = (array) $item->permissions;
$this->provision->role->create($item);
}

Log::notice('Provisioning {n} users', ['n' => count($data->users->add)]);
foreach ($data->users->add as $item) {
$this->provision->user->create($item);
}
}
}
43 changes: 41 additions & 2 deletions app/Services/ProvisioningService.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use App\Models\RoomType;
use App\Models\Server;
use App\Models\ServerPool;
use App\Models\User;
use Illuminate\Database\RecordsNotFoundException;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
Expand All @@ -31,7 +32,8 @@ protected function modelName()

protected function createWrapper(object $properties, callable $callback)
{
Log::notice("Provisioning {$this->modelName()} '$properties->name'");
$name = $properties->name ?? "$properties->firstname $properties->lastname";
Log::notice("Provisioning {$this->modelName()} '$name'");
$validator = Validator::make((array) $properties, $this->expectedProperties);
if ($validator->fails()) {
throw new UnexpectedValueException("Invalid {$this->modelName()} definition");
Expand All @@ -58,7 +60,8 @@ protected function destroyWrapper(array $match, ?callable $callback = null)
$callback($item);
}
if (! $item->delete()) {
Log::error("Failed to delete {$this->modelName()} '$item->name'");
$name = $item->name ?? "$item->firstname $item->lastname";
Log::error("Failed to delete {$this->modelName()} '$name'");
}
}
}
Expand Down Expand Up @@ -218,6 +221,39 @@ public function destroy(array $match = [])
}
}

class UserProvisioner extends AbstractProvisioner
{
protected string $model = User::class;

protected array $expectedProperties = [
'firstname' => 'required|string',
'lastname' => 'required|string',
'email' => 'required|string',
'password' => 'required|string',
'authenticator' => 'required|string',
'locale' => 'required|string',
'timezone' => 'required|string',
];

public function create(object $properties)
{
$this->createWrapper($properties, function ($user) use ($properties) {
$user->firstname = $properties->firstname;
$user->lastname = $properties->lastname;
$user->email = $properties->email;
$user->password = \Hash::make($properties->password);
$user->authenticator = $properties->authenticator;
$user->locale = $properties->locale;
$user->timezone = $properties->timezone;
});
}

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

class ProvisioningService
{
public ServerProvisioner $server;
Expand All @@ -228,11 +264,14 @@ class ProvisioningService

public RoleProvisioner $role;

public UserProvisioner $user;

public function __construct()
{
$this->server = new ServerProvisioner;
$this->serverPool = new ServerPoolProvisioner;
$this->roomType = new RoomTypeProvisioner;
$this->role = new RoleProvisioner;
$this->user = new UserProvisioner;
}
}
80 changes: 80 additions & 0 deletions tests/Backend/Unit/ProvisioningServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use App\Models\RoomType;
use App\Models\Server;
use App\Models\ServerPool;
use App\Models\User;
use App\Services\ProvisioningService;
use Database\Seeders\RolesAndPermissionsSeeder;
use Illuminate\Database\RecordsNotFoundException;
Expand Down Expand Up @@ -86,6 +87,15 @@ protected function setUp(): void
],
],
];
$this->testUser = (object) [
'firstname' => 'Maurice',
'lastname' => 'Moss',
'email' => '[email protected]',
'password' => 'Xuper$3cre7',
'authenticator' => 'local',
'locale' => 'en',
'timezone' => 'Europe/London',
];

for ($i = 1; $i <= 3; $i++) {
$server = new Server;
Expand All @@ -106,6 +116,16 @@ protected function setUp(): void
$roomType->color = $this->testRoomType->color;
$roomType->serverPool()->associate($serverPool);
$roomType->save();

$user = new User;
$user->firstname = "{$this->testUser->firstname} $i";
$user->lastname = $this->testUser->lastname;
$user->email = $this->testUser->email;
$user->password = \Hash::make($this->testUser->password);
$user->authenticator = $this->testUser->authenticator;
$user->locale = $this->testUser->locale;
$user->timezone = $this->testUser->timezone;
$user->save();
}
}

Expand Down Expand Up @@ -391,4 +411,64 @@ public function test_role_delete_named()
$this->assertNull(Role::firstWhere('name', 'User'));
$this->assertNotNull(Role::firstWhere('name', 'Superuser'));
}

/**
* Test user creation
*/
public function test_user_create()
{
$this->svc->user->create($this->testUser);
$user = User::where('firstname', $this->testUser->firstname)->where('lastname', $this->testUser->lastname)->first();
$this->assertEquals($this->testUser->email, $user->email);
$this->assertTrue(str_starts_with($user->password, '$2y$04$'));
$this->assertEquals($this->testUser->authenticator, $user->authenticator);
$this->assertEquals($this->testUser->locale, $user->locale);
$this->assertEquals($this->testUser->timezone, $user->timezone);
}

/**
* Test user creation with incomplete permissions spec
*/
public function test_user_create_incomplete()
{
unset($this->testUser->password);
$this->expectException(UnexpectedValueException::class);
$this->expectExceptionMessage('Invalid user definition');
$this->svc->user->create($this->testUser);
$this->assertNull(User::where('firstname', $this->testUser->firstname)->where('lastname', $this->testUser->lastname)->first());
}

/**
* Test deletion of all users
*/
public function test_user_delete_all()
{
$this->assertEquals(3, count(User::all()));
$this->svc->user->destroy();
$this->assertEquals(0, count(User::all()));
}

/**
* Test deletion of specified user
*/
public function test_user_delete_named()
{
$this->assertEquals(3, count(User::all()));
$this->svc->user->destroy([
'firstname' => "{$this->testUser->firstname} 2", 'lastname' => $this->testUser->lastname,
]);
$this->assertEquals(2, count(User::all()));
$this->assertNull(
User::where('firstname', "{$this->testUser->firstname} 2")
->where('lastname', $this->testUser->lastname)->first()
);
$this->assertNotNull(
User::where('firstname', "{$this->testUser->firstname} 1")
->where('lastname', $this->testUser->lastname)->first()
);
$this->assertNotNull(
User::where('firstname', "{$this->testUser->firstname} 3")
->where('lastname', $this->testUser->lastname)->first()
);
}
}

0 comments on commit d651dbf

Please sign in to comment.