From ce0a916799e6bff5aed87926b3f782318375e789 Mon Sep 17 00:00:00 2001 From: Chinmay Purav Date: Sun, 2 Feb 2025 01:04:44 +0530 Subject: [PATCH 1/2] recurring income acl added --- .../RecurringIncomeRecurringExpenseTrait.php | 9 ++- .../Pages/ListRecurringIncomes.php | 10 +-- app/Policies/RecurringIncomePolicy.php | 11 ++- .../RecurringIncomeFamilyViewTest.php | 68 +++++++++++++++++++ ...ecurringIncomeFamilyViewUserFilterTest.php | 42 ++++++++++++ .../RecurringIncomeIndividualViewTest.php | 43 ++++++++++++ ...ringIncomeIndividualViewUserFilterTest.php | 42 ++++++++++++ 7 files changed, 215 insertions(+), 10 deletions(-) create mode 100644 tests/Feature/RecurringIncome/RecurringIncomeFamilyViewTest.php create mode 100644 tests/Feature/RecurringIncome/RecurringIncomeFamilyViewUserFilterTest.php create mode 100644 tests/Feature/RecurringIncome/RecurringIncomeIndividualViewTest.php create mode 100644 tests/Feature/RecurringIncome/RecurringIncomeIndividualViewUserFilterTest.php diff --git a/app/Filament/Concerns/RecurringIncomeRecurringExpenseTrait.php b/app/Filament/Concerns/RecurringIncomeRecurringExpenseTrait.php index 271eab9..4f79d98 100644 --- a/app/Filament/Concerns/RecurringIncomeRecurringExpenseTrait.php +++ b/app/Filament/Concerns/RecurringIncomeRecurringExpenseTrait.php @@ -12,7 +12,6 @@ use Filament\Forms\Form; use Filament\Tables\Actions\BulkActionGroup; use Filament\Tables\Actions\DeleteAction; -use Filament\Tables\Actions\DeleteBulkAction; use Filament\Tables\Actions\EditAction; use Filament\Tables\Columns\TextColumn; use Filament\Tables\Filters\SelectFilter; @@ -25,6 +24,8 @@ */ trait RecurringIncomeRecurringExpenseTrait { + use BulkDeleter, UserFilterable; + public static function form(Form $form): Form { return $form @@ -82,6 +83,8 @@ public static function table(Table $table): Table { return $table ->columns([ + self::getUserColumn(), + TextColumn::make('person.name') ->searchable() ->sortable(), @@ -105,6 +108,8 @@ public static function table(Table $table): Table TextColumn::make('remaining_recurrences'), ]) ->filters([ + self::getUserFilter(), + SelectFilter::make('frequency') ->options(Frequency::class), ]) @@ -115,7 +120,7 @@ public static function table(Table $table): Table ]) ->bulkActions([ BulkActionGroup::make([ - DeleteBulkAction::make(), + self::deleteBulkAction(), ]), ]); } diff --git a/app/Filament/Resources/RecurringIncomeResource/Pages/ListRecurringIncomes.php b/app/Filament/Resources/RecurringIncomeResource/Pages/ListRecurringIncomes.php index 7aeddcf..992ba48 100644 --- a/app/Filament/Resources/RecurringIncomeResource/Pages/ListRecurringIncomes.php +++ b/app/Filament/Resources/RecurringIncomeResource/Pages/ListRecurringIncomes.php @@ -2,13 +2,15 @@ namespace App\Filament\Resources\RecurringIncomeResource\Pages; +use App\Filament\Concerns\UserFilterable; use App\Filament\Resources\RecurringIncomeResource; use Filament\Actions\CreateAction; use Filament\Resources\Pages\ListRecords; -use Illuminate\Database\Eloquent\Builder; class ListRecurringIncomes extends ListRecords { + use UserFilterable; + protected static string $resource = RecurringIncomeResource::class; protected function getHeaderActions(): array @@ -17,10 +19,4 @@ protected function getHeaderActions(): array CreateAction::make(), ]; } - - public function filterTableQuery(Builder $query): Builder - { - return parent::filterTableQuery($query) - ->where('user_id', auth()->id()); - } } diff --git a/app/Policies/RecurringIncomePolicy.php b/app/Policies/RecurringIncomePolicy.php index c49d459..f1077b3 100644 --- a/app/Policies/RecurringIncomePolicy.php +++ b/app/Policies/RecurringIncomePolicy.php @@ -2,6 +2,7 @@ namespace App\Policies; +use App\Enums\PanelId; use App\Models\RecurringIncome; use App\Models\User; use Illuminate\Auth\Access\HandlesAuthorization; @@ -22,16 +23,24 @@ public function view(User $user, RecurringIncome $recurringIncome): bool public function create(User $user): bool { - return true; + return PanelId::APP->isCurrentPanel(); } public function update(User $user, RecurringIncome $recurringIncome): bool { + if (PanelId::FAMILY->isCurrentPanel()) { + return false; + } + return $recurringIncome->user_id === $user->id; } public function delete(User $user, RecurringIncome $recurringIncome): bool { + if (PanelId::FAMILY->isCurrentPanel()) { + return false; + } + return $recurringIncome->user_id === $user->id; } } diff --git a/tests/Feature/RecurringIncome/RecurringIncomeFamilyViewTest.php b/tests/Feature/RecurringIncome/RecurringIncomeFamilyViewTest.php new file mode 100644 index 0000000..17ac0a6 --- /dev/null +++ b/tests/Feature/RecurringIncome/RecurringIncomeFamilyViewTest.php @@ -0,0 +1,68 @@ +user = User::factory()->create(); + $this->actingAs($this->user); + + $this->recurringIncome = RecurringIncome::factory()->for($this->user)->create([ + 'description' => 'User 1 RecurringIncome', + ]); + + PanelId::FAMILY->setCurrentPanel(); +}); + +it('cannot display create action', function () { + livewire(ListRecurringIncomes::class) + ->assertActionHidden('create'); +}); + +it('cannot display edit action', function () { + livewire(ListRecurringIncomes::class) + ->assertTableActionHidden('edit', $this->recurringIncome->id); +}); + +it('cannot display delete action', function () { + livewire(ListRecurringIncomes::class) + ->assertTableActionHidden('delete', $this->recurringIncome->id); +}); + +it('cannot display import action', function () { + livewire(ListRecurringIncomes::class) + ->assertTableActionHidden('delete', $this->recurringIncome->id); +}); + +it('cannot display bulk delete action', function () { + livewire(ListRecurringIncomes::class) + ->set('selectedTableRecords', [$this->recurringIncome]) + ->assertTableBulkActionHidden('delete'); +}); + +it('cannot render create recurringIncome page', function () { + $this->get(RecurringIncomeResource::getUrl('create')) + ->assertForbidden(); +}); + +it('cannot perform recurringIncome update action', function () { + livewire(RecurringIncomeResource\Pages\EditRecurringIncome::class, [ + 'record' => $this->recurringIncome->getRouteKey(), + ]) + ->assertForbidden(); +}); + +it('cannot perform delete recurringIncome action', function () { + livewire(RecurringIncomeResource\Pages\EditRecurringIncome::class, [ + 'record' => $this->recurringIncome->getRouteKey(), + ]) + ->assertForbidden(); +}); diff --git a/tests/Feature/RecurringIncome/RecurringIncomeFamilyViewUserFilterTest.php b/tests/Feature/RecurringIncome/RecurringIncomeFamilyViewUserFilterTest.php new file mode 100644 index 0000000..a186067 --- /dev/null +++ b/tests/Feature/RecurringIncome/RecurringIncomeFamilyViewUserFilterTest.php @@ -0,0 +1,42 @@ +user = User::factory()->create(); + $this->actingAs($this->user); + + $this->recurringIncome1 = RecurringIncome::factory()->for($this->user)->create([ + 'description' => 'User 1 RecurringIncome', + ]); + + $this->recurringIncome2 = RecurringIncome::factory()->for(User::factory())->create([ + 'description' => 'User 2 RecurringIncome', + ]); + + PanelId::FAMILY->setCurrentPanel(); +}); + +it('can display user filter', function () { + livewire(ListRecurringIncomes::class) + ->assertTableFilterVisible('user'); +}); + +it('can display user columns', function () { + livewire(ListRecurringIncomes::class) + ->assertTableColumnVisible('user.name'); +}); + +it('display user columns', function () { + livewire(ListRecurringIncomes::class) + ->assertSee([$this->recurringIncome1->description]) + ->assertSee([$this->recurringIncome2->description]); +}); diff --git a/tests/Feature/RecurringIncome/RecurringIncomeIndividualViewTest.php b/tests/Feature/RecurringIncome/RecurringIncomeIndividualViewTest.php new file mode 100644 index 0000000..8310205 --- /dev/null +++ b/tests/Feature/RecurringIncome/RecurringIncomeIndividualViewTest.php @@ -0,0 +1,43 @@ +user = User::factory()->create(); + $this->actingAs($this->user); + + $this->recurringIncome = RecurringIncome::factory()->for($this->user)->create([ + 'description' => 'User 1 RecurringIncome', + ]); + + PanelId::APP->setCurrentPanel(); +}); + +it('can display create action', function () { + livewire(ListRecurringIncomes::class) + ->assertActionVisible('create'); +}); + +it('can display edit action', function () { + livewire(ListRecurringIncomes::class) + ->assertTableActionVisible('edit', $this->recurringIncome->id); +}); + +it('can display delete action', function () { + livewire(ListRecurringIncomes::class) + ->assertTableActionVisible('delete', $this->recurringIncome->id); +}); + +it('can display bulk delete action', function () { + livewire(ListRecurringIncomes::class) + ->set('selectedTableRecords', [$this->recurringIncome]) + ->assertTableBulkActionVisible('delete'); +}); diff --git a/tests/Feature/RecurringIncome/RecurringIncomeIndividualViewUserFilterTest.php b/tests/Feature/RecurringIncome/RecurringIncomeIndividualViewUserFilterTest.php new file mode 100644 index 0000000..7ade767 --- /dev/null +++ b/tests/Feature/RecurringIncome/RecurringIncomeIndividualViewUserFilterTest.php @@ -0,0 +1,42 @@ +user = User::factory()->create(); + $this->actingAs($this->user); + + $this->recurringIncome1 = RecurringIncome::factory()->for($this->user)->create([ + 'description' => 'User 1 RecurringIncome', + ]); + + $this->recurringIncome2 = RecurringIncome::factory(User::factory())->create([ + 'description' => 'User 2 RecurringIncome', + ]); + + PanelId::APP->setCurrentPanel(); +}); + +it('cannot display user filter', function () { + livewire(ListRecurringIncomes::class) + ->assertTableFilterHidden('user'); +}); + +it('cannot display user columns', function () { + livewire(ListRecurringIncomes::class) + ->assertTableColumnHidden('user.name'); +}); + +it('can only list auth user recurringIncomes', function () { + livewire(ListRecurringIncomes::class) + ->assertSee([$this->recurringIncome1->description]) + ->assertDontSee([$this->recurringIncome2->description]); +}); From e4fa076f92ce5c066c0d659127de01c4ce5df12a Mon Sep 17 00:00:00 2001 From: Chinmay Purav Date: Sun, 2 Feb 2025 01:10:25 +0530 Subject: [PATCH 2/2] recurring expense acl added --- .../Pages/ListRecurringExpenses.php | 10 +-- app/Policies/RecurringExpensePolicy.php | 11 ++- .../RecurringExpenseFamilyViewTest.php | 68 +++++++++++++++++++ ...curringExpenseFamilyViewUserFilterTest.php | 42 ++++++++++++ .../RecurringExpenseIndividualViewTest.php | 43 ++++++++++++ ...ingExpenseIndividualViewUserFilterTest.php | 42 ++++++++++++ 6 files changed, 208 insertions(+), 8 deletions(-) create mode 100644 tests/Feature/RecurringExpense/RecurringExpenseFamilyViewTest.php create mode 100644 tests/Feature/RecurringExpense/RecurringExpenseFamilyViewUserFilterTest.php create mode 100644 tests/Feature/RecurringExpense/RecurringExpenseIndividualViewTest.php create mode 100644 tests/Feature/RecurringExpense/RecurringExpenseIndividualViewUserFilterTest.php diff --git a/app/Filament/Resources/RecurringExpenseResource/Pages/ListRecurringExpenses.php b/app/Filament/Resources/RecurringExpenseResource/Pages/ListRecurringExpenses.php index 79de6ee..602c2d0 100644 --- a/app/Filament/Resources/RecurringExpenseResource/Pages/ListRecurringExpenses.php +++ b/app/Filament/Resources/RecurringExpenseResource/Pages/ListRecurringExpenses.php @@ -2,13 +2,15 @@ namespace App\Filament\Resources\RecurringExpenseResource\Pages; +use App\Filament\Concerns\UserFilterable; use App\Filament\Resources\RecurringExpenseResource; use Filament\Actions\CreateAction; use Filament\Resources\Pages\ListRecords; -use Illuminate\Database\Eloquent\Builder; class ListRecurringExpenses extends ListRecords { + use UserFilterable; + protected static string $resource = RecurringExpenseResource::class; protected function getHeaderActions(): array @@ -17,10 +19,4 @@ protected function getHeaderActions(): array CreateAction::make(), ]; } - - public function filterTableQuery(Builder $query): Builder - { - return parent::filterTableQuery($query) - ->where('user_id', auth()->id()); - } } diff --git a/app/Policies/RecurringExpensePolicy.php b/app/Policies/RecurringExpensePolicy.php index e01ab6f..ce38dc1 100644 --- a/app/Policies/RecurringExpensePolicy.php +++ b/app/Policies/RecurringExpensePolicy.php @@ -2,6 +2,7 @@ namespace App\Policies; +use App\Enums\PanelId; use App\Models\RecurringExpense; use App\Models\User; use Illuminate\Auth\Access\HandlesAuthorization; @@ -22,16 +23,24 @@ public function view(User $user, RecurringExpense $recurringExpense): bool public function create(User $user): bool { - return true; + return PanelId::APP->isCurrentPanel(); } public function update(User $user, RecurringExpense $recurringExpense): bool { + if (PanelId::FAMILY->isCurrentPanel()) { + return false; + } + return $recurringExpense->user_id === $user->id; } public function delete(User $user, RecurringExpense $recurringExpense): bool { + if (PanelId::FAMILY->isCurrentPanel()) { + return false; + } + return $recurringExpense->user_id === $user->id; } } diff --git a/tests/Feature/RecurringExpense/RecurringExpenseFamilyViewTest.php b/tests/Feature/RecurringExpense/RecurringExpenseFamilyViewTest.php new file mode 100644 index 0000000..30347df --- /dev/null +++ b/tests/Feature/RecurringExpense/RecurringExpenseFamilyViewTest.php @@ -0,0 +1,68 @@ +user = User::factory()->create(); + $this->actingAs($this->user); + + $this->recurringExpense = RecurringExpense::factory()->for($this->user)->create([ + 'description' => 'User 1 RecurringExpense', + ]); + + PanelId::FAMILY->setCurrentPanel(); +}); + +it('cannot display create action', function () { + livewire(ListRecurringExpenses::class) + ->assertActionHidden('create'); +}); + +it('cannot display edit action', function () { + livewire(ListRecurringExpenses::class) + ->assertTableActionHidden('edit', $this->recurringExpense->id); +}); + +it('cannot display delete action', function () { + livewire(ListRecurringExpenses::class) + ->assertTableActionHidden('delete', $this->recurringExpense->id); +}); + +it('cannot display import action', function () { + livewire(ListRecurringExpenses::class) + ->assertTableActionHidden('delete', $this->recurringExpense->id); +}); + +it('cannot display bulk delete action', function () { + livewire(ListRecurringExpenses::class) + ->set('selectedTableRecords', [$this->recurringExpense]) + ->assertTableBulkActionHidden('delete'); +}); + +it('cannot render create recurringExpense page', function () { + $this->get(RecurringExpenseResource::getUrl('create')) + ->assertForbidden(); +}); + +it('cannot perform recurringExpense update action', function () { + livewire(RecurringExpenseResource\Pages\EditRecurringExpense::class, [ + 'record' => $this->recurringExpense->getRouteKey(), + ]) + ->assertForbidden(); +}); + +it('cannot perform delete recurringExpense action', function () { + livewire(RecurringExpenseResource\Pages\EditRecurringExpense::class, [ + 'record' => $this->recurringExpense->getRouteKey(), + ]) + ->assertForbidden(); +}); diff --git a/tests/Feature/RecurringExpense/RecurringExpenseFamilyViewUserFilterTest.php b/tests/Feature/RecurringExpense/RecurringExpenseFamilyViewUserFilterTest.php new file mode 100644 index 0000000..80e6396 --- /dev/null +++ b/tests/Feature/RecurringExpense/RecurringExpenseFamilyViewUserFilterTest.php @@ -0,0 +1,42 @@ +user = User::factory()->create(); + $this->actingAs($this->user); + + $this->recurringExpense1 = RecurringExpense::factory()->for($this->user)->create([ + 'description' => 'User 1 RecurringExpense', + ]); + + $this->recurringExpense2 = RecurringExpense::factory()->for(User::factory())->create([ + 'description' => 'User 2 RecurringExpense', + ]); + + PanelId::FAMILY->setCurrentPanel(); +}); + +it('can display user filter', function () { + livewire(ListRecurringExpenses::class) + ->assertTableFilterVisible('user'); +}); + +it('can display user columns', function () { + livewire(ListRecurringExpenses::class) + ->assertTableColumnVisible('user.name'); +}); + +it('display user columns', function () { + livewire(ListRecurringExpenses::class) + ->assertSee([$this->recurringExpense1->description]) + ->assertSee([$this->recurringExpense2->description]); +}); diff --git a/tests/Feature/RecurringExpense/RecurringExpenseIndividualViewTest.php b/tests/Feature/RecurringExpense/RecurringExpenseIndividualViewTest.php new file mode 100644 index 0000000..e784cb6 --- /dev/null +++ b/tests/Feature/RecurringExpense/RecurringExpenseIndividualViewTest.php @@ -0,0 +1,43 @@ +user = User::factory()->create(); + $this->actingAs($this->user); + + $this->recurringExpense = RecurringExpense::factory()->for($this->user)->create([ + 'description' => 'User 1 RecurringExpense', + ]); + + PanelId::APP->setCurrentPanel(); +}); + +it('can display create action', function () { + livewire(ListRecurringExpenses::class) + ->assertActionVisible('create'); +}); + +it('can display edit action', function () { + livewire(ListRecurringExpenses::class) + ->assertTableActionVisible('edit', $this->recurringExpense->id); +}); + +it('can display delete action', function () { + livewire(ListRecurringExpenses::class) + ->assertTableActionVisible('delete', $this->recurringExpense->id); +}); + +it('can display bulk delete action', function () { + livewire(ListRecurringExpenses::class) + ->set('selectedTableRecords', [$this->recurringExpense]) + ->assertTableBulkActionVisible('delete'); +}); diff --git a/tests/Feature/RecurringExpense/RecurringExpenseIndividualViewUserFilterTest.php b/tests/Feature/RecurringExpense/RecurringExpenseIndividualViewUserFilterTest.php new file mode 100644 index 0000000..8e5df80 --- /dev/null +++ b/tests/Feature/RecurringExpense/RecurringExpenseIndividualViewUserFilterTest.php @@ -0,0 +1,42 @@ +user = User::factory()->create(); + $this->actingAs($this->user); + + $this->recurringExpense1 = RecurringExpense::factory()->for($this->user)->create([ + 'description' => 'User 1 RecurringExpense', + ]); + + $this->recurringExpense2 = RecurringExpense::factory(User::factory())->create([ + 'description' => 'User 2 RecurringExpense', + ]); + + PanelId::APP->setCurrentPanel(); +}); + +it('cannot display user filter', function () { + livewire(ListRecurringExpenses::class) + ->assertTableFilterHidden('user'); +}); + +it('cannot display user columns', function () { + livewire(ListRecurringExpenses::class) + ->assertTableColumnHidden('user.name'); +}); + +it('can only list auth user recurringExpenses', function () { + livewire(ListRecurringExpenses::class) + ->assertSee([$this->recurringExpense1->description]) + ->assertDontSee([$this->recurringExpense2->description]); +});