From 873fb58177a63579f26ed93d46b98f4e380c76dd Mon Sep 17 00:00:00 2001 From: riccardodallavia Date: Fri, 20 Oct 2023 11:04:43 +0200 Subject: [PATCH] ADD canRun action --- README.md | 58 ++++++++++++++++++++++---- config/nova-eloquent-sortable.php | 19 +++++++-- src/Actions/CanRunSortableAction.php | 14 +++++++ src/Actions/CanSeeSortableAction.php | 2 +- src/Actions/EloquentSortableAction.php | 22 ++++------ src/Actions/MoveOrderDownAction.php | 11 ++--- src/Actions/MoveOrderUpAction.php | 11 ++--- src/Actions/MoveToEndAction.php | 11 ++--- src/Actions/MoveToStartAction.php | 11 ++--- src/Support/Config.php | 9 ++++ tests/ActionsTest.php | 39 ++++++++--------- 11 files changed, 132 insertions(+), 75 deletions(-) create mode 100644 src/Actions/CanRunSortableAction.php diff --git a/README.md b/README.md index a5aa650..d9fc6db 100644 --- a/README.md +++ b/README.md @@ -30,20 +30,33 @@ This is the contents of the published config file: ```php return [ + /* |-------------------------------------------------------------------------- - | Sortable permission action + | See sortable action permission |-------------------------------------------------------------------------- | | Here you may specify the fully qualified class name of the invokable class - | used to determine whether a user can see and perform sorts to a given model - | or not. + | used to determine whether a user can see sortable actions or not. | If null, all users who have access to Nova will have the permission. | */ 'can_see_sortable_action' => null, + /* + |-------------------------------------------------------------------------- + | Run sortable action permission + |-------------------------------------------------------------------------- + | + | Here you may specify the fully qualified class name of the invokable class + | used to determine whether a user can sort a given model or not. + | If null, all users who have access to Nova will have the permission. + | + */ + + 'can_run_sortable_action' => null, + ]; ``` @@ -71,10 +84,10 @@ use Maize\NovaEloquentSortable\Actions\MoveToStartAction; public function actions(NovaRequest $request) { return [ - MoveOrderDownAction::for($this), - MoveToEndAction::for($this), - MoveOrderUpAction::for($this), - MoveToStartAction::for($this), + MoveOrderDownAction::make(), + MoveToEndAction::make(), + MoveOrderUpAction::make(), + MoveToStartAction::make(), ]; } ``` @@ -127,7 +140,7 @@ The action is automatically hidden when the model is already in the first positi By default, all users who have access to Laravel Nova will be able to see all included sort actions. -If you want to restrict their visibility to some users, you can define a custom `CanSeeSortableAction` invokable class. +If you want to restrict their visibility for some users, you can define a custom `CanSeeSortableAction` invokable class. Here's an example class checking user's permissions: @@ -136,7 +149,7 @@ use Laravel\Nova\Http\Requests\NovaRequest; class CanSeeSortableAction { - public function __invoke(NovaRequest $request, $model = null, $resource = null): bool + public function __invoke(NovaRequest $request): bool { return $request->user()->can('sort_models'); } @@ -149,6 +162,33 @@ Once done, all you have to do is reference your custom class in `can_see_sortabl 'can_see_sortable_action' => \Path\To\CanSeeSortableAction::class, ``` +## Define a custom run permission + +By default, all users who have access to Laravel Nova will be able to run all included sort actions. + +If you want to restrict the permission for some users, you can define a custom `CanRunSortableAction` invokable class. + +Here's an example class checking user's permissions: + +```php +use Illuminate\Database\Eloquent\Model; +use Laravel\Nova\Http\Requests\NovaRequest; + +class CanRunSortableAction +{ + public function __invoke(NovaRequest $request, Model $model): bool + { + return $request->user()->can('sort_model', $model); + } +} +``` + +Once done, all you have to do is reference your custom class in `can_run_sortable_action` attribute under `config/nova-eloquent-sortable.php`: + +``` php +'can_run_sortable_action' => \Path\To\CanRunSortableAction::class, +``` + ## Testing ```bash diff --git a/config/nova-eloquent-sortable.php b/config/nova-eloquent-sortable.php index 546a6c6..652b4ae 100644 --- a/config/nova-eloquent-sortable.php +++ b/config/nova-eloquent-sortable.php @@ -1,18 +1,31 @@ null, + /* + |-------------------------------------------------------------------------- + | Run sortable action permission + |-------------------------------------------------------------------------- + | + | Here you may specify the fully qualified class name of the invokable class + | used to determine whether a user can sort a given model or not. + | If null, all users who have access to Nova will have the permission. + | + */ + + 'can_run_sortable_action' => null, + ]; diff --git a/src/Actions/CanRunSortableAction.php b/src/Actions/CanRunSortableAction.php new file mode 100644 index 0000000..f47eed7 --- /dev/null +++ b/src/Actions/CanRunSortableAction.php @@ -0,0 +1,14 @@ +withoutConfirmation() + $this ->onlyInline() - ->canSee(fn (NovaRequest $request) => static::canSeeSortable( - $request, - $resource->model(), - $resource - )); + ->canSee(fn (NovaRequest $request) => static::canSeeSortable($request)) + ->canRun(fn (NovaRequest $request, Model $model) => static::canRunSortable($request, $model)); } - public static function canSeeSortable(NovaRequest $request, $model = null, $resource = null): bool + public static function canSeeSortable(NovaRequest $request): bool { - return Config::getCanSeeSortableAction()($request, $model, $resource); + return Config::getCanSeeSortableAction()($request); } - public static function isUriKey(?string $uri): bool + public static function canRunSortable(NovaRequest $request, Model $model): bool { - return $uri === static::make()->uriKey(); + return Config::getCanRunSortableAction()($request, $model); } } diff --git a/src/Actions/MoveOrderDownAction.php b/src/Actions/MoveOrderDownAction.php index 93d9803..d8232b7 100644 --- a/src/Actions/MoveOrderDownAction.php +++ b/src/Actions/MoveOrderDownAction.php @@ -2,6 +2,7 @@ namespace Maize\NovaEloquentSortable\Actions; +use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Collection; use Laravel\Nova\Actions\Action; use Laravel\Nova\Fields\ActionFields; @@ -14,17 +15,13 @@ public function name(): string return __('Move order down'); } - public static function canSeeSortable(NovaRequest $request, $model = null, $resource = null): bool + public static function canRunSortable(NovaRequest $request, Model $model): bool { - if ($model?->isLastInOrder()) { + if ($model->isLastInOrder()) { return false; } - if (static::isUriKey($request->action)) { - return true; - } - - return parent::canSeeSortable($request, $model, $resource); + return parent::canRunSortable($request, $model); } public function handle(ActionFields $fields, Collection $models): mixed diff --git a/src/Actions/MoveOrderUpAction.php b/src/Actions/MoveOrderUpAction.php index d693a03..d757d75 100644 --- a/src/Actions/MoveOrderUpAction.php +++ b/src/Actions/MoveOrderUpAction.php @@ -2,6 +2,7 @@ namespace Maize\NovaEloquentSortable\Actions; +use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Collection; use Laravel\Nova\Actions\Action; use Laravel\Nova\Fields\ActionFields; @@ -14,17 +15,13 @@ public function name(): string return __('Move order up'); } - public static function canSeeSortable(NovaRequest $request, $model = null, $resource = null): bool + public static function canRunSortable(NovaRequest $request, Model $model): bool { - if ($model?->isFirstInOrder()) { + if ($model->isFirstInOrder()) { return false; } - if (static::isUriKey($request->action)) { - return true; - } - - return parent::canSeeSortable($request, $model, $resource); + return parent::canRunSortable($request, $model); } public function handle(ActionFields $fields, Collection $models): mixed diff --git a/src/Actions/MoveToEndAction.php b/src/Actions/MoveToEndAction.php index 5447ff8..c304baf 100644 --- a/src/Actions/MoveToEndAction.php +++ b/src/Actions/MoveToEndAction.php @@ -2,6 +2,7 @@ namespace Maize\NovaEloquentSortable\Actions; +use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Collection; use Laravel\Nova\Actions\Action; use Laravel\Nova\Fields\ActionFields; @@ -14,17 +15,13 @@ public function name(): string return __('Move to end'); } - public static function canSeeSortable(NovaRequest $request, $model = null, $resource = null): bool + public static function canRunSortable(NovaRequest $request, Model $model): bool { - if ($model?->isLastInOrder()) { + if ($model->isLastInOrder()) { return false; } - if (static::isUriKey($request->action)) { - return true; - } - - return parent::canSeeSortable($request, $model, $resource); + return parent::canRunSortable($request, $model); } public function handle(ActionFields $fields, Collection $models): mixed diff --git a/src/Actions/MoveToStartAction.php b/src/Actions/MoveToStartAction.php index 0c75765..47ef6c1 100644 --- a/src/Actions/MoveToStartAction.php +++ b/src/Actions/MoveToStartAction.php @@ -2,6 +2,7 @@ namespace Maize\NovaEloquentSortable\Actions; +use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Collection; use Laravel\Nova\Actions\Action; use Laravel\Nova\Fields\ActionFields; @@ -14,17 +15,13 @@ public function name(): string return __('Move to start'); } - public static function canSeeSortable(NovaRequest $request, $model = null, $resource = null): bool + public static function canRunSortable(NovaRequest $request, Model $model): bool { - if ($model?->isFirstInOrder()) { + if ($model->isFirstInOrder()) { return false; } - if (static::isUriKey($request->action)) { - return true; - } - - return parent::canSeeSortable($request, $model, $resource); + return parent::canRunSortable($request, $model); } public function handle(ActionFields $fields, Collection $models): mixed diff --git a/src/Support/Config.php b/src/Support/Config.php index c50407b..be1924b 100644 --- a/src/Support/Config.php +++ b/src/Support/Config.php @@ -2,6 +2,7 @@ namespace Maize\NovaEloquentSortable\Support; +use Maize\NovaEloquentSortable\Actions\CanRunSortableAction; use Maize\NovaEloquentSortable\Actions\CanSeeSortableAction; class Config @@ -13,4 +14,12 @@ public static function getCanSeeSortableAction(): CanSeeSortableAction return app($action); } + + public static function getCanRunSortableAction(): CanRunSortableAction + { + $action = config('nova-eloquent-sortable.can_run_sortable_action') + ?? CanRunSortableAction::class; + + return app($action); + } } diff --git a/tests/ActionsTest.php b/tests/ActionsTest.php index d177748..87fff01 100644 --- a/tests/ActionsTest.php +++ b/tests/ActionsTest.php @@ -7,51 +7,48 @@ use Maize\NovaEloquentSortable\Actions\MoveToEndAction; use Maize\NovaEloquentSortable\Actions\MoveToStartAction; use Maize\NovaEloquentSortable\Tests\Support\Models\Item; -use Maize\NovaEloquentSortable\Tests\Support\Resources\ItemResource; -it('can see', function (string $class, bool $canSeeFirst, bool $canSeeMiddle, bool $canSeeLast) { +it('can see', function (string $class, bool $canRunFirst, bool $canRunMiddle, bool $canRunLast) { $request = new NovaRequest(); - $resource = new ItemResource(null); $items = Item::factory()->count(5)->create(); $first = $items->first(); $middle = $items[2]; $last = $items->last(); - $action = $class::for($resource); + $action = $class::make(); - expect($action->canSeeSortable($request, $first))->toBe($canSeeFirst); - expect($action->canSeeSortable($request, $middle))->toBe($canSeeMiddle); - expect($action->canSeeSortable($request, $last))->toBe($canSeeLast); + expect($action->canRunSortable($request, $first))->toBe($canRunFirst); + expect($action->canRunSortable($request, $middle))->toBe($canRunMiddle); + expect($action->canRunSortable($request, $last))->toBe($canRunLast); })->with([ [ 'class' => MoveOrderDownAction::class, - 'canSeeFirst' => true, - 'canSeeMiddle' => true, - 'canSeeLast' => false, + 'canRunFirst' => true, + 'canRunMiddle' => true, + 'canRunLast' => false, ], [ 'class' => MoveToEndAction::class, - 'canSeeFirst' => true, - 'canSeeMiddle' => true, - 'canSeeLast' => false, + 'canRunFirst' => true, + 'canRunMiddle' => true, + 'canRunLast' => false, ], [ 'class' => MoveOrderUpAction::class, - 'canSeeFirst' => false, - 'canSeeMiddle' => true, - 'canSeeLast' => true, + 'canRunFirst' => false, + 'canRunMiddle' => true, + 'canRunLast' => true, ], [ 'class' => MoveToStartAction::class, - 'canSeeFirst' => false, - 'canSeeMiddle' => true, - 'canSeeLast' => true, + 'canRunFirst' => false, + 'canRunMiddle' => true, + 'canRunLast' => true, ], ]); it('can move', function (string $class, int $moveFirst, int $moveMiddle, int $moveLast) { - $resource = new ItemResource(null); $fields = new ActionFields(collect(), collect()); $items = Item::factory()->count(5)->create(); @@ -59,7 +56,7 @@ $middle = $items[2]; $last = $items->last(); - $action = $class::for($resource); + $action = $class::make(); $action->handle($fields, collect([$first->refresh()])); expect($first->refresh()->order_column)->toBe($moveFirst);