diff --git a/src/app/Domain.php b/src/app/Domain.php --- a/src/app/Domain.php +++ b/src/app/Domain.php @@ -86,24 +86,7 @@ return $this; } - $wallet_id = $user->wallets()->first()->id; - - foreach ($package->skus as $sku) { - for ($i = $sku->pivot->qty; $i > 0; $i--) { - \App\Entitlement::create( - [ - 'wallet_id' => $wallet_id, - 'sku_id' => $sku->id, - 'cost' => $sku->pivot->cost(), - 'fee' => $sku->pivot->fee(), - 'entitleable_id' => $this->id, - 'entitleable_type' => Domain::class - ] - ); - } - } - - return $this; + return $this->assignPackageAndWallet($package, $user->wallets()->first()); } /** diff --git a/src/app/Group.php b/src/app/Group.php --- a/src/app/Group.php +++ b/src/app/Group.php @@ -48,38 +48,6 @@ 'status', ]; - /** - * Assign the group to a wallet. - * - * @param \App\Wallet $wallet The wallet - * - * @return \App\Group Self - * @throws \Exception - */ - public function assignToWallet(Wallet $wallet): Group - { - if (empty($this->id)) { - throw new \Exception("Group not yet exists"); - } - - if ($this->entitlements()->count()) { - throw new \Exception("Group already assigned to a wallet"); - } - - $sku = \App\Sku::withObjectTenantContext($this)->where('title', 'group')->first(); - $exists = $wallet->entitlements()->where('sku_id', $sku->id)->count(); - - \App\Entitlement::create([ - 'wallet_id' => $wallet->id, - 'sku_id' => $sku->id, - 'cost' => $exists >= $sku->units_free ? $sku->cost : 0, - 'fee' => $exists >= $sku->units_free ? $sku->fee : 0, - 'entitleable_id' => $this->id, - 'entitleable_type' => Group::class - ]); - - return $this; - } /** * Returns group domain. diff --git a/src/app/Resource.php b/src/app/Resource.php --- a/src/app/Resource.php +++ b/src/app/Resource.php @@ -53,39 +53,6 @@ /** - * Assign the resource to a wallet. - * - * @param \App\Wallet $wallet The wallet - * - * @return \App\Resource Self - * @throws \Exception - */ - public function assignToWallet(Wallet $wallet): Resource - { - if (empty($this->id)) { - throw new \Exception("Resource not yet exists"); - } - - if ($this->entitlements()->count()) { - throw new \Exception("Resource already assigned to a wallet"); - } - - $sku = \App\Sku::withObjectTenantContext($this)->where('title', 'resource')->first(); - $exists = $wallet->entitlements()->where('sku_id', $sku->id)->count(); - - \App\Entitlement::create([ - 'wallet_id' => $wallet->id, - 'sku_id' => $sku->id, - 'cost' => $exists >= $sku->units_free ? $sku->cost : 0, - 'fee' => $exists >= $sku->units_free ? $sku->fee : 0, - 'entitleable_id' => $this->id, - 'entitleable_type' => Resource::class - ]); - - return $this; - } - - /** * Returns the resource domain. * * @return ?\App\Domain The domain to which the resource belongs to, NULL if it does not exist diff --git a/src/app/SharedFolder.php b/src/app/SharedFolder.php --- a/src/app/SharedFolder.php +++ b/src/app/SharedFolder.php @@ -59,39 +59,6 @@ /** - * Assign the folder to a wallet. - * - * @param \App\Wallet $wallet The wallet - * - * @return \App\SharedFolder Self - * @throws \Exception - */ - public function assignToWallet(Wallet $wallet): SharedFolder - { - if (empty($this->id)) { - throw new \Exception("Shared folder not yet exists"); - } - - if ($this->entitlements()->count()) { - throw new \Exception("Shared folder already assigned to a wallet"); - } - - $sku = \App\Sku::withObjectTenantContext($this)->where('title', 'shared-folder')->first(); - $exists = $wallet->entitlements()->where('sku_id', $sku->id)->count(); - - \App\Entitlement::create([ - 'wallet_id' => $wallet->id, - 'sku_id' => $sku->id, - 'cost' => $exists >= $sku->units_free ? $sku->cost : 0, - 'fee' => $exists >= $sku->units_free ? $sku->fee : 0, - 'entitleable_id' => $this->id, - 'entitleable_type' => SharedFolder::class - ]); - - return $this; - } - - /** * Returns the shared folder domain. * * @return ?\App\Domain The domain to which the folder belongs to, NULL if it does not exist diff --git a/src/app/Traits/EntitleableTrait.php b/src/app/Traits/EntitleableTrait.php --- a/src/app/Traits/EntitleableTrait.php +++ b/src/app/Traits/EntitleableTrait.php @@ -2,25 +2,181 @@ namespace App\Traits; +use App\Entitlement; +use App\Sku; +use App\Wallet; +use Illuminate\Support\Str; + trait EntitleableTrait { /** + * Assign a package to an entitleable object. It should not have any existing entitlements. + * + * @param \App\Package $package The package + * @param \App\Wallet $wallet The wallet + * + * @return $this + */ + public function assignPackageAndWallet(\App\Package $package, Wallet $wallet) + { + // TODO: There should be some sanity checks here. E.g. not package can be + // assigned to any entitleable, but we don't really have package types. + + foreach ($package->skus as $sku) { + for ($i = $sku->pivot->qty; $i > 0; $i--) { + Entitlement::create([ + 'wallet_id' => $wallet->id, + 'sku_id' => $sku->id, + 'cost' => $sku->pivot->cost(), + 'fee' => $sku->pivot->fee(), + 'entitleable_id' => $this->id, + 'entitleable_type' => self::class + ]); + } + } + + return $this; + } + + /** + * Assign a Sku to an entitleable object. + * + * @param \App\Sku $sku The sku to assign. + * @param int $count Count of entitlements to add + * + * @return $this + * @throws \Exception + */ + public function assignSku(Sku $sku, int $count = 1) + { + // TODO: I guess wallet could be parametrized in future + $wallet = $this->wallet(); + $exists = $this->entitlements()->where('sku_id', $sku->id)->count(); + + // TODO: Make sure the SKU can be assigned to the object + + while ($count > 0) { + Entitlement::create([ + 'wallet_id' => $wallet->id, + 'sku_id' => $sku->id, + 'cost' => $exists >= $sku->units_free ? $sku->cost : 0, + 'fee' => $exists >= $sku->units_free ? $sku->fee : 0, + 'entitleable_id' => $this->id, + 'entitleable_type' => self::class + ]); + + $exists++; + $count--; + } + + return $this; + } + + /** + * Assign the object to a wallet. + * + * @param \App\Wallet $wallet The wallet + * + * @return $this + * @throws \Exception + */ + public function assignToWallet(Wallet $wallet) + { + if (empty($this->id)) { + throw new \Exception("Object not yet exists"); + } + + if ($this->entitlements()->count()) { + throw new \Exception("Object already assigned to a wallet"); + } + + // Find the SKU title, e.g. \App\SharedFolder -> shared-folder + // Note: it does not work with User/Domain model (yet) + $title = Str::kebab(\class_basename(self::class)); + + $sku = Sku::withObjectTenantContext($this)->where('title', $title)->first(); + $exists = $wallet->entitlements()->where('sku_id', $sku->id)->count(); + + Entitlement::create([ + 'wallet_id' => $wallet->id, + 'sku_id' => $sku->id, + 'cost' => $exists >= $sku->units_free ? $sku->cost : 0, + 'fee' => $exists >= $sku->units_free ? $sku->fee : 0, + 'entitleable_id' => $this->id, + 'entitleable_type' => self::class + ]); + + return $this; + } + + /** * Entitlements for this object. * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function entitlements() { - return $this->hasMany(\App\Entitlement::class, 'entitleable_id', 'id') + return $this->hasMany(Entitlement::class, 'entitleable_id', 'id') ->where('entitleable_type', self::class); } /** + * Check if an entitlement for the specified SKU exists. + * + * @param string $title The SKU title + * + * @return bool True if specified SKU entitlement exists + */ + public function hasSku(string $title): bool + { + $sku = Sku::withObjectTenantContext($this)->where('title', $title)->first(); + + if (!$sku) { + return false; + } + + return $this->entitlements()->where('sku_id', $sku->id)->count() > 0; + } + + /** + * Remove a number of entitlements for the SKU. + * + * @param \App\Sku $sku The SKU + * @param int $count The number of entitlements to remove + * + * @return $this + */ + public function removeSku(Sku $sku, int $count = 1) + { + $entitlements = $this->entitlements() + ->where('sku_id', $sku->id) + ->orderBy('cost', 'desc') + ->orderBy('created_at') + ->get(); + + $entitlements_count = count($entitlements); + + foreach ($entitlements as $entitlement) { + if ($entitlements_count <= $sku->units_free) { + continue; + } + + if ($count > 0) { + $entitlement->delete(); + $entitlements_count--; + $count--; + } + } + + return $this; + } + + /** * Returns the wallet by which the object is controlled * * @return ?\App\Wallet A wallet object */ - public function wallet(): ?\App\Wallet + public function wallet(): ?Wallet { $entitlement = $this->entitlements()->withTrashed()->orderBy('created_at', 'desc')->first(); diff --git a/src/app/User.php b/src/app/User.php --- a/src/app/User.php +++ b/src/app/User.php @@ -123,24 +123,7 @@ $user = $this; } - $wallet_id = $this->wallets()->first()->id; - - foreach ($package->skus as $sku) { - for ($i = $sku->pivot->qty; $i > 0; $i--) { - \App\Entitlement::create( - [ - 'wallet_id' => $wallet_id, - 'sku_id' => $sku->id, - 'cost' => $sku->pivot->cost(), - 'fee' => $sku->pivot->fee(), - 'entitleable_id' => $user->id, - 'entitleable_type' => User::class - ] - ); - } - } - - return $user; + return $user->assignPackageAndWallet($package, $this->wallets()->first()); } /** @@ -167,38 +150,6 @@ } /** - * Assign a Sku to a user. - * - * @param \App\Sku $sku The sku to assign. - * @param int $count Count of entitlements to add - * - * @return \App\User Self - * @throws \Exception - */ - public function assignSku(Sku $sku, int $count = 1): User - { - // TODO: I guess wallet could be parametrized in future - $wallet = $this->wallet(); - $exists = $this->entitlements()->where('sku_id', $sku->id)->count(); - - while ($count > 0) { - \App\Entitlement::create([ - 'wallet_id' => $wallet->id, - 'sku_id' => $sku->id, - 'cost' => $exists >= $sku->units_free ? $sku->cost : 0, - 'fee' => $exists >= $sku->units_free ? $sku->fee : 0, - 'entitleable_id' => $this->id, - 'entitleable_type' => User::class - ]); - - $exists++; - $count--; - } - - return $this; - } - - /** * Check if current user can delete another object. * * @param mixed $object A user|domain|wallet|group object @@ -437,24 +388,6 @@ } /** - * Check if user has an entitlement for the specified SKU. - * - * @param string $title The SKU title - * - * @return bool True if specified SKU entitlement exists - */ - public function hasSku(string $title): bool - { - $sku = Sku::withObjectTenantContext($this)->where('title', $title)->first(); - - if (!$sku) { - return false; - } - - return $this->entitlements()->where('sku_id', $sku->id)->count() > 0; - } - - /** * Returns whether this domain is active. * * @return bool @@ -536,39 +469,6 @@ } /** - * Remove a number of entitlements for the SKU. - * - * @param \App\Sku $sku The SKU - * @param int $count The number of entitlements to remove - * - * @return User Self - */ - public function removeSku(Sku $sku, int $count = 1): User - { - $entitlements = $this->entitlements() - ->where('sku_id', $sku->id) - ->orderBy('cost', 'desc') - ->orderBy('created_at') - ->get(); - - $entitlements_count = count($entitlements); - - foreach ($entitlements as $entitlement) { - if ($entitlements_count <= $sku->units_free) { - continue; - } - - if ($count > 0) { - $entitlement->delete(); - $entitlements_count--; - $count--; - } - } - - return $this; - } - - /** * Return resources controlled by the current user. * * @param bool $with_accounts Include resources assigned to wallets