outl1ne / nova-settings

A Laravel Nova tool for editing custom settings using native Nova fields.
MIT License
271 stars 99 forks source link

Perrmisison to update, view #164

Closed arturasfrontit closed 1 year ago

arturasfrontit commented 1 year ago

How add permission to only view settings, but cant edit? And other combinations?

NovaSettings::make()
    ->canSee(fn () => auth()->user()->hasPermissionTo('viewAnySettings')),
marttinnotta commented 1 year ago

Please read Nova documentation about policies and how you can use them to allow/forbid certain actions.

https://nova.laravel.com/docs/4.0/resources/authorization.html#policies

If you do not know what policies are I suggest you start from Laravel's documentation about how to create and write them.

https://laravel.com/docs/10.x/authorization#creating-policies

arturasfrontit commented 1 year ago

Please read Nova documentation about policies and how you can use them to allow/forbid certain actions.

https://nova.laravel.com/docs/4.0/resources/authorization.html#policies

If you do not know what policies are I suggest you start from Laravel's documentation about how to create and write them.

https://laravel.com/docs/10.x/authorization#creating-policies

I have registered policy class, update method returns false, but I still can update settings

marttinnotta commented 1 year ago

I have registered policy class, update method returns false, but I still can update settings

Then you are doing something wrong.

// app/Policies/SettingsPolicy.php

namespace App\Policies;

class SettingsPolicy
{
    public function view(): bool 
    {
        return true;
    }

    public function update(): bool 
    {
        return false;
    }
}
// app/Providers/AuthServiceProvider.php

namespace App\Providers;

use App\Policies\SettingsPolicy;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Outl1ne\NovaSettings\Models\Settings;

class AuthServiceProvider extends ServiceProvider
{
    protected $policies = [
        Settings::class => SettingsPolicy::class,
    ];

    public function boot(): void
    {
        $this->registerPolicies();
    }
}

This example works as in you can see settings but you cant save (there is no save button and even if there is you would get 403 when trying to update).

arturasfrontit commented 1 year ago

I have registered policy class, update method returns false, but I still can update settings

Then you are doing something wrong.

// app/Policies/SettingsPolicy.php

namespace App\Policies;

class SettingsPolicy
{
    public function view(): bool 
    {
        return true;
    }

    public function update(): bool 
    {
        return false;
    }
}
// app/Providers/AuthServiceProvider.php

namespace App\Providers;

use App\Policies\SettingsPolicy;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Outl1ne\NovaSettings\Models\Settings;

class AuthServiceProvider extends ServiceProvider
{
    protected $policies = [
        Settings::class => SettingsPolicy::class,
    ];

    public function boot(): void
    {
        $this->registerPolicies();
    }
}

This example works as in you can see settings but you cant save (there is no save button and even if there is you would get 403 when trying to update).

<?php

namespace App\Policies\Nova;

use App\Models\Settings;

class SettingsPolicy extends Policy
{
    protected ?string $model = Settings::class;
}
<?php

namespace App\Policies\Nova;

use Illuminate\Auth\Access\HandlesAuthorization;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Foundation\Auth\User as Authenticatable;

/**
 * @SuppressWarnings(NumberOfChildren)
 */
class Policy
{
    use HandlesAuthorization;

    protected ?string $model = null;

    protected function hasPermissionTo(Authenticatable $user, string $permission): bool
    {
        $isSuperAdmin = method_exists($user, 'isSuperAdmin') && $user->isSuperAdmin();

        return $isSuperAdmin || $user->hasPermissionTo($this->buildPermission($permission));
    }

    public function buildPermission(?string $permission = null, ?string $model = null): string
    {
        return $permission . str($this->model ?? $model)
            ->explode('\\')
            ->last();
    }

    /**
     * Determine whether the user can view any models.
     */
    public function viewAny(Authenticatable $user): bool
    {
        return $this->hasPermissionTo($user, 'viewAny');
    }

    /**
     * Determine whether the user can view the model.
     */
    public function view(Authenticatable $user, Model $model): bool
    {
        return $this->hasPermissionTo($user, 'view');
    }

    /**
     * Determine whether the user can create models.
     */
    public function create(Authenticatable $user): bool
    {
        return $this->hasPermissionTo($user, 'create');
    }

    /**
     * Determine whether the user can update the model.
     */
    public function update(Authenticatable $user, Model $model): bool
    {
        return $this->hasPermissionTo($user, 'update');
    }

    /**
     * Determine whether the user can delete the model.
     */
    public function delete(Authenticatable $user, Model $model): bool
    {
        return $this->hasPermissionTo($user, 'delete');
    }

    /**
     * Determine whether the user can restore the model.
     */
    public function restore(Authenticatable $user, Model $model): bool
    {
        return $this->hasPermissionTo($user, 'restore');
    }

    /**
     * Determine whether the user can permanently delete the model.
     */
    public function forceDelete(Authenticatable $user, Model $model): bool
    {
        return $this->hasPermissionTo($user, 'forceDelete');
    }

    public function allowedActions(): array
    {
        return [];
    }

    protected function isActionAllowed(): bool
    {
        return collect($this->allowedActions())
            ->contains(request('action'));
    }
}

AuthServiceProvider:

/**
 * The policy mappings only for Nova.
 *
 * @var array<class-string, class-string>
 */
protected $novaPolicies = [
    Order::class => OrderPolicy::class,
    Settings::class => SettingsPolicy::class,
];

For example policies in Order resource works I cant update it, but settings doesn't work in updating and Im able to update it. The only thing that works for me is menu declaration:

MenuItem::make(__('Page settings'))
    ->canSee(fn () => $request->user()->hasPermissionTo('viewAnySettings'))
    ->path('nova-settings'),

Adding to settings policy

class SettingsPolicy extends Policy
{
    protected ?string $model = Settings::class;

    public function update(Authenticatable $user, Model $model): bool
    {
        return false;
    }
}

doesn't effect setting itself, but code below gives me 403:

$this->authorize('update', Settings::first());

image

marttinnotta commented 1 year ago

I tried out your code and it works like it should. The instant I make update method return false in your policy example I can no longer update settings but I can still view them.

Your issue most probably is somewhere else.