refactor(policies): extract HandlesUserOwnership trait (#478)

## What

`CategoryPolicy`, `LabelPolicy`, `TransactionPolicy`,
`AutomationRulePolicy` were structurally identical: `update`/`delete`
check `$user->id === $model->user_id`, everything else returns `false`.
`AccountPolicy` same + ownership `view`.

New `app/Policies/Concerns/HandlesUserOwnership` trait; the 5 policies
now use it (Account keeps its `view` override).

`BudgetPolicy` and `RealEstateDetailPolicy` untouched — different
semantics (all-allowed / ownership via parent account).

## Stats

- **-252 / +112 lines**

## Checks

- `php artisan test
--filter="Categor|Label|Transaction|AutomationRule|Account|Polic"` — 607
passed (2887 assertions), 1 skipped
- `vendor/bin/pint --dirty` — pass

Part of duplication-removal series (#475, #476, #477).
This commit is contained in:
Víctor Falcón 2026-06-03 17:43:30 +02:00 committed by GitHub
parent fe692e37c3
commit fe5e22bcfe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 75 additions and 254 deletions

View File

@ -4,16 +4,11 @@ namespace App\Policies;
use App\Models\Account;
use App\Models\User;
use App\Policies\Concerns\HandlesUserOwnership;
class AccountPolicy
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return false;
}
use HandlesUserOwnership;
/**
* Determine whether the user can view the model.
@ -22,44 +17,4 @@ class AccountPolicy
{
return $user->id === $account->user_id;
}
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return false;
}
/**
* Determine whether the user can update the model.
*/
public function update(User $user, Account $account): bool
{
return $user->id === $account->user_id;
}
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, Account $account): bool
{
return $user->id === $account->user_id;
}
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, Account $account): bool
{
return false;
}
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, Account $account): bool
{
return false;
}
}

View File

@ -2,64 +2,9 @@
namespace App\Policies;
use App\Models\AutomationRule;
use App\Models\User;
use App\Policies\Concerns\HandlesUserOwnership;
class AutomationRulePolicy
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return false;
}
/**
* Determine whether the user can view the model.
*/
public function view(User $user, AutomationRule $automationRule): bool
{
return false;
}
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return false;
}
/**
* Determine whether the user can update the model.
*/
public function update(User $user, AutomationRule $automationRule): bool
{
return $user->id === $automationRule->user_id;
}
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, AutomationRule $automationRule): bool
{
return $user->id === $automationRule->user_id;
}
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, AutomationRule $automationRule): bool
{
return false;
}
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, AutomationRule $automationRule): bool
{
return false;
}
use HandlesUserOwnership;
}

View File

@ -2,64 +2,9 @@
namespace App\Policies;
use App\Models\Category;
use App\Models\User;
use App\Policies\Concerns\HandlesUserOwnership;
class CategoryPolicy
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return false;
}
/**
* Determine whether the user can view the model.
*/
public function view(User $user, Category $category): bool
{
return false;
}
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return false;
}
/**
* Determine whether the user can update the model.
*/
public function update(User $user, Category $category): bool
{
return $user->id === $category->user_id;
}
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, Category $category): bool
{
return $user->id === $category->user_id;
}
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, Category $category): bool
{
return false;
}
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, Category $category): bool
{
return false;
}
use HandlesUserOwnership;
}

View File

@ -0,0 +1,65 @@
<?php
namespace App\Policies\Concerns;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
trait HandlesUserOwnership
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return false;
}
/**
* Determine whether the user can view the model.
*/
public function view(User $user, Model $model): bool
{
return false;
}
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return false;
}
/**
* Determine whether the user can update the model.
*/
public function update(User $user, Model $model): bool
{
return $user->id === $model->getAttribute('user_id');
}
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, Model $model): bool
{
return $user->id === $model->getAttribute('user_id');
}
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, Model $model): bool
{
return false;
}
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, Model $model): bool
{
return false;
}
}

View File

@ -2,64 +2,9 @@
namespace App\Policies;
use App\Models\Label;
use App\Models\User;
use App\Policies\Concerns\HandlesUserOwnership;
class LabelPolicy
{
/**
* Determine whether the user can view any models.
*/
public function viewAny(User $user): bool
{
return false;
}
/**
* Determine whether the user can view the model.
*/
public function view(User $user, Label $label): bool
{
return false;
}
/**
* Determine whether the user can create models.
*/
public function create(User $user): bool
{
return false;
}
/**
* Determine whether the user can update the model.
*/
public function update(User $user, Label $label): bool
{
return $user->id === $label->user_id;
}
/**
* Determine whether the user can delete the model.
*/
public function delete(User $user, Label $label): bool
{
return $user->id === $label->user_id;
}
/**
* Determine whether the user can restore the model.
*/
public function restore(User $user, Label $label): bool
{
return false;
}
/**
* Determine whether the user can permanently delete the model.
*/
public function forceDelete(User $user, Label $label): bool
{
return false;
}
use HandlesUserOwnership;
}

View File

@ -2,43 +2,9 @@
namespace App\Policies;
use App\Models\Transaction;
use App\Models\User;
use App\Policies\Concerns\HandlesUserOwnership;
class TransactionPolicy
{
public function viewAny(User $user): bool
{
return false;
}
public function view(User $user, Transaction $transaction): bool
{
return false;
}
public function create(User $user): bool
{
return false;
}
public function update(User $user, Transaction $transaction): bool
{
return $user->id === $transaction->user_id;
}
public function delete(User $user, Transaction $transaction): bool
{
return $user->id === $transaction->user_id;
}
public function restore(User $user, Transaction $transaction): bool
{
return false;
}
public function forceDelete(User $user, Transaction $transaction): bool
{
return false;
}
use HandlesUserOwnership;
}