feat(coolify): delete mapledeploy users
All checks were successful
Build MapleDeploy Coolify Image / build (push) Successful in 1m26s
All checks were successful
Build MapleDeploy Coolify Image / build (push) Successful in 1m26s
This commit is contained in:
parent
bc67ddc40c
commit
5cd9357ebd
2 changed files with 130 additions and 0 deletions
61
app/Console/Commands/Mapledeploy/UserDelete.php
Normal file
61
app/Console/Commands/Mapledeploy/UserDelete.php
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands\Mapledeploy;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class UserDelete extends Command
|
||||
{
|
||||
protected $signature = 'mapledeploy:user:delete {user_id : Coolify user id}';
|
||||
|
||||
protected $description = 'Delete a Coolify user for MapleDeploy dashboard access management';
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$rawUserId = $this->argument('user_id');
|
||||
$userId = filter_var($rawUserId, FILTER_VALIDATE_INT, ['options' => ['min_range' => 0]]);
|
||||
if ($userId === false) {
|
||||
return $this->failWith('INVALID_USER_ID');
|
||||
}
|
||||
|
||||
if ($userId === 0) {
|
||||
return $this->failWith('CANNOT_DELETE_ROOT_USER');
|
||||
}
|
||||
|
||||
$user = User::find($userId);
|
||||
if (! $user) {
|
||||
$this->line(json_encode([
|
||||
'deleted' => null,
|
||||
'alreadyDeleted' => true,
|
||||
'id' => $userId,
|
||||
], JSON_THROW_ON_ERROR));
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
$deleted = [
|
||||
'id' => $user->id,
|
||||
'email' => $user->email,
|
||||
];
|
||||
|
||||
DB::transaction(function () use ($user) {
|
||||
$user->tokens()->delete();
|
||||
// MapleDeploy branding: deletion must end any active browser sessions.
|
||||
DB::table('sessions')->where('user_id', $user->id)->delete();
|
||||
$user->delete();
|
||||
});
|
||||
|
||||
$this->line(json_encode(['deleted' => $deleted], JSON_THROW_ON_ERROR));
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
private function failWith(string $code): int
|
||||
{
|
||||
$this->line(json_encode(['error' => $code], JSON_THROW_ON_ERROR));
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
}
|
||||
|
|
@ -238,6 +238,75 @@ function runMapledeployUserCommand(array $arguments, string $stdin = ''): array
|
|||
->and($memberUser->fresh()->remember_token)->toBeNull();
|
||||
});
|
||||
|
||||
test('MapleDeploy user delete command removes non-root users', function () {
|
||||
runMapledeployUserCommand([
|
||||
'mapledeploy:user:create',
|
||||
'--admin',
|
||||
'--email=owner@example.com',
|
||||
'--name=Owner',
|
||||
], "owner-password\n");
|
||||
|
||||
$member = runMapledeployUserCommand([
|
||||
'mapledeploy:user:create',
|
||||
'--email=delete-me@example.com',
|
||||
'--name=Delete Me',
|
||||
'--team-role=admin',
|
||||
], "member-password\n");
|
||||
$memberUser = User::findOrFail($member['json']['user']['id']);
|
||||
|
||||
DB::table('personal_access_tokens')->insert([
|
||||
'tokenable_type' => User::class,
|
||||
'tokenable_id' => $memberUser->id,
|
||||
'name' => 'delete-token',
|
||||
'token' => hash('sha256', 'delete-token'),
|
||||
'team_id' => '0',
|
||||
'abilities' => json_encode(['*'], JSON_THROW_ON_ERROR),
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
DB::table('sessions')->insert([
|
||||
'id' => 'delete-session',
|
||||
'user_id' => $memberUser->id,
|
||||
'ip_address' => '127.0.0.1',
|
||||
'user_agent' => 'Test Browser',
|
||||
'payload' => base64_encode('delete-payload'),
|
||||
'last_activity' => now()->timestamp,
|
||||
]);
|
||||
|
||||
$deleteRoot = runMapledeployUserCommand(['mapledeploy:user:delete', '0']);
|
||||
expect($deleteRoot['exitCode'])->toBe(1)
|
||||
->and($deleteRoot['json'])->toBe(['error' => 'CANNOT_DELETE_ROOT_USER']);
|
||||
|
||||
$invalid = runMapledeployUserCommand(['mapledeploy:user:delete', 'not-a-user-id']);
|
||||
expect($invalid['exitCode'])->toBe(1)
|
||||
->and($invalid['json'])->toBe(['error' => 'INVALID_USER_ID']);
|
||||
|
||||
$delete = runMapledeployUserCommand([
|
||||
'mapledeploy:user:delete',
|
||||
(string) $memberUser->id,
|
||||
]);
|
||||
|
||||
expect($delete['exitCode'])->toBe(0)
|
||||
->and($delete['json']['deleted'])->toBe([
|
||||
'id' => $memberUser->id,
|
||||
'email' => 'delete-me@example.com',
|
||||
])
|
||||
->and(User::find($memberUser->id))->toBeNull()
|
||||
->and(DB::table('personal_access_tokens')->where('tokenable_id', $memberUser->id)->count())->toBe(0)
|
||||
->and(DB::table('sessions')->where('user_id', $memberUser->id)->count())->toBe(0);
|
||||
|
||||
$missing = runMapledeployUserCommand([
|
||||
'mapledeploy:user:delete',
|
||||
(string) $memberUser->id,
|
||||
]);
|
||||
expect($missing['exitCode'])->toBe(0)
|
||||
->and($missing['json'])->toBe([
|
||||
'deleted' => null,
|
||||
'alreadyDeleted' => true,
|
||||
'id' => $memberUser->id,
|
||||
]);
|
||||
});
|
||||
|
||||
test('MapleDeploy password command can transfer root ownership identity', function () {
|
||||
runMapledeployUserCommand([
|
||||
'mapledeploy:user:create',
|
||||
|
|
|
|||
Loading…
Reference in a new issue