All checks were successful
Build MapleDeploy Coolify Image / build (push) Successful in 41s
160 lines
4.9 KiB
PHP
160 lines
4.9 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands\Mapledeploy;
|
|
|
|
use App\Enums\Role;
|
|
use App\Models\Team;
|
|
use App\Models\User;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Hash;
|
|
use Illuminate\Support\Facades\Validator;
|
|
use Illuminate\Support\Str;
|
|
use Illuminate\Validation\Rule;
|
|
|
|
class UserCreate extends Command
|
|
{
|
|
protected $signature = 'mapledeploy:user:create
|
|
{--email= : User email address}
|
|
{--name= : User display name}
|
|
{--admin : Create the first root admin user}
|
|
{--team-role=member : Root team role for non-admin users}';
|
|
|
|
protected $description = 'Create a Coolify user for MapleDeploy dashboard access management';
|
|
|
|
public function handle(): int
|
|
{
|
|
$password = $this->readPassword();
|
|
$input = [
|
|
'email' => $this->option('email'),
|
|
'name' => $this->option('name'),
|
|
'password' => $password,
|
|
'team_role' => $this->option('team-role'),
|
|
];
|
|
|
|
$validator = Validator::make($input, [
|
|
'email' => ['required', 'string', 'email', 'max:255'],
|
|
'name' => ['required', 'string', 'max:255'],
|
|
'password' => ['required', 'string', 'min:8'],
|
|
'team_role' => ['required', Rule::in([Role::ADMIN->value, Role::MEMBER->value])],
|
|
]);
|
|
|
|
if ($validator->fails()) {
|
|
return $this->failWith('INVALID_INPUT');
|
|
}
|
|
|
|
$input['email'] = Str::lower((string) $input['email']);
|
|
|
|
if (User::whereEmail($input['email'])->exists()) {
|
|
return $this->failWith('EMAIL_EXISTS');
|
|
}
|
|
|
|
if ($this->option('admin')) {
|
|
return $this->createAdmin($input);
|
|
}
|
|
|
|
return $this->createMember($input);
|
|
}
|
|
|
|
private function createAdmin(array $input): int
|
|
{
|
|
if (User::count() !== 0) {
|
|
return $this->failWith('USERS_ALREADY_EXIST');
|
|
}
|
|
|
|
$user = DB::transaction(function () use ($input) {
|
|
$user = (new User)->forceFill([
|
|
'id' => 0,
|
|
'name' => $input['name'],
|
|
'email' => $input['email'],
|
|
'password' => Hash::make($input['password']),
|
|
]);
|
|
$user->save();
|
|
$user->markEmailAsVerified();
|
|
|
|
$settings = instanceSettings();
|
|
$settings->is_registration_enabled = false;
|
|
$attributes = $settings->getAttributes();
|
|
if (array_key_exists('setup_token', $attributes)) {
|
|
$settings->setup_token = null;
|
|
}
|
|
if (array_key_exists('setup_callback_url', $attributes)) {
|
|
$settings->setup_callback_url = null;
|
|
}
|
|
$settings->save();
|
|
|
|
return $user;
|
|
});
|
|
|
|
return $this->succeedWithUser($user);
|
|
}
|
|
|
|
private function createMember(array $input): int
|
|
{
|
|
$rootTeam = Team::find(0);
|
|
if (! $rootTeam) {
|
|
return $this->failWith('ROOT_TEAM_MISSING');
|
|
}
|
|
|
|
$user = DB::transaction(function () use ($input, $rootTeam) {
|
|
$user = User::create([
|
|
'name' => $input['name'],
|
|
'email' => $input['email'],
|
|
'password' => Hash::make($input['password']),
|
|
]);
|
|
$user->markEmailAsVerified();
|
|
$this->deletePersonalTeams($user);
|
|
$user->teams()->syncWithoutDetaching([
|
|
$rootTeam->id => ['role' => $input['team_role']],
|
|
]);
|
|
|
|
return $user;
|
|
});
|
|
|
|
return $this->succeedWithUser($user);
|
|
}
|
|
|
|
private function deletePersonalTeams(User $user): void
|
|
{
|
|
// MapleDeploy branding: dashboard-managed users should only see the
|
|
// managed instance root team, not an empty personal Coolify team.
|
|
$personalTeams = Team::query()
|
|
->where('teams.id', '!=', 0)
|
|
->where('personal_team', true)
|
|
->whereHas('members', fn ($query) => $query->whereKey($user->id))
|
|
->get();
|
|
|
|
foreach ($personalTeams as $team) {
|
|
DB::table('team_user')
|
|
->where('team_id', $team->id)
|
|
->where('user_id', $user->id)
|
|
->delete();
|
|
DB::table('teams')->where('id', $team->id)->delete();
|
|
}
|
|
}
|
|
|
|
private function readPassword(): string
|
|
{
|
|
return rtrim((string) stream_get_contents(STDIN), "\n");
|
|
}
|
|
|
|
private function succeedWithUser(User $user): int
|
|
{
|
|
$this->line(json_encode([
|
|
'user' => [
|
|
'id' => $user->id,
|
|
'email' => $user->email,
|
|
'name' => $user->name,
|
|
],
|
|
], 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;
|
|
}
|
|
}
|