diff --git a/config/access-control.php b/config/access-control.php index 4ecf74e..ccb6be1 100644 --- a/config/access-control.php +++ b/config/access-control.php @@ -12,4 +12,20 @@ 'isolate_parent_query' => true, // Isolate the control's logic by applying a parent where on the query 'isolate_perimeter_queries' => true, // Isolate every perimeter query by applying a default "orWhere" to prevent Overlayed Perimeters collapsing ], + + /* + |-------------------------------------------------------------------------- + | Access Control Methods + |-------------------------------------------------------------------------- + | + */ + 'methods' => [ + 'viewAny' => 'view', + 'view' => 'view', + 'create' => 'create', + 'update' => 'update', + 'delete' => 'delete', + 'restore' => 'restore', + 'forceDelete' => 'forceDelete', + ], ]; diff --git a/src/Console/PerimeterMakeCommand.php b/src/Console/PerimeterMakeCommand.php index c89f387..f2e1cf1 100644 --- a/src/Console/PerimeterMakeCommand.php +++ b/src/Console/PerimeterMakeCommand.php @@ -104,7 +104,7 @@ protected function buildClass($name) protected function getOptions() { return [ - ['overlay', 'o', InputOption::VALUE_OPTIONAL, 'Indicates if the perimeter overlays'], + ['overlay', 'o', InputOption::VALUE_NONE, 'Indicates if the perimeter overlays'], ]; } diff --git a/src/Console/stubs/control.stub b/src/Console/stubs/control.stub index dda0591..731a410 100644 --- a/src/Console/stubs/control.stub +++ b/src/Console/stubs/control.stub @@ -13,7 +13,7 @@ class {{ class }} extends Control * The model the control refers to. * @var class-string */ - protected string $model = {{ namespacedModel }}::class; + protected string $model = \{{ namespacedModel }}::class; /** * Retrieve the list of perimeter definitions for the current control. diff --git a/src/Controls/Control.php b/src/Controls/Control.php index 2439418..42ae3f5 100644 --- a/src/Controls/Control.php +++ b/src/Controls/Control.php @@ -61,9 +61,12 @@ protected function perimeters(): array */ public function applies(Model $user, string $method, Model $model): bool { + // If the method is viewAny, we check instead if he has any 'view' right on different perimeters + $appliesMethod = config(sprintf('access-control.methods.%s', $method)) ?? $method; + foreach ($this->perimeters() as $perimeter) { - if ($perimeter->applyAllowedCallback($user, $method)) { - // If the model doesn't exists, it means the method is not related to a model + if ($perimeter->applyAllowedCallback($user, $appliesMethod)) { + // If the model doesn't exist, it means the method is not related to a model // so we don't need to activate the should result since we can't compare an existing model if (!$model->exists) { return true; @@ -131,7 +134,7 @@ protected function applyQueryControl(Builder $query, Model $user): Builder }; foreach ($this->perimeters() as $perimeter) { - if ($perimeter->applyAllowedCallback($user, 'view')) { + if ($perimeter->applyAllowedCallback($user, config('access-control.methods.view'))) { if (config('access-control.queries.isolate_perimeter_queries')) { $query = $query->orWhere(function (Builder $query) use ($user, $perimeter) { $perimeter->applyQueryCallback($query, $user); @@ -166,7 +169,7 @@ protected function applyScoutQueryControl(\Laravel\Scout\Builder $query, Model $ }; foreach ($this->perimeters() as $perimeter) { - if ($perimeter->applyAllowedCallback($user, 'view')) { + if ($perimeter->applyAllowedCallback($user, config('access-control.methods.view'))) { $query = $perimeter->applyScoutQueryCallback($query, $user); $noResultCallback = function ($query) {return $query; }; diff --git a/tests/Feature/ControlsShouldTest.php b/tests/Feature/ControlsShouldTest.php index cb6a9de..6b4205b 100644 --- a/tests/Feature/ControlsShouldTest.php +++ b/tests/Feature/ControlsShouldTest.php @@ -14,9 +14,18 @@ public function test_control_with_no_perimeter_passing(): void $this->assertFalse((new \Lomkit\Access\Tests\Support\Access\Controls\ModelControl())->applies(Auth::user(), 'create', new Model())); } + public function test_control_should_view_any_using_client_perimeter_with_changed_view_any_method_configuration(): void + { + Gate::define('view client models', function (User $user) { + return true; + }); + + $this->assertTrue((new \Lomkit\Access\Tests\Support\Access\Controls\ModelControl())->applies(Auth::user(), 'viewAny', new Model())); + } + public function test_control_should_view_any_using_client_perimeter(): void { - Gate::define('viewAny client models', function (User $user) { + Gate::define('view client models', function (User $user) { return true; }); @@ -85,7 +94,7 @@ public function test_control_should_delete_using_client_perimeter(): void public function test_control_should_view_any_using_global_perimeter(): void { - Gate::define('viewAny global models', function (User $user) { + Gate::define('view global models', function (User $user) { return true; }); diff --git a/tests/Feature/PoliciesTest.php b/tests/Feature/PoliciesTest.php index 3f53f1a..e7ed951 100644 --- a/tests/Feature/PoliciesTest.php +++ b/tests/Feature/PoliciesTest.php @@ -24,7 +24,7 @@ public function test_policies_calls_view_method_properly(): void public function test_policies_calls_view_any_method_properly(): void { - Gate::define('viewAny global models', function (User $user) { + Gate::define('view global models', function (User $user) { return true; }); $user = \Illuminate\Support\Facades\Auth::user(); diff --git a/tests/Unit/Console/MakeCommandsTest.php b/tests/Unit/Console/MakeCommandsTest.php index 76f3973..dd345c6 100644 --- a/tests/Unit/Console/MakeCommandsTest.php +++ b/tests/Unit/Console/MakeCommandsTest.php @@ -109,7 +109,7 @@ public function test_make_control_with_model_command() $this->assertFileExists(app_path('Access/Controls/TestControl.php')); $this->assertStringContainsString('class TestControl', file_get_contents(app_path('Access/Controls/TestControl.php'))); - $this->assertStringContainsString('protected string $model = App\Models\User::class;', file_get_contents(app_path('Access/Controls/TestControl.php'))); + $this->assertStringContainsString('protected string $model = \App\Models\User::class;', file_get_contents(app_path('Access/Controls/TestControl.php'))); unlink(app_path('Models/User.php')); unlink(app_path('Models/Post.php'));