diff --git a/src/app/Console/Commands/UserAddAlias.php b/src/app/Console/Commands/User/AddAliasCommand.php similarity index 91% rename from src/app/Console/Commands/UserAddAlias.php rename to src/app/Console/Commands/User/AddAliasCommand.php index 59c4d62a..d891ec86 100644 --- a/src/app/Console/Commands/UserAddAlias.php +++ b/src/app/Console/Commands/User/AddAliasCommand.php @@ -1,59 +1,60 @@ getUser($this->argument('user')); if (!$user) { + $this->error("User not found."); return 1; } $alias = \strtolower($this->argument('alias')); // Check if the alias already exists if ($user->aliases()->where('alias', $alias)->first()) { $this->error("Address is already assigned to the user."); return 1; } $controller = $user->wallet()->owner; // Validate the alias $error = UsersController::validateAlias($alias, $controller); if ($error) { if (!$this->option('force')) { $this->error($error); return 1; } } $user->aliases()->create(['alias' => $alias]); } } diff --git a/src/app/Console/Commands/UserAssignSku.php b/src/app/Console/Commands/User/AssignSkuCommand.php similarity index 88% rename from src/app/Console/Commands/UserAssignSku.php rename to src/app/Console/Commands/User/AssignSkuCommand.php index e36d6188..6b316098 100644 --- a/src/app/Console/Commands/UserAssignSku.php +++ b/src/app/Console/Commands/User/AssignSkuCommand.php @@ -1,56 +1,56 @@ getUser($this->argument('user')); if (!$user) { - $this->error("Unable to find the user {$this->argument('user')}."); + $this->error("User not found."); return 1; } $sku = $this->getObject(\App\Sku::class, $this->argument('sku'), 'title'); if (!$sku) { $this->error("Unable to find the SKU {$this->argument('sku')}."); return 1; } $quantity = (int) $this->option('qty'); // Check if the entitlement already exists if (empty($quantity)) { if ($user->entitlements()->where('sku_id', $sku->id)->first()) { $this->error("The entitlement already exists. Maybe try with --qty=X?"); return 1; } } $user->assignSku($sku, $quantity ?: 1); } } diff --git a/src/app/Console/Commands/UserDomains.php b/src/app/Console/Commands/User/DomainsCommand.php similarity index 58% rename from src/app/Console/Commands/UserDomains.php rename to src/app/Console/Commands/User/DomainsCommand.php index ba2a0fc3..681a879c 100644 --- a/src/app/Console/Commands/UserDomains.php +++ b/src/app/Console/Commands/User/DomainsCommand.php @@ -1,40 +1,41 @@ getUser($this->argument('userid')); + $user = $this->getUser($this->argument('user')); if (!$user) { + $this->error("User not found."); return 1; } foreach ($user->domains() as $domain) { - $this->info("{$domain->namespace}"); + $this->info($domain->namespace); } } } diff --git a/src/app/Console/Commands/UserEntitlements.php b/src/app/Console/Commands/User/EntitlementsCommand.php similarity index 84% rename from src/app/Console/Commands/UserEntitlements.php rename to src/app/Console/Commands/User/EntitlementsCommand.php index e3253b88..331fe3ca 100644 --- a/src/app/Console/Commands/UserEntitlements.php +++ b/src/app/Console/Commands/User/EntitlementsCommand.php @@ -1,53 +1,52 @@ getUser($this->argument('userid')); if (!$user) { + $this->error("User not found."); return 1; } - $this->info("Found user: {$user->id}"); - $skus_counted = []; foreach ($user->entitlements as $entitlement) { if (!array_key_exists($entitlement->sku_id, $skus_counted)) { $skus_counted[$entitlement->sku_id] = 1; } else { $skus_counted[$entitlement->sku_id] += 1; } } foreach ($skus_counted as $id => $qty) { $sku = \App\Sku::find($id); - $this->info("SKU: {$sku->title} ({$qty})"); + $this->info("{$sku->title}: {$qty}"); } } } diff --git a/src/app/Console/Commands/UserForceDelete.php b/src/app/Console/Commands/User/ForceDeleteCommand.php similarity index 80% rename from src/app/Console/Commands/UserForceDelete.php rename to src/app/Console/Commands/User/ForceDeleteCommand.php index eb818d2a..03fba65b 100644 --- a/src/app/Console/Commands/UserForceDelete.php +++ b/src/app/Console/Commands/User/ForceDeleteCommand.php @@ -1,46 +1,47 @@ getUser($this->argument('user'), true); if (!$user) { + $this->error("User not found."); return 1; } if (!$user->trashed()) { - $this->error('The user is not yet deleted'); + $this->error("The user is not yet deleted."); return 1; } DB::beginTransaction(); $user->forceDelete(); DB::commit(); } } diff --git a/src/app/Console/Commands/User/GreylistCommand.php b/src/app/Console/Commands/User/GreylistCommand.php index 76710b44..59ecab6f 100644 --- a/src/app/Console/Commands/User/GreylistCommand.php +++ b/src/app/Console/Commands/User/GreylistCommand.php @@ -1,73 +1,63 @@ argument('user'); $recipientHash = hash('sha256', $recipientAddress); $lastConnect = \App\Policy\Greylist\Connect::where('recipient_hash', $recipientHash) ->orderBy('updated_at', 'desc') ->first(); if ($lastConnect) { $timestamp = $lastConnect->updated_at->copy(); $this->info("Going from timestamp (last connect) {$timestamp}"); } else { $timestamp = \Carbon\Carbon::now(); $this->info("Going from timestamp (now) {$timestamp}"); } \App\Policy\Greylist\Connect::where('recipient_hash', $recipientHash) ->where('greylisting', true) ->whereDate('updated_at', '>=', $timestamp->copy()->subDays(7)) ->orderBy('created_at')->each( function ($connect) { $this->info( sprintf( "From %s@%s since %s", $connect->sender_local, $connect->sender_domain, $connect->created_at ) ); } ); } } diff --git a/src/app/Console/Commands/UserRestore.php b/src/app/Console/Commands/User/RestoreCommand.php similarity index 81% rename from src/app/Console/Commands/UserRestore.php rename to src/app/Console/Commands/User/RestoreCommand.php index dbf8906b..f1fdac09 100644 --- a/src/app/Console/Commands/UserRestore.php +++ b/src/app/Console/Commands/User/RestoreCommand.php @@ -1,47 +1,47 @@ getUser($this->argument('user'), true); if (!$user) { - $this->error('User not found.'); + $this->error("User not found."); return 1; } if (!$user->trashed()) { - $this->error('The user is not yet deleted.'); + $this->error("The user is not deleted."); return 1; } DB::beginTransaction(); $user->restore(); DB::commit(); } } diff --git a/src/app/Console/Commands/UserDiscount.php b/src/app/Console/Commands/User/SetDiscountCommand.php similarity index 81% rename from src/app/Console/Commands/UserDiscount.php rename to src/app/Console/Commands/User/SetDiscountCommand.php index 5d85a822..2fae46dc 100644 --- a/src/app/Console/Commands/UserDiscount.php +++ b/src/app/Console/Commands/User/SetDiscountCommand.php @@ -1,58 +1,58 @@ getUser($this->argument('user')); if (!$user) { + $this->error("User not found."); return 1; } - $this->info("Found user {$user->id}"); - if ($this->argument('discount') === '0') { $discount = null; } else { $discount = $this->getObject(\App\Discount::class, $this->argument('discount')); if (!$discount) { + $this->error("Discount not found."); return 1; } } foreach ($user->wallets as $wallet) { if (!$discount) { $wallet->discount()->dissociate(); } else { $wallet->discount()->associate($discount); } $wallet->save(); } } } diff --git a/src/app/Console/Commands/User/StatusCommand.php b/src/app/Console/Commands/User/StatusCommand.php index 564d3944..402e6b27 100644 --- a/src/app/Console/Commands/User/StatusCommand.php +++ b/src/app/Console/Commands/User/StatusCommand.php @@ -1,71 +1,58 @@ withEnvTenantContext()->where('email', $this->argument('user'))->first(); - - if (!$user) { - $user = \App\User::withTrashed()->withEnvTenantContext()->where('id', $this->argument('user'))->first(); - } + $user = $this->getUser($this->argument('user'), true); if (!$user) { - $this->error("No such user '" . $this->argument('user') . "' within this tenant context."); - $this->info("Try ./artisan scalpel:user:read --attr=email --attr=tenant_id " . $this->argument('user')); + $this->error("User not found."); + $this->error("Try ./artisan scalpel:user:read --attr=email --attr=tenant_id " . $this->argument('user')); return 1; } $statuses = [ - 'active' => \App\User::STATUS_ACTIVE, - 'suspended' => \App\User::STATUS_SUSPENDED, - 'deleted' => \App\User::STATUS_DELETED, - 'ldapReady' => \App\User::STATUS_LDAP_READY, - 'imapReady' => \App\User::STATUS_IMAP_READY, + 'active' => User::STATUS_ACTIVE, + 'suspended' => User::STATUS_SUSPENDED, + 'deleted' => User::STATUS_DELETED, + 'ldapReady' => User::STATUS_LDAP_READY, + 'imapReady' => User::STATUS_IMAP_READY, ]; $user_state = []; foreach (\array_keys($statuses) as $state) { $func = 'is' . \ucfirst($state); if ($user->$func()) { $user_state[] = $state; } } $this->info("Status: " . \implode(',', $user_state)); } } diff --git a/src/app/Console/Commands/UserSuspend.php b/src/app/Console/Commands/User/SuspendCommand.php similarity index 81% rename from src/app/Console/Commands/UserSuspend.php rename to src/app/Console/Commands/User/SuspendCommand.php index c213d23b..6bcbfa63 100644 --- a/src/app/Console/Commands/UserSuspend.php +++ b/src/app/Console/Commands/User/SuspendCommand.php @@ -1,41 +1,39 @@ getUser($this->argument('user')); if (!$user) { + $this->error("User not found."); return 1; } - $this->info("Found user: {$user->id}"); - $user->suspend(); } } diff --git a/src/app/Console/Commands/UserUnsuspend.php b/src/app/Console/Commands/User/UnsuspendCommand.php similarity index 75% rename from src/app/Console/Commands/UserUnsuspend.php rename to src/app/Console/Commands/User/UnsuspendCommand.php index dbbd32e5..b18f157f 100644 --- a/src/app/Console/Commands/UserUnsuspend.php +++ b/src/app/Console/Commands/User/UnsuspendCommand.php @@ -1,40 +1,39 @@ getUser($this->argument('user')); if (!$user) { + $this->error("User not found."); return 1; } - $this->info("Found user {$user->id}"); - $user->unsuspend(); } } diff --git a/src/app/Console/Commands/UserVerify.php b/src/app/Console/Commands/User/VerifyCommand.php similarity index 76% rename from src/app/Console/Commands/UserVerify.php rename to src/app/Console/Commands/User/VerifyCommand.php index 5830bf3a..51ed99d5 100644 --- a/src/app/Console/Commands/UserVerify.php +++ b/src/app/Console/Commands/User/VerifyCommand.php @@ -1,41 +1,42 @@ getUser($this->argument('user')); if (!$user) { + $this->error("User not found."); return 1; } - $this->info("Found user: {$user->id}"); - $job = new \App\Jobs\User\VerifyJob($user->id); $job->handle(); + + // TODO: We should check the job result and print an error on failure } } diff --git a/src/app/Console/Commands/UserWallets.php b/src/app/Console/Commands/User/WalletsCommand.php similarity index 78% rename from src/app/Console/Commands/UserWallets.php rename to src/app/Console/Commands/User/WalletsCommand.php index f522efa8..065b5305 100644 --- a/src/app/Console/Commands/UserWallets.php +++ b/src/app/Console/Commands/User/WalletsCommand.php @@ -1,40 +1,41 @@ getUser($this->argument('user')); if (!$user) { + $this->error("User not found."); return 1; } foreach ($user->wallets as $wallet) { $this->info("{$wallet->id} {$wallet->description}"); } } } diff --git a/src/app/Console/Commands/UserDelete.php b/src/app/Console/Commands/UserDelete.php deleted file mode 100644 index eb74376f..00000000 --- a/src/app/Console/Commands/UserDelete.php +++ /dev/null @@ -1,38 +0,0 @@ -getUser($this->argument('user')); - - if (!$user) { - return 1; - } - - $user->delete(); - } -} diff --git a/src/tests/Feature/Console/DomainsTest.php b/src/tests/Feature/Console/DomainsTest.php index 9a8cc4ce..e908f011 100644 --- a/src/tests/Feature/Console/DomainsTest.php +++ b/src/tests/Feature/Console/DomainsTest.php @@ -1,27 +1,28 @@ first(); // Existing domain $code = \Artisan::call("domains"); $output = trim(\Artisan::output()); $this->assertSame(0, $code); $this->assertTrue(strpos($output, (string) $domain->id) !== false); // TODO: Test --deleted argument // TODO: Test output format and other attributes // TODO: Test tenant context + $this->markTestIncomplete(); } } diff --git a/src/tests/Feature/Console/UserRestoreTest.php b/src/tests/Feature/Console/User/AddAliasTest.php similarity index 62% copy from src/tests/Feature/Console/UserRestoreTest.php copy to src/tests/Feature/Console/User/AddAliasTest.php index 662b0fbd..0b6857b6 100644 --- a/src/tests/Feature/Console/UserRestoreTest.php +++ b/src/tests/Feature/Console/User/AddAliasTest.php @@ -1,80 +1,77 @@ deleteTestUser('user@force-delete.com'); $this->deleteTestDomain('force-delete.com'); } /** * {@inheritDoc} */ public function tearDown(): void { $this->deleteTestUser('user@force-delete.com'); $this->deleteTestDomain('force-delete.com'); parent::tearDown(); } /** * Test the command */ public function testHandle(): void { - Queue::fake(); - // Non-existing user - $code = \Artisan::call("user:restore unknown@unknown.org"); + $code = \Artisan::call("user:add-alias unknown unknown"); $output = trim(\Artisan::output()); + $this->assertSame(1, $code); $this->assertSame("User not found.", $output); - // Create a user account for delete $user = $this->getTestUser('user@force-delete.com'); $domain = $this->getTestDomain('force-delete.com', [ 'status' => \App\Domain::STATUS_NEW, 'type' => \App\Domain::TYPE_HOSTED, ]); $package_kolab = \App\Package::withEnvTenantContext()->where('title', 'kolab')->first(); $package_domain = \App\Package::withEnvTenantContext()->where('title', 'domain-hosting')->first(); $user->assignPackage($package_kolab); $domain->assignPackage($package_domain, $user); - $wallet = $user->wallets()->first(); - $entitlements = $wallet->entitlements->pluck('id')->all(); - - $this->assertCount(8, $entitlements); - // Non-deleted user - $code = \Artisan::call("user:restore {$user->email}"); + // Invalid alias + $code = \Artisan::call("user:add-alias {$user->email} invalid"); $output = trim(\Artisan::output()); - $this->assertSame(1, $code); - $this->assertSame("The user is not yet deleted.", $output); - - $user->delete(); - $this->assertTrue($user->trashed()); - $this->assertTrue($domain->fresh()->trashed()); + $this->assertSame(1, $code); + $this->assertSame("The specified alias is invalid.", $output); - // Deleted user - $code = \Artisan::call("user:restore {$user->email}"); + // Test success + $code = \Artisan::call("user:add-alias {$user->email} test@force-delete.com"); $output = trim(\Artisan::output()); + $this->assertSame(0, $code); $this->assertSame("", $output); + $this->assertCount(1, $user->aliases()->where('alias', 'test@force-delete.com')->get()); + + // Alias already exists + $code = \Artisan::call("user:add-alias {$user->email} test@force-delete.com"); + $output = trim(\Artisan::output()); + + $this->assertSame(1, $code); + $this->assertSame("Address is already assigned to the user.", $output); - $this->assertFalse($user->fresh()->trashed()); - $this->assertFalse($domain->fresh()->trashed()); + // TODO: test --force option } } diff --git a/src/tests/Feature/Console/UserAssignSkuTest.php b/src/tests/Feature/Console/User/AssignSkuTest.php similarity index 91% rename from src/tests/Feature/Console/UserAssignSkuTest.php rename to src/tests/Feature/Console/User/AssignSkuTest.php index 9905fe72..0ff6a5ee 100644 --- a/src/tests/Feature/Console/UserAssignSkuTest.php +++ b/src/tests/Feature/Console/User/AssignSkuTest.php @@ -1,63 +1,63 @@ deleteTestUser('add-entitlement@kolabnow.com'); } /** * {@inheritDoc} */ public function tearDown(): void { $this->deleteTestUser('add-entitlement@kolabnow.com'); parent::tearDown(); } /** * Test command runs */ public function testHandle(): void { $sku = \App\Sku::where('title', 'meet')->first(); $user = $this->getTestUser('add-entitlement@kolabnow.com'); $this->artisan('user:assign-sku unknown@unknown.org ' . $sku->id) ->assertExitCode(1) - ->expectsOutput("Unable to find the user unknown@unknown.org."); + ->expectsOutput("User not found."); $this->artisan('user:assign-sku ' . $user->email . ' unknownsku') ->assertExitCode(1) ->expectsOutput("Unable to find the SKU unknownsku."); $this->artisan('user:assign-sku ' . $user->email . ' ' . $sku->id) ->assertExitCode(0); $this->assertCount(1, $user->entitlements()->where('sku_id', $sku->id)->get()); // Try again (also test sku by title) $this->artisan('user:assign-sku ' . $user->email . ' ' . $sku->title) ->assertExitCode(1) ->expectsOutput("The entitlement already exists. Maybe try with --qty=X?"); $this->assertCount(1, $user->entitlements()->where('sku_id', $sku->id)->get()); // Try again with --qty option, to force the assignment $this->artisan('user:assign-sku ' . $user->email . ' ' . $sku->title . ' --qty=1') ->assertExitCode(0); $this->assertCount(2, $user->entitlements()->where('sku_id', $sku->id)->get()); } } diff --git a/src/tests/Feature/Console/User/DeleteTest.php b/src/tests/Feature/Console/User/DeleteTest.php new file mode 100644 index 00000000..c48cd3e1 --- /dev/null +++ b/src/tests/Feature/Console/User/DeleteTest.php @@ -0,0 +1,58 @@ +deleteTestUser('user@force-delete.com'); + } + + /** + * {@inheritDoc} + */ + public function tearDown(): void + { + $this->deleteTestUser('user@force-delete.com'); + + parent::tearDown(); + } + + /** + * Test the command + */ + public function testHandle(): void + { + // Non-existing user + $code = \Artisan::call("user:delete unknown"); + $output = trim(\Artisan::output()); + + $this->assertSame(1, $code); + $this->assertSame("No such user unknown", $output); + + $user = $this->getTestUser('user@force-delete.com'); + + // Test success + $code = \Artisan::call("user:delete {$user->email}"); + $output = trim(\Artisan::output()); + + $this->assertSame(0, $code); + $this->assertSame("", $output); + $this->assertTrue($user->fresh()->trashed()); + + // User already deleted + $code = \Artisan::call("user:delete {$user->email}"); + $output = trim(\Artisan::output()); + + $this->assertSame(1, $code); + $this->assertSame("No such user user@force-delete.com", $output); + } +} diff --git a/src/tests/Feature/Console/User/DomainsTest.php b/src/tests/Feature/Console/User/DomainsTest.php new file mode 100644 index 00000000..2ca6d3ad --- /dev/null +++ b/src/tests/Feature/Console/User/DomainsTest.php @@ -0,0 +1,27 @@ +assertSame(1, $code); + $this->assertSame("User not found.", $output); + + $code = \Artisan::call("user:domains john@kolab.org"); + $output = trim(\Artisan::output()); + + $this->assertSame(0, $code); + $this->assertTrue(strpos($output, "kolab.org") !== false); + $this->assertTrue(strpos($output, \config('app.domain')) !== false); + } +} diff --git a/src/tests/Feature/Console/User/EntitlementsTest.php b/src/tests/Feature/Console/User/EntitlementsTest.php new file mode 100644 index 00000000..fdb0c1de --- /dev/null +++ b/src/tests/Feature/Console/User/EntitlementsTest.php @@ -0,0 +1,28 @@ +assertSame(1, $code); + $this->assertSame("User not found.", $output); + + $code = \Artisan::call("user:entitlements john@kolab.org"); + $output = trim(\Artisan::output()); + + $this->assertSame(0, $code); + $this->assertTrue(strpos($output, "storage: 5") !== false); + $this->assertTrue(strpos($output, "mailbox: 1") !== false); + $this->assertTrue(strpos($output, "groupware: 1") !== false); + } +} diff --git a/src/tests/Feature/Console/UserForceDeleteTest.php b/src/tests/Feature/Console/User/ForceDeleteTest.php similarity index 97% rename from src/tests/Feature/Console/UserForceDeleteTest.php rename to src/tests/Feature/Console/User/ForceDeleteTest.php index 4b57ea5e..795bc3b7 100644 --- a/src/tests/Feature/Console/UserForceDeleteTest.php +++ b/src/tests/Feature/Console/User/ForceDeleteTest.php @@ -1,98 +1,98 @@ deleteTestUser('user@force-delete.com'); $this->deleteTestDomain('force-delete.com'); } /** * {@inheritDoc} */ public function tearDown(): void { $this->deleteTestUser('user@force-delete.com'); $this->deleteTestDomain('force-delete.com'); parent::tearDown(); } /** * Test the command */ public function testHandle(): void { // Non-existing user $this->artisan('user:force-delete unknown@unknown.org') ->assertExitCode(1); Queue::fake(); $user = $this->getTestUser('user@force-delete.com'); $domain = $this->getTestDomain('force-delete.com', [ 'status' => \App\Domain::STATUS_NEW, 'type' => \App\Domain::TYPE_HOSTED, ]); $package_kolab = \App\Package::withEnvTenantContext()->where('title', 'kolab')->first(); $package_domain = \App\Package::withEnvTenantContext()->where('title', 'domain-hosting')->first(); $user->assignPackage($package_kolab); $domain->assignPackage($package_domain, $user); $wallet = $user->wallets()->first(); $entitlements = $wallet->entitlements->pluck('id')->all(); $this->assertCount(8, $entitlements); // Non-deleted user $this->artisan('user:force-delete user@force-delete.com') ->assertExitCode(1); $user->delete(); $this->assertTrue($user->trashed()); $this->assertTrue($domain->fresh()->trashed()); // Deleted user $this->artisan('user:force-delete user@force-delete.com') ->assertExitCode(0); $this->assertCount( 0, \App\User::withTrashed()->where('email', 'user@force-delete.com')->get() ); $this->assertCount( 0, \App\Domain::withTrashed()->where('namespace', 'force-delete.com')->get() ); $this->assertCount( 0, \App\Wallet::where('id', $wallet->id)->get() ); $this->assertCount( 0, \App\Entitlement::withTrashed()->where('wallet_id', $wallet->id)->get() ); $this->assertCount( 0, \App\Entitlement::withTrashed()->where('entitleable_id', $user->id)->get() ); $this->assertCount( 0, \App\Transaction::whereIn('object_id', $entitlements) ->where('object_type', \App\Entitlement::class) ->get() ); // TODO: Test that it also deletes users in a group account } } diff --git a/src/tests/Feature/Console/UserDiscountTest.php b/src/tests/Feature/Console/User/GreylistTest.php similarity index 51% rename from src/tests/Feature/Console/UserDiscountTest.php rename to src/tests/Feature/Console/User/GreylistTest.php index 3e99362b..8b1c6fef 100644 --- a/src/tests/Feature/Console/UserDiscountTest.php +++ b/src/tests/Feature/Console/User/GreylistTest.php @@ -1,13 +1,16 @@ markTestIncomplete(); } } diff --git a/src/tests/Feature/Console/UserRestoreTest.php b/src/tests/Feature/Console/User/RestoreTest.php similarity index 94% rename from src/tests/Feature/Console/UserRestoreTest.php rename to src/tests/Feature/Console/User/RestoreTest.php index 662b0fbd..7f36dae4 100644 --- a/src/tests/Feature/Console/UserRestoreTest.php +++ b/src/tests/Feature/Console/User/RestoreTest.php @@ -1,80 +1,80 @@ deleteTestUser('user@force-delete.com'); $this->deleteTestDomain('force-delete.com'); } /** * {@inheritDoc} */ public function tearDown(): void { $this->deleteTestUser('user@force-delete.com'); $this->deleteTestDomain('force-delete.com'); parent::tearDown(); } /** * Test the command */ public function testHandle(): void { Queue::fake(); // Non-existing user $code = \Artisan::call("user:restore unknown@unknown.org"); $output = trim(\Artisan::output()); $this->assertSame(1, $code); $this->assertSame("User not found.", $output); // Create a user account for delete $user = $this->getTestUser('user@force-delete.com'); $domain = $this->getTestDomain('force-delete.com', [ 'status' => \App\Domain::STATUS_NEW, 'type' => \App\Domain::TYPE_HOSTED, ]); $package_kolab = \App\Package::withEnvTenantContext()->where('title', 'kolab')->first(); $package_domain = \App\Package::withEnvTenantContext()->where('title', 'domain-hosting')->first(); $user->assignPackage($package_kolab); $domain->assignPackage($package_domain, $user); $wallet = $user->wallets()->first(); $entitlements = $wallet->entitlements->pluck('id')->all(); $this->assertCount(8, $entitlements); // Non-deleted user $code = \Artisan::call("user:restore {$user->email}"); $output = trim(\Artisan::output()); $this->assertSame(1, $code); - $this->assertSame("The user is not yet deleted.", $output); + $this->assertSame("The user is not deleted.", $output); $user->delete(); $this->assertTrue($user->trashed()); $this->assertTrue($domain->fresh()->trashed()); // Deleted user $code = \Artisan::call("user:restore {$user->email}"); $output = trim(\Artisan::output()); $this->assertSame(0, $code); $this->assertSame("", $output); $this->assertFalse($user->fresh()->trashed()); $this->assertFalse($domain->fresh()->trashed()); } } diff --git a/src/tests/Feature/Console/User/SetDiscountTest.php b/src/tests/Feature/Console/User/SetDiscountTest.php new file mode 100644 index 00000000..90e173fb --- /dev/null +++ b/src/tests/Feature/Console/User/SetDiscountTest.php @@ -0,0 +1,64 @@ +deleteTestUser('wallets-controller@kolabnow.com'); + } + + /** + * {@inheritDoc} + */ + public function tearDown(): void + { + $this->deleteTestUser('wallets-controller@kolabnow.com'); + + parent::tearDown(); + } + + /** + * Test command runs + */ + public function testHandle(): void + { + $user = $this->getTestUser('wallets-controller@kolabnow.com'); + $wallet = $user->wallets()->first(); + $discount = \App\Discount::withObjectTenantContext($user)->where('discount', 100)->first(); + + // Invalid user id + $code = \Artisan::call("user:set-discount 123 123"); + $output = trim(\Artisan::output()); + $this->assertSame(1, $code); + $this->assertSame("User not found.", $output); + + // Invalid discount id + $code = \Artisan::call("user:set-discount {$user->id} 123"); + $output = trim(\Artisan::output()); + $this->assertSame(1, $code); + $this->assertSame("Discount not found.", $output); + + // Assign a discount + $code = \Artisan::call("user:set-discount {$user->id} {$discount->id}"); + $output = trim(\Artisan::output()); + $this->assertSame(0, $code); + $this->assertSame("", $output); + $this->assertSame($discount->id, $wallet->fresh()->discount_id); + + // Remove the discount + $code = \Artisan::call("user:set-discount {$user->id} 0"); + $output = trim(\Artisan::output()); + $this->assertSame(0, $code); + $this->assertSame("", $output); + $this->assertNull($wallet->fresh()->discount_id); + } +} diff --git a/src/tests/Feature/Console/User/StatusTest.php b/src/tests/Feature/Console/User/StatusTest.php new file mode 100644 index 00000000..b3f88d23 --- /dev/null +++ b/src/tests/Feature/Console/User/StatusTest.php @@ -0,0 +1,29 @@ +assertSame(1, $code); + $this->assertSame( + "User not found.\nTry ./artisan scalpel:user:read --attr=email --attr=tenant_id unknown", + $output + ); + + $code = \Artisan::call("user:status john@kolab.org"); + $output = trim(\Artisan::output()); + + $this->assertSame(0, $code); + $this->assertSame("Status: active,ldapReady,imapReady", $output); + } +} diff --git a/src/tests/Feature/Console/User/SuspendTest.php b/src/tests/Feature/Console/User/SuspendTest.php new file mode 100644 index 00000000..dd9d2586 --- /dev/null +++ b/src/tests/Feature/Console/User/SuspendTest.php @@ -0,0 +1,54 @@ +deleteTestUser('user@force-delete.com'); + } + + /** + * {@inheritDoc} + */ + public function tearDown(): void + { + $this->deleteTestUser('user@force-delete.com'); + + parent::tearDown(); + } + + /** + * Test the command + */ + public function testHandle(): void + { + Queue::fake(); + + // Non-existing user + $code = \Artisan::call("user:suspend unknown"); + $output = trim(\Artisan::output()); + + $this->assertSame(1, $code); + $this->assertSame("User not found.", $output); + + $user = $this->getTestUser('user@force-delete.com'); + + // Test success + $code = \Artisan::call("user:suspend {$user->email}"); + $output = trim(\Artisan::output()); + + $this->assertSame(0, $code); + $this->assertSame("", $output); + $this->assertTrue($user->fresh()->isSuspended()); + } +} diff --git a/src/tests/Feature/Console/User/UnsuspendTest.php b/src/tests/Feature/Console/User/UnsuspendTest.php new file mode 100644 index 00000000..d55ee736 --- /dev/null +++ b/src/tests/Feature/Console/User/UnsuspendTest.php @@ -0,0 +1,55 @@ +deleteTestUser('user@force-delete.com'); + } + + /** + * {@inheritDoc} + */ + public function tearDown(): void + { + $this->deleteTestUser('user@force-delete.com'); + + parent::tearDown(); + } + + /** + * Test the command + */ + public function testHandle(): void + { + Queue::fake(); + + // Non-existing user + $code = \Artisan::call("user:unsuspend unknown"); + $output = trim(\Artisan::output()); + + $this->assertSame(1, $code); + $this->assertSame("User not found.", $output); + + $user = $this->getTestUser('user@force-delete.com'); + $user->suspend(); + + // Test success + $code = \Artisan::call("user:unsuspend {$user->email}"); + $output = trim(\Artisan::output()); + + $this->assertSame(0, $code); + $this->assertSame("", $output); + $this->assertFalse($user->fresh()->isSuspended()); + } +} diff --git a/src/tests/Feature/Console/User/VerifyTest.php b/src/tests/Feature/Console/User/VerifyTest.php new file mode 100644 index 00000000..6cdb36ab --- /dev/null +++ b/src/tests/Feature/Console/User/VerifyTest.php @@ -0,0 +1,55 @@ +deleteTestUser('user@force-delete.com'); + } + + /** + * {@inheritDoc} + */ + public function tearDown(): void + { + $this->deleteTestUser('user@force-delete.com'); + + parent::tearDown(); + } + + /** + * Test the command + */ + public function testHandle(): void + { + Queue::fake(); + + // Non-existing user + $code = \Artisan::call("user:verify unknown"); + $output = trim(\Artisan::output()); + + $this->assertSame(1, $code); + $this->assertSame("User not found.", $output); + + $user = $this->getTestUser('user@force-delete.com'); + + // Test success + $code = \Artisan::call("user:verify {$user->email}"); + $output = trim(\Artisan::output()); + + $this->assertSame(0, $code); + $this->assertSame("", $output); + + // TODO: Test the verification utility error conditions + } +} diff --git a/src/tests/Feature/Console/User/WalletsTest.php b/src/tests/Feature/Console/User/WalletsTest.php new file mode 100644 index 00000000..c3c6f29b --- /dev/null +++ b/src/tests/Feature/Console/User/WalletsTest.php @@ -0,0 +1,29 @@ +assertSame(1, $code); + $this->assertSame("User not found.", $output); + + $user = $this->getTestUser('john@kolab.org'); + $wallet = $user->wallets()->first(); + + $code = \Artisan::call("user:wallets john@kolab.org"); + $output = trim(\Artisan::output()); + + $this->assertSame(0, $code); + $this->assertSame(trim("{$wallet->id} {$wallet->description}"), $output); + } +} diff --git a/src/tests/Feature/Console/UserDomainsTest.php b/src/tests/Feature/Console/UserDomainsTest.php deleted file mode 100644 index 6e9bdafe..00000000 --- a/src/tests/Feature/Console/UserDomainsTest.php +++ /dev/null @@ -1,16 +0,0 @@ -artisan('user:domains john@kolab.org') - ->assertExitCode(0); - - $this->markTestIncomplete(); - } -} diff --git a/src/tests/Feature/Console/UserEntitlementsTest.php b/src/tests/Feature/Console/UserEntitlementsTest.php deleted file mode 100644 index 1a421886..00000000 --- a/src/tests/Feature/Console/UserEntitlementsTest.php +++ /dev/null @@ -1,16 +0,0 @@ -artisan('user:entitlements john@kolab.org') - ->assertExitCode(0); - - $this->markTestIncomplete(); - } -} diff --git a/src/tests/Feature/Console/UserSettingsTest.php b/src/tests/Feature/Console/UserSettingsTest.php new file mode 100644 index 00000000..a9aa0e0d --- /dev/null +++ b/src/tests/Feature/Console/UserSettingsTest.php @@ -0,0 +1,22 @@ +assertSame(0, $code); + + // Test the output and extra arguments + $this->markTestIncomplete(); + } +} diff --git a/src/tests/Feature/Console/UserWalletsTest.php b/src/tests/Feature/Console/UserWalletsTest.php deleted file mode 100644 index 7e3e723a..00000000 --- a/src/tests/Feature/Console/UserWalletsTest.php +++ /dev/null @@ -1,16 +0,0 @@ -artisan('user:wallets john@kolab.org') - ->assertExitCode(0); - - $this->markTestIncomplete(); - } -} diff --git a/src/tests/Feature/Console/DomainsTest.php b/src/tests/Feature/Console/UsersTest.php similarity index 57% copy from src/tests/Feature/Console/DomainsTest.php copy to src/tests/Feature/Console/UsersTest.php index 9a8cc4ce..7a966d9f 100644 --- a/src/tests/Feature/Console/DomainsTest.php +++ b/src/tests/Feature/Console/UsersTest.php @@ -1,27 +1,28 @@ first(); + $john = $this->getTestUser('john@kolab.org'); // Existing domain - $code = \Artisan::call("domains"); + $code = \Artisan::call("users"); $output = trim(\Artisan::output()); $this->assertSame(0, $code); - $this->assertTrue(strpos($output, (string) $domain->id) !== false); + $this->assertTrue(strpos($output, (string) $john->id) !== false); // TODO: Test --deleted argument // TODO: Test output format and other attributes // TODO: Test tenant context + $this->markTestIncomplete(); } }