diff --git a/src/app/Console/Commands/Domain/StatusCommand.php b/src/app/Console/Commands/Domain/StatusCommand.php --- a/src/app/Console/Commands/Domain/StatusCommand.php +++ b/src/app/Console/Commands/Domain/StatusCommand.php @@ -35,29 +35,6 @@ return 1; } - $statuses = [ - 'active' => Domain::STATUS_ACTIVE, - 'suspended' => Domain::STATUS_SUSPENDED, - 'deleted' => Domain::STATUS_DELETED, - 'confirmed' => Domain::STATUS_CONFIRMED, - 'verified' => Domain::STATUS_VERIFIED, - 'ldapReady' => Domain::STATUS_LDAP_READY, - ]; - - $domain_state = []; - - foreach ($statuses as $text => $bit) { - if ($text == 'deleted') { - $status = $domain->trashed(); - } else { - $status = $domain->{'is' . \ucfirst($text)}(); - } - - if ($status) { - $domain_state[] = "$text ($bit)"; - } - } - - $this->info("Status ({$domain->status}): " . \implode(', ', $domain_state)); + $this->info("Status ({$domain->status}): " . $domain->statusText()); } } diff --git a/src/app/Console/Commands/User/InfoCommand.php b/src/app/Console/Commands/User/InfoCommand.php new file mode 100644 --- /dev/null +++ b/src/app/Console/Commands/User/InfoCommand.php @@ -0,0 +1,59 @@ +getUser($this->argument('email'), true); + + if (!$user) { + $this->error('User not found.'); + return 1; + } + + $props = ['id', 'email', 'created_at', 'updated_at', 'deleted_at']; + + foreach ($props as $prop) { + if (!empty($user->{$prop})) { + $this->info("{$prop}: " . $user->{$prop}); + } + } + + $this->info("status: {$user->status} (" . $user->statusText() . ")"); + + $user->settings()->orderBy('key')->each( + function ($setting) { + if ($setting->value !== null) { + $this->info("{$setting->key}: " . \str_replace("\n", ' ', $setting->value)); + } + } + ); + + // TODO: Display additional info (maybe with --all option): + // - wallet balance + // - tenant ID (and name) + // - if not an account owner, owner ID/email + // - if signup code available, IP address (other headers) + } +} diff --git a/src/app/Console/Commands/User/StatusCommand.php b/src/app/Console/Commands/User/StatusCommand.php --- a/src/app/Console/Commands/User/StatusCommand.php +++ b/src/app/Console/Commands/User/StatusCommand.php @@ -35,30 +35,6 @@ return 1; } - $statuses = [ - 'active' => User::STATUS_ACTIVE, - 'suspended' => User::STATUS_SUSPENDED, - 'deleted' => User::STATUS_DELETED, - 'ldapReady' => User::STATUS_LDAP_READY, - 'imapReady' => User::STATUS_IMAP_READY, - 'degraded' => User::STATUS_DEGRADED, - 'restricted' => User::STATUS_RESTRICTED, - ]; - - $user_state = []; - - foreach ($statuses as $text => $bit) { - if ($text == 'deleted') { - $status = $user->trashed(); - } else { - $status = $user->{'is' . \ucfirst($text)}(); - } - - if ($status) { - $user_state[] = "$text ($bit)"; - } - } - - $this->info("Status ({$user->status}): " . \implode(', ', $user_state)); + $this->info("Status ({$user->status}): " . $user->statusText()); } } diff --git a/src/app/Console/Development/DomainStatus.php b/src/app/Console/Development/DomainStatus.php deleted file mode 100644 --- a/src/app/Console/Development/DomainStatus.php +++ /dev/null @@ -1,75 +0,0 @@ -argument('domain'))->firstOrFail(); - - $statuses = [ - 'active' => Domain::STATUS_ACTIVE, - 'suspended' => Domain::STATUS_SUSPENDED, - 'deleted' => Domain::STATUS_DELETED, - 'ldapReady' => Domain::STATUS_LDAP_READY, - 'verified' => Domain::STATUS_VERIFIED, - 'confirmed' => Domain::STATUS_CONFIRMED, - ]; - - // I'd prefer "-state" and "+state" syntax, but it's not possible - $delete = false; - if ($update = $this->option('del')) { - $delete = true; - } elseif ($update = $this->option('add')) { - // do nothing - } - - if (!empty($update)) { - $map = \array_change_key_case($statuses); - $update = \strtolower($update); - - if (isset($map[$update])) { - if ($delete && $domain->status & $map[$update]) { - $domain->status ^= $map[$update]; - $domain->save(); - } elseif (!$delete && !($domain->status & $map[$update])) { - $domain->status |= $map[$update]; - $domain->save(); - } - } - } - - $domain_state = []; - foreach (\array_keys($statuses) as $state) { - $func = 'is' . \ucfirst($state); - if ($domain->$func()) { - $domain_state[] = $state; - } - } - - $this->info("Status: " . \implode(',', $domain_state)); - } -} diff --git a/src/app/Traits/StatusPropertyTrait.php b/src/app/Traits/StatusPropertyTrait.php --- a/src/app/Traits/StatusPropertyTrait.php +++ b/src/app/Traits/StatusPropertyTrait.php @@ -2,6 +2,8 @@ namespace App\Traits; +use Illuminate\Support\Str; + trait StatusPropertyTrait { /** @@ -64,6 +66,23 @@ return defined('static::STATUS_SUSPENDED') && ($this->status & static::STATUS_SUSPENDED) > 0; } + /** + * Returns object's statuses in a textual form + */ + public function statusText(): string + { + $reflection = new \ReflectionClass(get_class($this)); + $result = []; + + foreach ($reflection->getConstants() as $const => $value) { + if (str_starts_with($const, 'STATUS_') && ($this->status & $value) > 0) { + $result[] = Str::camel(strtolower(str_replace('STATUS_', '', $const))) . " ($value)"; + } + } + + return implode(', ', $result); + } + /** * Suspend this object. * diff --git a/src/tests/Feature/Console/Domain/StatusTest.php b/src/tests/Feature/Console/Domain/StatusTest.php --- a/src/tests/Feature/Console/Domain/StatusTest.php +++ b/src/tests/Feature/Console/Domain/StatusTest.php @@ -51,18 +51,15 @@ } // Test deleted domain - $user = $this->getTestUser('john@kolab.org'); $domain = $this->getTestDomain('domain-delete.com', [ 'status' => \App\Domain::STATUS_NEW, 'type' => \App\Domain::TYPE_HOSTED, ]); - $package_domain = \App\Package::where('title', 'domain-hosting')->first(); - $domain->assignPackage($package_domain, $user); $domain->delete(); $code = \Artisan::call("domain:status {$domain->namespace}"); $output = trim(\Artisan::output()); $this->assertSame(0, $code); - $this->assertSame("Status (1): deleted (8)", $output); + $this->assertSame("Status (1): new (1)", $output); } } diff --git a/src/tests/Feature/Console/User/InfoTest.php b/src/tests/Feature/Console/User/InfoTest.php new file mode 100644 --- /dev/null +++ b/src/tests/Feature/Console/User/InfoTest.php @@ -0,0 +1,59 @@ +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:info unknown"); + $output = trim(\Artisan::output()); + + $this->assertSame(1, $code); + $this->assertSame("User not found.", $output); + + // Test existing but soft-deleted user + $user = $this->getTestUser('user@force-delete.com', ['status' => \App\User::STATUS_NEW]); + $user->delete(); + + $code = \Artisan::call("user:info {$user->email}"); + $output = trim(\Artisan::output()); + + $this->assertSame(0, $code); + $this->assertStringContainsString("id: {$user->id}", $output); + $this->assertStringContainsString("email: {$user->email}", $output); + $this->assertStringContainsString("created_at: {$user->created_at}", $output); + $this->assertStringContainsString("deleted_at: {$user->deleted_at}", $output); + $this->assertStringContainsString("status: {$user->status}", $output); + $this->assertStringContainsString("currency: CHF", $output); + } +} diff --git a/src/tests/Feature/Console/User/StatusTest.php b/src/tests/Feature/Console/User/StatusTest.php --- a/src/tests/Feature/Console/User/StatusTest.php +++ b/src/tests/Feature/Console/User/StatusTest.php @@ -52,7 +52,7 @@ $output = trim(\Artisan::output()); $this->assertSame(0, $code); - $this->assertSame("Status (51): active (2), ldapReady (16), imapReady (32)", $output); + $this->assertSame("Status (51): new (1), active (2), ldapReady (16), imapReady (32)", $output); $user->status = User::STATUS_ACTIVE; $user->save(); @@ -63,6 +63,6 @@ $output = trim(\Artisan::output()); $this->assertSame(0, $code); - $this->assertSame("Status (2): active (2), deleted (8)", $output); + $this->assertSame("Status (2): active (2)", $output); } } diff --git a/src/tests/Unit/DomainTest.php b/src/tests/Unit/DomainTest.php --- a/src/tests/Unit/DomainTest.php +++ b/src/tests/Unit/DomainTest.php @@ -137,4 +137,33 @@ $this->assertSame($hash_code, $hash_code2); } + + /** + * Test domain statusText() + */ + public function testStatusText(): void + { + $domain = new Domain(); + + $this->assertSame('', $domain->statusText()); + + $domain->status = Domain::STATUS_NEW + | Domain::STATUS_ACTIVE + | Domain::STATUS_SUSPENDED + | Domain::STATUS_DELETED + | Domain::STATUS_CONFIRMED + | Domain::STATUS_VERIFIED + | Domain::STATUS_LDAP_READY; + + $expected = [ + 'new (1)', + 'suspended (4)', + 'deleted (8)', + 'confirmed (16)', + 'verified (32)', + 'ldapReady (64)', + ]; + + $this->assertSame(implode(', ', $expected), $domain->statusText()); + } } diff --git a/src/tests/Unit/UserTest.php b/src/tests/Unit/UserTest.php --- a/src/tests/Unit/UserTest.php +++ b/src/tests/Unit/UserTest.php @@ -136,4 +136,36 @@ ] ); } + + /** + * Test basic User funtionality + */ + public function testStatusText(): void + { + $user = new User(['email' => 'user@email.com']); + + $this->assertSame('', $user->statusText()); + + $user->status = User::STATUS_NEW + | User::STATUS_ACTIVE + | User::STATUS_SUSPENDED + | User::STATUS_DELETED + | User::STATUS_IMAP_READY + | User::STATUS_LDAP_READY + | User::STATUS_DEGRADED + | User::STATUS_RESTRICTED; + + $expected = [ + 'new (1)', + 'active (2)', + 'suspended (4)', + 'deleted (8)', + 'ldapReady (16)', + 'imapReady (32)', + 'degraded (64)', + 'restricted (128)', + ]; + + $this->assertSame(implode(', ', $expected), $user->statusText()); + } }