diff --git a/src/app/AuthAttempt.php b/src/app/AuthAttempt.php --- a/src/app/AuthAttempt.php +++ b/src/app/AuthAttempt.php @@ -65,10 +65,7 @@ */ public function isAccepted(): bool { - if ($this->status == self::STATUS_ACCEPTED && Carbon::now() < $this->expires_at) { - return true; - } - return false; + return $this->status == self::STATUS_ACCEPTED && Carbon::now() < $this->expires_at; } /** @@ -78,7 +75,7 @@ */ public function isDenied(): bool { - return ($this->status == self::STATUS_DENIED); + return $this->status == self::STATUS_DENIED; } /** @@ -183,6 +180,7 @@ if ($this->isAccepted()) { return true; } + if ($this->isDenied()) { return false; } diff --git a/src/app/Domain.php b/src/app/Domain.php --- a/src/app/Domain.php +++ b/src/app/Domain.php @@ -7,6 +7,7 @@ use App\Traits\DomainConfigTrait; use App\Traits\EntitleableTrait; use App\Traits\SettingsTrait; +use App\Traits\StatusPropertyTrait; use App\Traits\UuidIntKeyTrait; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; @@ -26,6 +27,7 @@ use EntitleableTrait; use SettingsTrait; use SoftDeletes; + use StatusPropertyTrait; use UuidIntKeyTrait; // we've simply never heard of this domain @@ -100,16 +102,6 @@ } /** - * Returns whether this domain is active. - * - * @return bool - */ - public function isActive(): bool - { - return ($this->status & self::STATUS_ACTIVE) > 0; - } - - /** * Returns whether this domain is confirmed the ownership of. * * @return bool @@ -120,16 +112,6 @@ } /** - * Returns whether this domain is deleted. - * - * @return bool - */ - public function isDeleted(): bool - { - return ($this->status & self::STATUS_DELETED) > 0; - } - - /** * Returns whether this domain is registered with us. * * @return bool @@ -150,16 +132,6 @@ } /** - * Returns whether this domain is new. - * - * @return bool - */ - public function isNew(): bool - { - return ($this->status & self::STATUS_NEW) > 0; - } - - /** * Returns whether this domain is public. * * @return bool @@ -170,26 +142,6 @@ } /** - * Returns whether this domain is registered in LDAP. - * - * @return bool - */ - public function isLdapReady(): bool - { - return ($this->status & self::STATUS_LDAP_READY) > 0; - } - - /** - * Returns whether this domain is suspended. - * - * @return bool - */ - public function isSuspended(): bool - { - return ($this->status & self::STATUS_SUSPENDED) > 0; - } - - /** * Returns whether this (external) domain has been verified * to exist in DNS. * @@ -372,21 +324,6 @@ } /** - * Suspend this domain. - * - * @return void - */ - public function suspend(): void - { - if ($this->isSuspended()) { - return; - } - - $this->status |= Domain::STATUS_SUSPENDED; - $this->save(); - } - - /** * Unsuspend this domain. * * The domain is unsuspended through either of the following courses of actions; diff --git a/src/app/Group.php b/src/app/Group.php --- a/src/app/Group.php +++ b/src/app/Group.php @@ -6,6 +6,7 @@ use App\Traits\EntitleableTrait; use App\Traits\GroupConfigTrait; use App\Traits\SettingsTrait; +use App\Traits\StatusPropertyTrait; use App\Traits\UuidIntKeyTrait; use App\Wallet; use Illuminate\Database\Eloquent\Model; @@ -28,6 +29,7 @@ use GroupConfigTrait; use SettingsTrait; use SoftDeletes; + use StatusPropertyTrait; use UuidIntKeyTrait; // we've simply never heard of this group @@ -99,56 +101,6 @@ } /** - * Returns whether this group is active. - * - * @return bool - */ - public function isActive(): bool - { - return ($this->status & self::STATUS_ACTIVE) > 0; - } - - /** - * Returns whether this group is deleted. - * - * @return bool - */ - public function isDeleted(): bool - { - return ($this->status & self::STATUS_DELETED) > 0; - } - - /** - * Returns whether this group is new. - * - * @return bool - */ - public function isNew(): bool - { - return ($this->status & self::STATUS_NEW) > 0; - } - - /** - * Returns whether this group is registered in LDAP. - * - * @return bool - */ - public function isLdapReady(): bool - { - return ($this->status & self::STATUS_LDAP_READY) > 0; - } - - /** - * Returns whether this group is suspended. - * - * @return bool - */ - public function isSuspended(): bool - { - return ($this->status & self::STATUS_SUSPENDED) > 0; - } - - /** * Ensure the email is appropriately cased. * * @param string $email Group email address @@ -171,65 +123,4 @@ $this->attributes['members'] = implode(',', $members); } - - /** - * Group status mutator - * - * @throws \Exception - */ - public function setStatusAttribute($status) - { - $new_status = 0; - - $allowed_values = [ - self::STATUS_NEW, - self::STATUS_ACTIVE, - self::STATUS_SUSPENDED, - self::STATUS_DELETED, - self::STATUS_LDAP_READY, - ]; - - foreach ($allowed_values as $value) { - if ($status & $value) { - $new_status |= $value; - $status ^= $value; - } - } - - if ($status > 0) { - throw new \Exception("Invalid group status: {$status}"); - } - - $this->attributes['status'] = $new_status; - } - - /** - * Suspend this group. - * - * @return void - */ - public function suspend(): void - { - if ($this->isSuspended()) { - return; - } - - $this->status |= Group::STATUS_SUSPENDED; - $this->save(); - } - - /** - * Unsuspend this group. - * - * @return void - */ - public function unsuspend(): void - { - if (!$this->isSuspended()) { - return; - } - - $this->status ^= Group::STATUS_SUSPENDED; - $this->save(); - } } diff --git a/src/app/Http/Controllers/API/V4/DomainsController.php b/src/app/Http/Controllers/API/V4/DomainsController.php --- a/src/app/Http/Controllers/API/V4/DomainsController.php +++ b/src/app/Http/Controllers/API/V4/DomainsController.php @@ -281,25 +281,6 @@ } /** - * Prepare domain statuses for the UI - * - * @param \App\Domain $domain Domain object - * - * @return array Statuses array - */ - protected static function objectState($domain): array - { - return [ - 'isLdapReady' => $domain->isLdapReady(), - 'isConfirmed' => $domain->isConfirmed(), - 'isVerified' => $domain->isVerified(), - 'isSuspended' => $domain->isSuspended(), - 'isActive' => $domain->isActive(), - 'isDeleted' => $domain->isDeleted() || $domain->trashed(), - ]; - } - - /** * Domain status (extended) information. * * @param \App\Domain $domain Domain object diff --git a/src/app/Http/Controllers/API/V4/GroupsController.php b/src/app/Http/Controllers/API/V4/GroupsController.php --- a/src/app/Http/Controllers/API/V4/GroupsController.php +++ b/src/app/Http/Controllers/API/V4/GroupsController.php @@ -227,23 +227,6 @@ } /** - * Prepare group statuses for the UI - * - * @param \App\Group $group Group object - * - * @return array Statuses array - */ - protected static function objectState($group): array - { - return [ - 'isLdapReady' => $group->isLdapReady(), - 'isSuspended' => $group->isSuspended(), - 'isActive' => $group->isActive(), - 'isDeleted' => $group->isDeleted() || $group->trashed(), - ]; - } - - /** * Validate an email address for use as a group email * * @param string $email Email address diff --git a/src/app/Http/Controllers/API/V4/ResourcesController.php b/src/app/Http/Controllers/API/V4/ResourcesController.php --- a/src/app/Http/Controllers/API/V4/ResourcesController.php +++ b/src/app/Http/Controllers/API/V4/ResourcesController.php @@ -25,23 +25,6 @@ /** - * Prepare resource statuses for the UI - * - * @param \App\Resource $resource Resource object - * - * @return array Statuses array - */ - protected static function objectState($resource): array - { - return [ - 'isLdapReady' => $resource->isLdapReady(), - 'isImapReady' => $resource->isImapReady(), - 'isActive' => $resource->isActive(), - 'isDeleted' => $resource->isDeleted() || $resource->trashed(), - ]; - } - - /** * Resource status (extended) information * * @param \App\Resource $resource Resource object diff --git a/src/app/Http/Controllers/API/V4/SharedFoldersController.php b/src/app/Http/Controllers/API/V4/SharedFoldersController.php --- a/src/app/Http/Controllers/API/V4/SharedFoldersController.php +++ b/src/app/Http/Controllers/API/V4/SharedFoldersController.php @@ -26,23 +26,6 @@ /** - * Prepare shared folder statuses for the UI - * - * @param \App\SharedFolder $folder Shared folder object - * - * @return array Statuses array - */ - protected static function objectState($folder): array - { - return [ - 'isLdapReady' => $folder->isLdapReady(), - 'isImapReady' => $folder->isImapReady(), - 'isActive' => $folder->isActive(), - 'isDeleted' => $folder->isDeleted() || $folder->trashed(), - ]; - } - - /** * SharedFolder status (extended) information * * @param \App\SharedFolder $folder SharedFolder object diff --git a/src/app/Http/Controllers/API/V4/UsersController.php b/src/app/Http/Controllers/API/V4/UsersController.php --- a/src/app/Http/Controllers/API/V4/UsersController.php +++ b/src/app/Http/Controllers/API/V4/UsersController.php @@ -427,15 +427,11 @@ */ protected static function objectState($user): array { - return [ - 'isImapReady' => $user->isImapReady(), - 'isLdapReady' => $user->isLdapReady(), - 'isSuspended' => $user->isSuspended(), - 'isActive' => $user->isActive(), - 'isDeleted' => $user->isDeleted() || $user->trashed(), - 'isDegraded' => $user->isDegraded(), - 'isAccountDegraded' => $user->isDegraded(true), - ]; + $state = parent::objectState($user); + + $state['isAccountDegraded'] = $user->isDegraded(true); + + return $state; } /** diff --git a/src/app/Http/Controllers/RelationController.php b/src/app/Http/Controllers/RelationController.php --- a/src/app/Http/Controllers/RelationController.php +++ b/src/app/Http/Controllers/RelationController.php @@ -86,7 +86,22 @@ */ protected static function objectState($resource): array { - return []; + $state = []; + + $reflect = new \ReflectionClass(get_class($resource)); + + foreach (array_keys($reflect->getConstants()) as $const) { + if (strpos($const, 'STATUS_') === 0 && $const != 'STATUS_NEW') { + $method = Str::camel('is_' . strtolower(substr($const, 7))); + $state[$method] = $resource->{$method}(); + } + } + + if (empty($state['isDeleted']) && method_exists($resource, 'trashed')) { + $state['isDeleted'] = $resource->trashed(); + } + + return $state; } /** diff --git a/src/app/Jobs/WalletCheck.php b/src/app/Jobs/WalletCheck.php --- a/src/app/Jobs/WalletCheck.php +++ b/src/app/Jobs/WalletCheck.php @@ -203,10 +203,7 @@ // Suspend the account $this->wallet->owner->suspend(); foreach ($this->wallet->entitlements as $entitlement) { - if ( - $entitlement->entitleable_type == \App\Domain::class - || $entitlement->entitleable_type == \App\User::class - ) { + if (method_exists($entitlement->entitleable_type, 'suspend')) { $entitlement->entitleable->suspend(); } } diff --git a/src/app/Observers/WalletObserver.php b/src/app/Observers/WalletObserver.php --- a/src/app/Observers/WalletObserver.php +++ b/src/app/Observers/WalletObserver.php @@ -99,10 +99,7 @@ // Un-suspend domains/users foreach ($wallet->entitlements as $entitlement) { - if ( - $entitlement->entitleable_type == \App\Domain::class - || $entitlement->entitleable_type == \App\User::class - ) { + if (method_exists($entitlement->entitleable_type, 'unsuspend')) { $entitlement->entitleable->unsuspend(); } } diff --git a/src/app/Resource.php b/src/app/Resource.php --- a/src/app/Resource.php +++ b/src/app/Resource.php @@ -6,6 +6,7 @@ use App\Traits\EntitleableTrait; use App\Traits\ResourceConfigTrait; use App\Traits\SettingsTrait; +use App\Traits\StatusPropertyTrait; use App\Traits\UuidIntKeyTrait; use App\Wallet; use Illuminate\Database\Eloquent\Model; @@ -27,6 +28,7 @@ use ResourceConfigTrait; use SettingsTrait; use SoftDeletes; + use StatusPropertyTrait; use UuidIntKeyTrait; // we've simply never heard of this resource @@ -92,85 +94,4 @@ return false; } - - /** - * Returns whether this resource is active. - * - * @return bool - */ - public function isActive(): bool - { - return ($this->status & self::STATUS_ACTIVE) > 0; - } - - /** - * Returns whether this resource is deleted. - * - * @return bool - */ - public function isDeleted(): bool - { - return ($this->status & self::STATUS_DELETED) > 0; - } - - /** - * Returns whether this resource's folder exists in IMAP. - * - * @return bool - */ - public function isImapReady(): bool - { - return ($this->status & self::STATUS_IMAP_READY) > 0; - } - - /** - * Returns whether this resource is registered in LDAP. - * - * @return bool - */ - public function isLdapReady(): bool - { - return ($this->status & self::STATUS_LDAP_READY) > 0; - } - - /** - * Returns whether this resource is new. - * - * @return bool - */ - public function isNew(): bool - { - return ($this->status & self::STATUS_NEW) > 0; - } - - /** - * Resource status mutator - * - * @throws \Exception - */ - public function setStatusAttribute($status) - { - $new_status = 0; - - $allowed_values = [ - self::STATUS_NEW, - self::STATUS_ACTIVE, - self::STATUS_DELETED, - self::STATUS_IMAP_READY, - self::STATUS_LDAP_READY, - ]; - - foreach ($allowed_values as $value) { - if ($status & $value) { - $new_status |= $value; - $status ^= $value; - } - } - - if ($status > 0) { - throw new \Exception("Invalid resource status: {$status}"); - } - - $this->attributes['status'] = $new_status; - } } diff --git a/src/app/SharedFolder.php b/src/app/SharedFolder.php --- a/src/app/SharedFolder.php +++ b/src/app/SharedFolder.php @@ -6,6 +6,7 @@ use App\Traits\EntitleableTrait; use App\Traits\SharedFolderConfigTrait; use App\Traits\SettingsTrait; +use App\Traits\StatusPropertyTrait; use App\Traits\UuidIntKeyTrait; use App\Wallet; use Illuminate\Database\Eloquent\Model; @@ -28,6 +29,7 @@ use SharedFolderConfigTrait; use SettingsTrait; use SoftDeletes; + use StatusPropertyTrait; use UuidIntKeyTrait; // we've simply never heard of this folder @@ -100,87 +102,6 @@ } /** - * Returns whether this folder is active. - * - * @return bool - */ - public function isActive(): bool - { - return ($this->status & self::STATUS_ACTIVE) > 0; - } - - /** - * Returns whether this folder is deleted. - * - * @return bool - */ - public function isDeleted(): bool - { - return ($this->status & self::STATUS_DELETED) > 0; - } - - /** - * Returns whether this folder exists in IMAP. - * - * @return bool - */ - public function isImapReady(): bool - { - return ($this->status & self::STATUS_IMAP_READY) > 0; - } - - /** - * Returns whether this folder is registered in LDAP. - * - * @return bool - */ - public function isLdapReady(): bool - { - return ($this->status & self::STATUS_LDAP_READY) > 0; - } - - /** - * Returns whether this folder is new. - * - * @return bool - */ - public function isNew(): bool - { - return ($this->status & self::STATUS_NEW) > 0; - } - - /** - * Folder status mutator - * - * @throws \Exception - */ - public function setStatusAttribute($status) - { - $new_status = 0; - - $allowed_values = [ - self::STATUS_NEW, - self::STATUS_ACTIVE, - self::STATUS_DELETED, - self::STATUS_IMAP_READY, - self::STATUS_LDAP_READY, - ]; - - foreach ($allowed_values as $value) { - if ($status & $value) { - $new_status |= $value; - $status ^= $value; - } - } - - if ($status > 0) { - throw new \Exception("Invalid shared folder status: {$status}"); - } - - $this->attributes['status'] = $new_status; - } - - /** * Folder type mutator * * @throws \Exception diff --git a/src/app/Traits/StatusPropertyTrait.php b/src/app/Traits/StatusPropertyTrait.php new file mode 100644 --- /dev/null +++ b/src/app/Traits/StatusPropertyTrait.php @@ -0,0 +1,134 @@ +status & static::STATUS_ACTIVE) > 0; + } + + /** + * Returns whether this object is deleted. + * + * @return bool + */ + public function isDeleted(): bool + { + return defined('static::STATUS_DELETED') && ($this->status & static::STATUS_DELETED) > 0; + } + + /** + * Returns whether this object is registered in IMAP. + * + * @return bool + */ + public function isImapReady(): bool + { + return defined('static::STATUS_IMAP_READY') && ($this->status & static::STATUS_IMAP_READY) > 0; + } + + /** + * Returns whether this object is registered in LDAP. + * + * @return bool + */ + public function isLdapReady(): bool + { + return defined('static::STATUS_LDAP_READY') && ($this->status & static::STATUS_LDAP_READY) > 0; + } + + /** + * Returns whether this object is new. + * + * @return bool + */ + public function isNew(): bool + { + return defined('static::STATUS_NEW') && ($this->status & static::STATUS_NEW) > 0; + } + + /** + * Returns whether this object is suspended. + * + * @return bool + */ + public function isSuspended(): bool + { + return defined('static::STATUS_SUSPENDED') && ($this->status & static::STATUS_SUSPENDED) > 0; + } + + /** + * Suspend this object. + * + * @return void + */ + public function suspend(): void + { + if (!defined('static::STATUS_SUSPENDED') || $this->isSuspended()) { + return; + } + + $this->status |= static::STATUS_SUSPENDED; + $this->save(); + } + + /** + * Unsuspend this object. + * + * @return void + */ + public function unsuspend(): void + { + if (!defined('static::STATUS_SUSPENDED') || !$this->isSuspended()) { + return; + } + + $this->status ^= static::STATUS_SUSPENDED; + $this->save(); + } + + /** + * Status property mutator + * + * @throws \Exception + */ + public function setStatusAttribute($status) + { + $new_status = 0; + + $allowed_states = [ + 'STATUS_NEW', + 'STATUS_ACTIVE', + 'STATUS_SUSPENDED', + 'STATUS_DELETED', + 'STATUS_LDAP_READY', + 'STATUS_IMAP_READY', + ]; + + foreach ($allowed_states as $const) { + if (!defined("static::$const")) { + continue; + } + + $value = constant("static::$const"); + + if ($status & $value) { + $new_status |= $value; + $status ^= $value; + } + } + + if ($status > 0) { + throw new \Exception("Invalid status: {$status}"); + } + + $this->attributes['status'] = $new_status; + } +} diff --git a/src/app/User.php b/src/app/User.php --- a/src/app/User.php +++ b/src/app/User.php @@ -9,6 +9,7 @@ use App\Traits\UserConfigTrait; use App\Traits\UuidIntKeyTrait; use App\Traits\SettingsTrait; +use App\Traits\StatusPropertyTrait; use App\Wallet; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Facades\DB; @@ -39,6 +40,7 @@ use UuidIntKeyTrait; use SettingsTrait; use SoftDeletes; + use StatusPropertyTrait; // a new user, default on creation public const STATUS_NEW = 1 << 0; @@ -409,16 +411,6 @@ } /** - * Returns whether this user is active. - * - * @return bool - */ - public function isActive(): bool - { - return ($this->status & self::STATUS_ACTIVE) > 0; - } - - /** * Returns whether this user (or its wallet owner) is degraded. * * @param bool $owner Check also the wallet owner instead just the user himself @@ -439,56 +431,6 @@ } /** - * Returns whether this user is deleted. - * - * @return bool - */ - public function isDeleted(): bool - { - return ($this->status & self::STATUS_DELETED) > 0; - } - - /** - * Returns whether this user is registered in IMAP. - * - * @return bool - */ - public function isImapReady(): bool - { - return ($this->status & self::STATUS_IMAP_READY) > 0; - } - - /** - * Returns whether this user is registered in LDAP. - * - * @return bool - */ - public function isLdapReady(): bool - { - return ($this->status & self::STATUS_LDAP_READY) > 0; - } - - /** - * Returns whether this user is new. - * - * @return bool - */ - public function isNew(): bool - { - return ($this->status & self::STATUS_NEW) > 0; - } - - /** - * Returns whether this user is suspended. - * - * @return bool - */ - public function isSuspended(): bool - { - return ($this->status & self::STATUS_SUSPENDED) > 0; - } - - /** * A shortcut to get the user name. * * @param bool $fallback Return " User" if there's no name @@ -575,21 +517,6 @@ } /** - * Suspend this user. - * - * @return void - */ - public function suspend(): void - { - if ($this->isSuspended()) { - return; - } - - $this->status |= User::STATUS_SUSPENDED; - $this->save(); - } - - /** * Un-degrade this user. * * @return void @@ -605,21 +532,6 @@ } /** - * Unsuspend this user. - * - * @return void - */ - public function unsuspend(): void - { - if (!$this->isSuspended()) { - return; - } - - $this->status ^= User::STATUS_SUSPENDED; - $this->save(); - } - - /** * Return users controlled by the current user. * * @param bool $with_accounts Include users assigned to wallets diff --git a/src/database/migrations/2022_01_03_120000_signup_codes_indices.php b/src/database/migrations/2022_01_03_120000_signup_codes_indices.php --- a/src/database/migrations/2022_01_03_120000_signup_codes_indices.php +++ b/src/database/migrations/2022_01_03_120000_signup_codes_indices.php @@ -34,9 +34,9 @@ Schema::table( 'signup_codes', function (Blueprint $table) { - $table->dropIndex('email'); - $table->dropIndex('ip_address'); - $table->dropIndex('expires_at'); + $table->dropIndex('signup_codes_email_index'); + $table->dropIndex('signup_codes_ip_address_index'); + $table->dropIndex('signup_codes_expires_at_index'); } ); } diff --git a/src/phpstan.neon b/src/phpstan.neon --- a/src/phpstan.neon +++ b/src/phpstan.neon @@ -7,6 +7,7 @@ - '#Call to an undefined [a-zA-Z0-9<>\\ ]+::withObjectTenantContext\(\)#' - '#Call to an undefined [a-zA-Z0-9<>\\ ]+::withSubjectTenantContext\(\)#' - '#Call to an undefined method Tests\\Browser::#' + - '#Access to undefined constant static\(App\\[a-zA-Z]+\)::STATUS_[A-Z_]+#' level: 4 parallel: processTimeout: 300.0