diff --git a/src/app/Console/Commands/User/CreateCommand.php b/src/app/Console/Commands/User/CreateCommand.php index 95e2c648..2938372c 100644 --- a/src/app/Console/Commands/User/CreateCommand.php +++ b/src/app/Console/Commands/User/CreateCommand.php @@ -1,152 +1,151 @@ argument('email'); $packages = $this->option('package'); $password = $this->option('password'); $role = $this->option('role'); $existingDeletedUser = null; $packagesToAssign = []; if ($role === User::ROLE_ADMIN || $role === User::ROLE_RESELLER) { if ($error = $this->validateUserWithRole($email)) { $this->error($error); return 1; } // TODO: Assigning user to an existing account // TODO: Making him an operator of the reseller wallet } else { list($local, $domainName) = explode('@', $email, 2); $domain = $this->getDomain($domainName); if (!$domain) { $this->error("No such domain {$domainName}."); return 1; } - if ($domain->isPublic()) { - $this->error("Domain {$domainName} is public."); - return 1; - } - - $owner = $domain->wallet()->owner; - - // Validate email address - if ($error = UsersController::validateEmail($email, $owner, $existingDeletedUser)) { - $this->error("{$email}: {$error}"); - return 1; + if (!$domain->isPublic()) { + $owner = $domain->wallet()->owner; } foreach ($packages as $package) { $userPackage = $this->getObject(\App\Package::class, $package, 'title', false); if (!$userPackage) { $this->error("Invalid package: {$package}"); return 1; } $packagesToAssign[] = $userPackage; } } if (!$password) { $password = \App\Utils::generatePassphrase(); } try { $user = new \App\User(); $user->email = $email; $user->password = $password; $user->role = $role; } catch (\Exception $e) { $this->error($e->getMessage()); return 1; } + if (empty($owner)) { + $owner = $user; + } + + if ($role != User::ROLE_ADMIN && $role != User::ROLE_RESELLER) { + // Validate email address + if ($error = UsersController::validateEmail($email, $owner, $existingDeletedUser)) { + $this->error("{$email}: {$error}"); + return 1; + } + } + DB::beginTransaction(); if ($existingDeletedUser) { $this->info("Force deleting existing but deleted user {$email}"); $existingDeletedUser->forceDelete(); } $user->save(); - if (empty($owner)) { - $owner = $user; - } - foreach ($packagesToAssign as $package) { $owner->assignPackage($package, $user); } DB::commit(); $this->info((string) $user->id); } /** * Validate email address for a new admin/reseller user * * @param string $email Email address * * @return ?string Error message */ protected function validateUserWithRole($email): ?string { // Validate the email address (basicly just the syntax) $v = Validator::make( ['email' => $email], ['email' => ['required', new ExternalEmail()]] ); if ($v->fails()) { return $v->errors()->toArray()['email'][0]; } // Check if an email is already taken if ( User::emailExists($email, true) || User::aliasExists($email) || \App\Group::emailExists($email, true) || \App\Resource::emailExists($email, true) || \App\SharedFolder::emailExists($email, true) || \App\SharedFolder::aliasExists($email) ) { return "Email address is already in use"; } return null; } } diff --git a/src/tests/Feature/Console/User/CreateTest.php b/src/tests/Feature/Console/User/CreateTest.php index 338d81ad..b227d214 100644 --- a/src/tests/Feature/Console/User/CreateTest.php +++ b/src/tests/Feature/Console/User/CreateTest.php @@ -1,116 +1,119 @@ deleteTestUser('user@kolab.org'); + $this->deleteTestUser('user@kolabnow.com'); $this->deleteTestUser('admin@kolab.org'); $this->deleteTestUser('reseller@unknown.domain.tld'); } /** * {@inheritDoc} */ public function tearDown(): void { $this->deleteTestUser('user@kolab.org'); + $this->deleteTestUser('user@kolabnow.com'); $this->deleteTestUser('admin@kolab.org'); $this->deleteTestUser('reseller@unknown.domain.tld'); parent::tearDown(); } /** * Test the command */ public function testHandle(): void { Queue::fake(); // Warning: We're not using artisan() here, as this will not // allow us to test "empty output" cases // Invalid email $code = \Artisan::call("user:create jack..test@kolab.org"); $output = trim(\Artisan::output()); $this->assertSame(1, $code); $this->assertSame("jack..test@kolab.org: The specified email is invalid.", $output); // Non-existing domain $code = \Artisan::call("user:create jack@kolab"); $output = trim(\Artisan::output()); $this->assertSame(1, $code); $this->assertSame("No such domain kolab.", $output); // Existing email $code = \Artisan::call("user:create jack@kolab.org"); $output = trim(\Artisan::output()); $this->assertSame(1, $code); $this->assertSame("jack@kolab.org: The specified email is not available.", $output); // Existing email (of a user alias) $code = \Artisan::call("user:create jack.daniels@kolab.org"); $output = trim(\Artisan::output()); $this->assertSame(1, $code); $this->assertSame("jack.daniels@kolab.org: The specified email is not available.", $output); - // Public domain not allowed in the group email address - $code = \Artisan::call("user:create user@kolabnow.com"); - $output = trim(\Artisan::output()); - $this->assertSame(1, $code); - $this->assertSame("Domain kolabnow.com is public.", $output); - // Valid (user) $code = \Artisan::call("user:create user@kolab.org --package=kolab"); $output = trim(\Artisan::output()); $user = User::where('email', 'user@kolab.org')->first(); $this->assertSame(0, $code); $this->assertEquals($user->id, $output); $this->assertSame(1, $user->countEntitlementsBySku('mailbox')); $this->assertSame(1, $user->countEntitlementsBySku('groupware')); $this->assertSame(5, $user->countEntitlementsBySku('storage')); // Valid (admin) $code = \Artisan::call("user:create admin@kolab.org --role=admin --password=simple123"); $output = trim(\Artisan::output()); $user = User::where('email', 'admin@kolab.org')->first(); $this->assertSame(0, $code); $this->assertEquals($user->id, $output); $this->assertEquals($user->role, User::ROLE_ADMIN); // Valid (reseller) $code = \Artisan::call("user:create reseller@unknown.domain.tld --role=reseller --password=simple123"); $output = trim(\Artisan::output()); $user = User::where('email', 'reseller@unknown.domain.tld')->first(); $this->assertSame(0, $code); $this->assertEquals($user->id, $output); $this->assertEquals($user->role, User::ROLE_RESELLER); + // Valid (public domain) + $code = \Artisan::call("user:create user@kolabnow.com"); + $output = trim(\Artisan::output()); + $user = User::where('email', 'user@kolabnow.com')->first(); + $this->assertSame(0, $code); + $this->assertEquals($user->id, $output); + // Invalid role $code = \Artisan::call("user:create unknwon@kolab.org --role=unknown"); $output = trim(\Artisan::output()); $this->assertSame(1, $code); $this->assertSame("Invalid role: unknown", $output); // Existing email (but with role-reseller) $code = \Artisan::call("user:create jack@kolab.org --role=reseller"); $output = trim(\Artisan::output()); $user = User::where('email', 'reseller@unknown.domain.tld')->first(); $this->assertSame(1, $code); $this->assertEquals("Email address is already in use", $output); // TODO: Test a case where deleted user exists } }