diff --git a/src/app/Console/Commands/Domain/SetWalletCommand.php b/src/app/Console/Commands/Domain/SetWalletCommand.php --- a/src/app/Console/Commands/Domain/SetWalletCommand.php +++ b/src/app/Console/Commands/Domain/SetWalletCommand.php @@ -45,8 +45,8 @@ return 1; } - if ($domain->entitlement) { - $this->error("Domain already assigned to a wallet: {$domain->entitlement->wallet->id}."); + if ($entitlement = $domain->entitlements()->first()) { + $this->error("Domain already assigned to a wallet: {$entitlement->wallet->id}."); return 1; } diff --git a/src/app/Domain.php b/src/app/Domain.php --- a/src/app/Domain.php +++ b/src/app/Domain.php @@ -3,10 +3,11 @@ namespace App; use App\Wallet; -use App\Traits\UuidIntKeyTrait; use App\Traits\BelongsToTenantTrait; +use App\Traits\EntitleableTrait; use App\Traits\DomainConfigTrait; use App\Traits\SettingsTrait; +use App\Traits\UuidIntKeyTrait; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; @@ -20,11 +21,12 @@ */ class Domain extends Model { - use UuidIntKeyTrait; use BelongsToTenantTrait; + use EntitleableTrait; use DomainConfigTrait; use SettingsTrait; use SoftDeletes; + use UuidIntKeyTrait; // we've simply never heard of this domain public const STATUS_NEW = 1 << 0; @@ -104,27 +106,6 @@ return $this; } - /** - * The domain entitlement. - * - * @return \Illuminate\Database\Eloquent\Relations\MorphOne - */ - public function entitlement() - { - return $this->morphOne('App\Entitlement', 'entitleable'); - } - - /** - * Entitlements for this domain. - * - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function entitlements() - { - return $this->hasMany('App\Entitlement', 'entitleable_id', 'id') - ->where('entitleable_type', Domain::class); - } - /** * Return list of public+active domain names (for current tenant) */ @@ -526,17 +507,4 @@ return false; } - - /** - * Returns the wallet by which the domain is controlled - * - * @return \App\Wallet A wallet object - */ - public function wallet(): ?Wallet - { - // Note: Not all domains have a entitlement/wallet - $entitlement = $this->entitlement()->withTrashed()->orderBy('created_at', 'desc')->first(); - - return $entitlement ? $entitlement->wallet : null; - } } diff --git a/src/app/Group.php b/src/app/Group.php --- a/src/app/Group.php +++ b/src/app/Group.php @@ -3,6 +3,7 @@ namespace App; use App\Traits\BelongsToTenantTrait; +use App\Traits\EntitleableTrait; use App\Traits\UuidIntKeyTrait; use App\Wallet; use Illuminate\Database\Eloquent\Model; @@ -20,8 +21,9 @@ class Group extends Model { use BelongsToTenantTrait; - use UuidIntKeyTrait; + use EntitleableTrait; use SoftDeletes; + use UuidIntKeyTrait; // we've simply never heard of this domain public const STATUS_NEW = 1 << 0; @@ -54,7 +56,7 @@ throw new \Exception("Group not yet exists"); } - if ($this->entitlement()->count()) { + if ($this->entitlements()->count()) { throw new \Exception("Group already assigned to a wallet"); } @@ -110,16 +112,6 @@ return false; } - /** - * The group entitlement. - * - * @return \Illuminate\Database\Eloquent\Relations\MorphOne - */ - public function entitlement() - { - return $this->morphOne('App\Entitlement', 'entitleable'); - } - /** * Group members propert accessor. Converts internal comma-separated list into an array * @@ -266,17 +258,4 @@ $this->status ^= Group::STATUS_SUSPENDED; $this->save(); } - - /** - * Returns the wallet by which the group is controlled - * - * @return \App\Wallet A wallet object - */ - public function wallet(): ?Wallet - { - // Note: Not all domains have a entitlement/wallet - $entitlement = $this->entitlement()->withTrashed()->orderBy('created_at', 'desc')->first(); - - return $entitlement ? $entitlement->wallet : null; - } } diff --git a/src/app/Traits/EntitleableTrait.php b/src/app/Traits/EntitleableTrait.php new file mode 100644 --- /dev/null +++ b/src/app/Traits/EntitleableTrait.php @@ -0,0 +1,39 @@ +hasMany(\App\Entitlement::class, 'entitleable_id', 'id') + ->where('entitleable_type', self::class); + } + + /** + * Returns the wallet by which the object is controlled + * + * @return ?\App\Wallet A wallet object + */ + public function wallet(): ?\App\Wallet + { + $entitlement = $this->entitlements()->withTrashed()->orderBy('created_at', 'desc')->first(); + + if ($entitlement) { + return $entitlement->wallet; + } + + // TODO: No entitlement should not happen, but in tests we have + // such cases, so we fallback to the user's wallet in this case + if ($this instanceof \App\User) { + return $this->wallets()->first(); + } + + return null; + } +} diff --git a/src/app/User.php b/src/app/User.php --- a/src/app/User.php +++ b/src/app/User.php @@ -5,10 +5,11 @@ use App\Entitlement; use App\UserAlias; use App\Sku; -use App\Traits\UuidIntKeyTrait; use App\Traits\BelongsToTenantTrait; +use App\Traits\EntitleableTrait; use App\Traits\UserConfigTrait; use App\Traits\UserAliasesTrait; +use App\Traits\UuidIntKeyTrait; use App\Traits\SettingsTrait; use App\Wallet; use Illuminate\Database\Eloquent\SoftDeletes; @@ -29,6 +30,7 @@ */ class User extends Authenticatable { + use EntitleableTrait; use UuidIntKeyTrait; use BelongsToTenantTrait; use NullableFields; @@ -214,7 +216,7 @@ // TODO: For now controller can delete/update the account owner, // this may change in future, controllers are not 0-regression feature - return $this->wallets->contains($wallet) || $this->accounts->contains($wallet); + return $wallet && ($wallet->user_id == $this->id || $this->accounts->contains($wallet)); } /** @@ -256,7 +258,7 @@ $wallet = $object->wallet(); - return $wallet && ($this->wallets->contains($wallet) || $this->accounts->contains($wallet)); + return $wallet && ($wallet->user_id == $this->id || $this->accounts->contains($wallet)); } /** @@ -341,30 +343,6 @@ return $domains; } - /** - * The user entitlement. - * - * @return \Illuminate\Database\Eloquent\Relations\MorphOne - */ - public function entitlement() - { - return $this->morphOne('App\Entitlement', 'entitleable'); - } - - /** - * Entitlements for this user. - * - * Note that these are entitlements that apply to the user account, and not entitlements that - * this user owns. - * - * @return \Illuminate\Database\Eloquent\Relations\HasMany - */ - public function entitlements() - { - return $this->hasMany('App\Entitlement', 'entitleable_id', 'id') - ->where('entitleable_type', User::class); - } - /** * Find whether an email address exists as a user (including deleted users). * @@ -696,20 +674,6 @@ return $this->hasMany('App\VerificationCode', 'user_id', 'id'); } - /** - * Returns the wallet by which the user is controlled - * - * @return ?\App\Wallet A wallet object - */ - public function wallet(): ?Wallet - { - $entitlement = $this->entitlement()->withTrashed()->orderBy('created_at', 'desc')->first(); - - // TODO: No entitlement should not happen, but in tests we have - // such cases, so we fallback to the user's wallet in this case - return $entitlement ? $entitlement->wallet : $this->wallets()->first(); - } - /** * Wallets this user owns. * diff --git a/src/tests/Feature/Console/Domain/SetWalletTest.php b/src/tests/Feature/Console/Domain/SetWalletTest.php --- a/src/tests/Feature/Console/Domain/SetWalletTest.php +++ b/src/tests/Feature/Console/Domain/SetWalletTest.php @@ -60,11 +60,11 @@ $this->assertSame('', $output); $domain->refresh(); - $sku = \App\Sku::withObjectTenantContext($domain) - ->where('title', 'domain-hosting')->first(); + $sku = \App\Sku::withObjectTenantContext($domain)->where('title', 'domain-hosting')->first(); + $entitlement = $domain->entitlements()->first(); - $this->assertSame($sku->id, $domain->entitlement->sku_id); - $this->assertSame($wallet->id, $domain->entitlement->wallet_id); + $this->assertSame($sku->id, $entitlement->sku_id); + $this->assertSame($wallet->id, $entitlement->wallet_id); // Already assigned to a wallet $code = \Artisan::call("domain:set-wallet domain-delete.com " . $wallet->id); diff --git a/src/tests/Feature/Console/OwnerSwapTest.php b/src/tests/Feature/Console/OwnerSwapTest.php --- a/src/tests/Feature/Console/OwnerSwapTest.php +++ b/src/tests/Feature/Console/OwnerSwapTest.php @@ -107,7 +107,7 @@ // Test case when the target user does not belong to the same account $john = $this->getTestUser('john@kolab.org'); - $owner->entitlement()->update(['wallet_id' => $john->wallets->first()->id]); + $owner->entitlements()->update(['wallet_id' => $john->wallets->first()->id]); $code = \Artisan::call("owner:swap user2@owner-swap.com user1@owner-swap.com"); $output = trim(\Artisan::output()); diff --git a/src/tests/Feature/Controller/DomainsTest.php b/src/tests/Feature/Controller/DomainsTest.php --- a/src/tests/Feature/Controller/DomainsTest.php +++ b/src/tests/Feature/Controller/DomainsTest.php @@ -537,7 +537,7 @@ // Test creating a domain that is soft-deleted and belongs to another user $domain->delete(); - $domain->entitlement()->withTrashed()->update(['wallet_id' => $jack->wallets->first()->id]); + $domain->entitlements()->withTrashed()->update(['wallet_id' => $jack->wallets->first()->id]); $response = $this->actingAs($john)->post("/api/v4/domains", $post); $response->assertStatus(422); diff --git a/src/tests/Feature/GroupTest.php b/src/tests/Feature/GroupTest.php --- a/src/tests/Feature/GroupTest.php +++ b/src/tests/Feature/GroupTest.php @@ -35,7 +35,7 @@ $result = $group->assignToWallet($user->wallets->first()); $this->assertSame($group, $result); - $this->assertSame(1, $group->entitlement()->count()); + $this->assertSame(1, $group->entitlements()->count()); // Can't be done twice on the same group $this->expectException(\Exception::class);