Git Product home page Git Product logo

nova-permissions's Introduction

Laravel Nova Grouped Permissions

Latest Version on Github

A Laravel Nova Tool that allows you to group your Permissions into Groups and attach it to Users. It uses Spatie's laravel-permission.

We have a Migration, Seed, Policy and Resource ready for a good Authorization Experience.

  1. Installation
  2. Permissions with Groups
  3. Customization
  4. Credits

image

Installation

You can install the package in to a Laravel app that uses Nova via composer:

composer require eminiarts/nova-permissions

Publish the Migration with the following command:

php artisan vendor:publish --provider="Eminiarts\NovaPermissions\ToolServiceProvider" --tag="migrations"

Migrate the Database:

php artisan migrate

Next up, you must register the tool with Nova. This is typically done in the tools method of the NovaServiceProvider.

// in app/Providers/NovaServiceProvider.php

// ...

public function tools()
{
    return [
        // ...
        new \Eminiarts\NovaPermissions\NovaPermissions(),
    ];
}

If you want to hide the tool from certain users, you can write your custom logic for the ability to see the tool:

// in app/Providers/NovaServiceProvider.php

// ...

public function tools()
{
    return [
        // ...
        (new \Eminiarts\NovaPermissions\NovaPermissions())->canSee(function ($request) {
            return $request->user()->isSuperAdmin();
        }),
    ];
}

Finally, add MorphToMany fields to you app/Nova/User resource:

// ...
use Laravel\Nova\Fields\MorphToMany;

public function fields(Request $request)
{
    return [
        // ...
        MorphToMany::make('Roles', 'roles', \Eminiarts\NovaPermissions\Nova\Role::class),
        MorphToMany::make('Permissions', 'permissions', \Eminiarts\NovaPermissions\Nova\Permission::class),
    ];
}

Add the Spatie\Permission\Traits\HasRoles trait to your User model(s):

use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
    use HasRoles;

    // ...
}

A new menu item called Permissions & Roles will appear in your Nova app after installing this package.

Permissions with Groups

Detail View

image

Edit View

image

Database Seeding

Publish our Seeder with the following command:

php artisan vendor:publish --provider="Eminiarts\NovaPermissions\ToolServiceProvider" --tag="seeds"

This is just an example on how you could seed your Database with Roles and Permissions. Modify RolesAndPermissionsSeeder.php in database/seeds. List all your Models you want to have Permissions for in the $collection Array and change the email for the Super-Admin:

<?php

use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;

class RolesAndPermissionsSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        // Reset cached roles and permissions
        app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();

        $collection = collect([
            'invoices',
            'clients',
            'contacts',
            'payments',
            'teams',
            'users',
            'roles',
            // ... your own models/permission you want to crate
        ]);

        $collection->each(function ($item, $key) {
            // create permissions for each collection item
            Permission::create(['group' => $item, 'name' => 'view ' . $item]);
            Permission::create(['group' => $item, 'name' => 'view own ' . $item]);
            Permission::create(['group' => $item, 'name' => 'manage ' . $item]);
            Permission::create(['group' => $item, 'name' => 'manage own ' . $item]);
            Permission::create(['group' => $item, 'name' => 'restore ' . $item]);
            Permission::create(['group' => $item, 'name' => 'forceDelete ' . $item]);
        });

        // Create a Super-Admin Role and assign all permissions to it
        $role = Role::create(['name' => 'super-admin']);
        $role->givePermissionTo(Permission::all());

        // Give User Super-Admin Role
        $user = App\User::whereEmail('[email protected]')->first(); // enter your email here 
        $user->assignRole('super-admin');
    }
}

Now you can seed the Database. Add $this->call(RolesAndPermissionsSeeder::class); to the DatabaseSeeder.

Note: If this doesn't work, run composer dumpautoload to autoload the Seeder.

Create a Model Policy

You can extend Eminiarts\NovaPermissions\Policies\Policy and have a very clean Model Policy that works with Nova.

For Example: Create a new Contact Policy with php artisan make:policy ContactPolicy with the following code:

<?php
namespace App\Policies;

use Eminiarts\NovaPermissions\Policies\Policy;

class ContactPolicy extends Policy
{
    /**
     * The Permission key the Policy corresponds to.
     *
     * @var string
     */
    public static $key = 'contacts';
}

It should now work as exptected. Just create a Role, modify its Permissions and the Policy should take care of the rest.

Note: Don't forget to add your Policy to your $policies in App\Providers\AuthServiceProvider.

Note: Only extend the Policy if you have created your Permissions according to our Seeding Example. Otherwise, make sure to have view contacts, view own contacts, manage contacts, manage own contacts, restore contacts, forceDelete contacts as Permissions in your Table in order to extend our Policy.

view own contacts is superior to view contacts and allows the User to only view his own Contacts.

manage own contacts is superior to manage contacts and allows the User to only manage his own Contacts.

Super Admin

A Super Admin can do everything. If you extend our Policy, make sure to add a isSuperAdmin() Function to your App\User Model:

<?php
namespace App;

class User {
    /**
     * Determines if the User is a Super admin
     * @return null
    */
    public function isSuperAdmin()
    {
        return $this->hasRole('super-admin');
    }
}

You can modify this function as you please.

Scope Resource for User

If you use our Policy and Seeder, the user will still be able to see other Entries. In order to only allow a User to view his own Entries and no others, you can extens our Eminiarts\NovaPermissions\Nova\ResourceForUser Class like this:

<?php
namespace App\Nova;

use Eminiarts\NovaPermissions\Nova\ResourceForUser;

class Contact extends ResourceForUser 
{
    //...
}

Note: ResourceForUser assumes the Resource has a user_id column in the Database. If you are using another column, feel free to copy the contents of the Resource and modify it.

Customization

Use your own Resources

If you want to use your own resource classes, you can define them when you register the tool:

// in app/Providers/NovaServiceProvider.php

// ...

use App\Nova\Role;
use App\Nova\Permission;

public function tools()
{
    return [
        // ...
        \Eminiarts\NovaPermissions\NovaPermissionTool::make()
            ->roleResource(Role::class)
            ->permissionResource(Permission::class),
    ];
}

Credits

This Package is inspired by vyuldashev/nova-permission and silvanite/novatoolpermissions. I wanted to have a combination of both. Thanks to both authors. Also, a huge thanks goes to Spatie spatie/laravel-permission for their amazing work!

nova-permissions's People

Contributors

4n70w4 avatar bajramemini avatar chuangbo avatar ericvanjohnson avatar fbrissi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

nova-permissions's Issues

Nova 4

Doesn't work with Nova 4

Attached role to user when first register

I'm trying to get a Role to automatically attach to new users when they user the registration form, but I'm not having much success, can anyone help.

In my RegisterController I have tried the following:

protected function create(array $data)
    {
        //due to how HTML forms work, we'll only have the 'marketing_opt_in' index *if* it's been ticked

        //sensible default
        $marketingOptIn = 0;


        $role = Role::where('name', 'User')->first();

        if(array_key_exists('marketing_opt_in', $data))
        {
            $marketingOptIn = $data['marketing_opt_in'];    //if we have marketing_opt_in, it will only ever be 1
        }

        //end "due to"----

        //persist User to DB
        $user = User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'phoneNumber' => $data['phoneNumber'],
            'password' => Hash::make($data['password']),
            'marketing_opt_in' => $marketingOptIn
        ]);

        //conditionally fire the 'MarketingOptIn' event
        if($marketingOptIn == 1)
        {
            event(new MarketingOptIn($user));   //FUN FACT (TODO?): as User isn't logged in at this point, the auto event logging (to 'events' table) won't capture 'user_id' here...
        }

        $user->assignRole($role);

        return $user;
    }

User detail issue

Hello,
in the user detail view, console error is occurred and redirected to 404

Console Error:
vendor.js?id=db1251c9aab40d18aa25:94685 [Vue warn]: Error in render: "TypeError: Cannot read property 'searchable' of undefined"

found in

---> at resources/js/views/Index.vue
at resources/js/components/Detail/MorphToManyField.vue
at resources/js/components/Detail/RelationshipPanel.vue
at resources/js/components/LoadingView.vue
at resources/js/views/Detail.vue

warn @ vendor.js?id=db1251c9aab40d18aa25:94685
logError @ vendor.js?id=db1251c9aab40d18aa25:95944
globalHandleError @ vendor.js?id=db1251c9aab40d18aa25:95939
handleError @ vendor.js?id=db1251c9aab40d18aa25:95899
Vue._render @ vendor.js?id=db1251c9aab40d18aa25:97598
updateComponent @ vendor.js?id=db1251c9aab40d18aa25:98112
get @ vendor.js?id=db1251c9aab40d18aa25:98523
Watcher @ vendor.js?id=db1251c9aab40d18aa25:98512
mountComponent @ vendor.js?id=db1251c9aab40d18aa25:98119
webpackJsonp../node_modules/vue/dist/vue.common.dev.js.Vue.$mount @ vendor.js?id=db1251c9aab40d18aa25:103089
webpackJsonp../node_modules/vue/dist/vue.common.dev.js.Vue.$mount @ vendor.js?id=db1251c9aab40d18aa25:105974
init @ vendor.js?id=db1251c9aab40d18aa25:97176
createComponent @ vendor.js?id=db1251c9aab40d18aa25:100018
createElm @ vendor.js?id=db1251c9aab40d18aa25:99965
patch @ vendor.js?id=db1251c9aab40d18aa25:100515
Vue._update @ vendor.js?id=db1251c9aab40d18aa25:97991
updateComponent @ vendor.js?id=db1251c9aab40d18aa25:98112
get @ vendor.js?id=db1251c9aab40d18aa25:98523
Watcher @ vendor.js?id=db1251c9aab40d18aa25:98512
mountComponent @ vendor.js?id=db1251c9aab40d18aa25:98119
webpackJsonp../node_modules/vue/dist/vue.common.dev.js.Vue.$mount @ vendor.js?id=db1251c9aab40d18aa25:103089
webpackJsonp../node_modules/vue/dist/vue.common.dev.js.Vue.$mount @ vendor.js?id=db1251c9aab40d18aa25:105974
init @ vendor.js?id=db1251c9aab40d18aa25:97176
createComponent @ vendor.js?id=db1251c9aab40d18aa25:100018
createElm @ vendor.js?id=db1251c9aab40d18aa25:99965
createChildren @ vendor.js?id=db1251c9aab40d18aa25:100093
createElm @ vendor.js?id=db1251c9aab40d18aa25:99994
createChildren @ vendor.js?id=db1251c9aab40d18aa25:100093
createElm @ vendor.js?id=db1251c9aab40d18aa25:99994
patch @ vendor.js?id=db1251c9aab40d18aa25:100515
Vue._update @ vendor.js?id=db1251c9aab40d18aa25:97991
updateComponent @ vendor.js?id=db1251c9aab40d18aa25:98112
get @ vendor.js?id=db1251c9aab40d18aa25:98523
Watcher @ vendor.js?id=db1251c9aab40d18aa25:98512
mountComponent @ vendor.js?id=db1251c9aab40d18aa25:98119
webpackJsonp../node_modules/vue/dist/vue.common.dev.js.Vue.$mount @ vendor.js?id=db1251c9aab40d18aa25:103089
webpackJsonp../node_modules/vue/dist/vue.common.dev.js.Vue.$mount @ vendor.js?id=db1251c9aab40d18aa25:105974
init @ vendor.js?id=db1251c9aab40d18aa25:97176
createComponent @ vendor.js?id=db1251c9aab40d18aa25:100018
createElm @ vendor.js?id=db1251c9aab40d18aa25:99965
createChildren @ vendor.js?id=db1251c9aab40d18aa25:100093
createElm @ vendor.js?id=db1251c9aab40d18aa25:99994
updateChildren @ vendor.js?id=db1251c9aab40d18aa25:100256
patchVnode @ vendor.js?id=db1251c9aab40d18aa25:100359
patch @ vendor.js?id=db1251c9aab40d18aa25:100520
Vue._update @ vendor.js?id=db1251c9aab40d18aa25:97994
updateComponent @ vendor.js?id=db1251c9aab40d18aa25:98112
get @ vendor.js?id=db1251c9aab40d18aa25:98523
run @ vendor.js?id=db1251c9aab40d18aa25:98598
flushSchedulerQueue @ vendor.js?id=db1251c9aab40d18aa25:98356
(anonymous) @ vendor.js?id=db1251c9aab40d18aa25:96040
flushCallbacks @ vendor.js?id=db1251c9aab40d18aa25:95966
Promise.then (async)
timerFunc @ vendor.js?id=db1251c9aab40d18aa25:95993
nextTick @ vendor.js?id=db1251c9aab40d18aa25:96050
queueWatcher @ vendor.js?id=db1251c9aab40d18aa25:98448
update @ vendor.js?id=db1251c9aab40d18aa25:98588
notify @ vendor.js?id=db1251c9aab40d18aa25:94796
reactiveSetter @ vendor.js?id=db1251c9aab40d18aa25:95121
proxySetter @ vendor.js?id=db1251c9aab40d18aa25:98675
_callee$ @ app.js?id=5edeff062047b08e8e66:11433
tryCatch @ app.js?id=5edeff062047b08e8e66:34881
invoke @ app.js?id=5edeff062047b08e8e66:35115
prototype. @ app.js?id=5edeff062047b08e8e66:34933
step @ app.js?id=5edeff062047b08e8e66:15157
(anonymous) @ app.js?id=5edeff062047b08e8e66:15168
Promise.then (async)
step @ app.js?id=5edeff062047b08e8e66:15167
(anonymous) @ app.js?id=5edeff062047b08e8e66:15168
Promise.then (async)
step @ app.js?id=5edeff062047b08e8e66:15167
(anonymous) @ app.js?id=5edeff062047b08e8e66:15175
F @ app.js?id=5edeff062047b08e8e66:31062
(anonymous) @ app.js?id=5edeff062047b08e8e66:15154
initializeComponent @ app.js?id=5edeff062047b08e8e66:11444
mounted @ app.js?id=5edeff062047b08e8e66:11400
invokeWithErrorHandling @ vendor.js?id=db1251c9aab40d18aa25:95914
callHook @ vendor.js?id=db1251c9aab40d18aa25:98265
insert @ vendor.js?id=db1251c9aab40d18aa25:97197
invokeWithErrorHandling @ vendor.js?id=db1251c9aab40d18aa25:95914
invoker @ vendor.js?id=db1251c9aab40d18aa25:96235
invokeInsertHook @ vendor.js?id=db1251c9aab40d18aa25:100386
patch @ vendor.js?id=db1251c9aab40d18aa25:100603
Vue._update @ vendor.js?id=db1251c9aab40d18aa25:97994
updateComponent @ vendor.js?id=db1251c9aab40d18aa25:98112
get @ vendor.js?id=db1251c9aab40d18aa25:98523
run @ vendor.js?id=db1251c9aab40d18aa25:98598
flushSchedulerQueue @ vendor.js?id=db1251c9aab40d18aa25:98356
(anonymous) @ vendor.js?id=db1251c9aab40d18aa25:96040
flushCallbacks @ vendor.js?id=db1251c9aab40d18aa25:95966
Promise.then (async)
timerFunc @ vendor.js?id=db1251c9aab40d18aa25:95993
nextTick @ vendor.js?id=db1251c9aab40d18aa25:96050
Vue.$nextTick @ vendor.js?id=db1251c9aab40d18aa25:97569
_callee$ @ app.js?id=5edeff062047b08e8e66:60956
tryCatch @ app.js?id=5edeff062047b08e8e66:34881
invoke @ app.js?id=5edeff062047b08e8e66:35115
prototype. @ app.js?id=5edeff062047b08e8e66:34933
step @ app.js?id=5edeff062047b08e8e66:15157
(anonymous) @ app.js?id=5edeff062047b08e8e66:15168
Promise.then (async)
step @ app.js?id=5edeff062047b08e8e66:15167
(anonymous) @ app.js?id=5edeff062047b08e8e66:15175
F @ app.js?id=5edeff062047b08e8e66:31062
(anonymous) @ app.js?id=5edeff062047b08e8e66:15154
beforeEach @ app.js?id=5edeff062047b08e8e66:60972
iterator @ vendor.js?id=db1251c9aab40d18aa25:93278
step @ vendor.js?id=db1251c9aab40d18aa25:93004
runQueue @ vendor.js?id=db1251c9aab40d18aa25:93012
confirmTransition @ vendor.js?id=db1251c9aab40d18aa25:93305
transitionTo @ vendor.js?id=db1251c9aab40d18aa25:93192
init @ vendor.js?id=db1251c9aab40d18aa25:93892
beforeCreate @ vendor.js?id=db1251c9aab40d18aa25:92361
invokeWithErrorHandling @ vendor.js?id=db1251c9aab40d18aa25:95914
callHook @ vendor.js?id=db1251c9aab40d18aa25:98265
Vue._init @ vendor.js?id=db1251c9aab40d18aa25:99043
Vue @ vendor.js?id=db1251c9aab40d18aa25:99123
liftOff @ app.js?id=5edeff062047b08e8e66:53380
(anonymous) @ 9:269
Show 22 more frames
vendor.js?id=db1251c9aab40d18aa25:95948 TypeError: Cannot read property 'searchable' of undefined
at Proxy.render (app.js?id=5edeff062047b08e8e66:41640)
at VueComponent.Vue._render (vendor.js?id=db1251c9aab40d18aa25:97596)
at VueComponent.updateComponent (vendor.js?id=db1251c9aab40d18aa25:98112)
at Watcher.get (vendor.js?id=db1251c9aab40d18aa25:98523)
at new Watcher (vendor.js?id=db1251c9aab40d18aa25:98512)
at mountComponent (vendor.js?id=db1251c9aab40d18aa25:98119)
at VueComponent.webpackJsonp../node_modules/vue/dist/vue.common.dev.js.Vue.$mount (vendor.js?id=db1251c9aab40d18aa25:103089)
at VueComponent.webpackJsonp../node_modules/vue/dist/vue.common.dev.js.Vue.$mount (vendor.js?id=db1251c9aab40d18aa25:105974)
at init (vendor.js?id=db1251c9aab40d18aa25:97176)
at createComponent (vendor.js?id=db1251c9aab40d18aa25:100018)
logError @ vendor.js?id=db1251c9aab40d18aa25:95948
globalHandleError @ vendor.js?id=db1251c9aab40d18aa25:95939
handleError @ vendor.js?id=db1251c9aab40d18aa25:95899
Vue._render @ vendor.js?id=db1251c9aab40d18aa25:97598
updateComponent @ vendor.js?id=db1251c9aab40d18aa25:98112
get @ vendor.js?id=db1251c9aab40d18aa25:98523
Watcher @ vendor.js?id=db1251c9aab40d18aa25:98512
mountComponent @ vendor.js?id=db1251c9aab40d18aa25:98119
webpackJsonp../node_modules/vue/dist/vue.common.dev.js.Vue.$mount @ vendor.js?id=db1251c9aab40d18aa25:103089
webpackJsonp../node_modules/vue/dist/vue.common.dev.js.Vue.$mount @ vendor.js?id=db1251c9aab40d18aa25:105974
init @ vendor.js?id=db1251c9aab40d18aa25:97176
createComponent @ vendor.js?id=db1251c9aab40d18aa25:100018
createElm @ vendor.js?id=db1251c9aab40d18aa25:99965
patch @ vendor.js?id=db1251c9aab40d18aa25:100515
Vue._update @ vendor.js?id=db1251c9aab40d18aa25:97991
updateComponent @ vendor.js?id=db1251c9aab40d18aa25:98112
get @ vendor.js?id=db1251c9aab40d18aa25:98523
Watcher @ vendor.js?id=db1251c9aab40d18aa25:98512
mountComponent @ vendor.js?id=db1251c9aab40d18aa25:98119
webpackJsonp../node_modules/vue/dist/vue.common.dev.js.Vue.$mount @ vendor.js?id=db1251c9aab40d18aa25:103089
webpackJsonp../node_modules/vue/dist/vue.common.dev.js.Vue.$mount @ vendor.js?id=db1251c9aab40d18aa25:105974
init @ vendor.js?id=db1251c9aab40d18aa25:97176
createComponent @ vendor.js?id=db1251c9aab40d18aa25:100018
createElm @ vendor.js?id=db1251c9aab40d18aa25:99965
createChildren @ vendor.js?id=db1251c9aab40d18aa25:100093
createElm @ vendor.js?id=db1251c9aab40d18aa25:99994
createChildren @ vendor.js?id=db1251c9aab40d18aa25:100093
createElm @ vendor.js?id=db1251c9aab40d18aa25:99994
patch @ vendor.js?id=db1251c9aab40d18aa25:100515
Vue._update @ vendor.js?id=db1251c9aab40d18aa25:97991
updateComponent @ vendor.js?id=db1251c9aab40d18aa25:98112
get @ vendor.js?id=db1251c9aab40d18aa25:98523
Watcher @ vendor.js?id=db1251c9aab40d18aa25:98512
mountComponent @ vendor.js?id=db1251c9aab40d18aa25:98119
webpackJsonp../node_modules/vue/dist/vue.common.dev.js.Vue.$mount @ vendor.js?id=db1251c9aab40d18aa25:103089
webpackJsonp../node_modules/vue/dist/vue.common.dev.js.Vue.$mount @ vendor.js?id=db1251c9aab40d18aa25:105974
init @ vendor.js?id=db1251c9aab40d18aa25:97176
createComponent @ vendor.js?id=db1251c9aab40d18aa25:100018
createElm @ vendor.js?id=db1251c9aab40d18aa25:99965
createChildren @ vendor.js?id=db1251c9aab40d18aa25:100093
createElm @ vendor.js?id=db1251c9aab40d18aa25:99994
updateChildren @ vendor.js?id=db1251c9aab40d18aa25:100256
patchVnode @ vendor.js?id=db1251c9aab40d18aa25:100359
patch @ vendor.js?id=db1251c9aab40d18aa25:100520
Vue._update @ vendor.js?id=db1251c9aab40d18aa25:97994
updateComponent @ vendor.js?id=db1251c9aab40d18aa25:98112
get @ vendor.js?id=db1251c9aab40d18aa25:98523
run @ vendor.js?id=db1251c9aab40d18aa25:98598
flushSchedulerQueue @ vendor.js?id=db1251c9aab40d18aa25:98356
(anonymous) @ vendor.js?id=db1251c9aab40d18aa25:96040
flushCallbacks @ vendor.js?id=db1251c9aab40d18aa25:95966
Promise.then (async)
timerFunc @ vendor.js?id=db1251c9aab40d18aa25:95993
nextTick @ vendor.js?id=db1251c9aab40d18aa25:96050
queueWatcher @ vendor.js?id=db1251c9aab40d18aa25:98448
update @ vendor.js?id=db1251c9aab40d18aa25:98588
notify @ vendor.js?id=db1251c9aab40d18aa25:94796
reactiveSetter @ vendor.js?id=db1251c9aab40d18aa25:95121
proxySetter @ vendor.js?id=db1251c9aab40d18aa25:98675
_callee$ @ app.js?id=5edeff062047b08e8e66:11433
tryCatch @ app.js?id=5edeff062047b08e8e66:34881
invoke @ app.js?id=5edeff062047b08e8e66:35115
prototype. @ app.js?id=5edeff062047b08e8e66:34933
step @ app.js?id=5edeff062047b08e8e66:15157
(anonymous) @ app.js?id=5edeff062047b08e8e66:15168
Promise.then (async)
step @ app.js?id=5edeff062047b08e8e66:15167
(anonymous) @ app.js?id=5edeff062047b08e8e66:15168
Promise.then (async)
step @ app.js?id=5edeff062047b08e8e66:15167
(anonymous) @ app.js?id=5edeff062047b08e8e66:15175
F @ app.js?id=5edeff062047b08e8e66:31062
(anonymous) @ app.js?id=5edeff062047b08e8e66:15154
initializeComponent @ app.js?id=5edeff062047b08e8e66:11444
mounted @ app.js?id=5edeff062047b08e8e66:11400
invokeWithErrorHandling @ vendor.js?id=db1251c9aab40d18aa25:95914
callHook @ vendor.js?id=db1251c9aab40d18aa25:98265
insert @ vendor.js?id=db1251c9aab40d18aa25:97197
invokeWithErrorHandling @ vendor.js?id=db1251c9aab40d18aa25:95914
invoker @ vendor.js?id=db1251c9aab40d18aa25:96235
invokeInsertHook @ vendor.js?id=db1251c9aab40d18aa25:100386
patch @ vendor.js?id=db1251c9aab40d18aa25:100603
Vue._update @ vendor.js?id=db1251c9aab40d18aa25:97994
updateComponent @ vendor.js?id=db1251c9aab40d18aa25:98112
get @ vendor.js?id=db1251c9aab40d18aa25:98523
run @ vendor.js?id=db1251c9aab40d18aa25:98598
flushSchedulerQueue @ vendor.js?id=db1251c9aab40d18aa25:98356
(anonymous) @ vendor.js?id=db1251c9aab40d18aa25:96040
flushCallbacks @ vendor.js?id=db1251c9aab40d18aa25:95966
Promise.then (async)
timerFunc @ vendor.js?id=db1251c9aab40d18aa25:95993
nextTick @ vendor.js?id=db1251c9aab40d18aa25:96050
Vue.$nextTick @ vendor.js?id=db1251c9aab40d18aa25:97569
_callee$ @ app.js?id=5edeff062047b08e8e66:60956
tryCatch @ app.js?id=5edeff062047b08e8e66:34881
invoke @ app.js?id=5edeff062047b08e8e66:35115
prototype. @ app.js?id=5edeff062047b08e8e66:34933
step @ app.js?id=5edeff062047b08e8e66:15157
(anonymous) @ app.js?id=5edeff062047b08e8e66:15168
Promise.then (async)
step @ app.js?id=5edeff062047b08e8e66:15167
(anonymous) @ app.js?id=5edeff062047b08e8e66:15175
F @ app.js?id=5edeff062047b08e8e66:31062
(anonymous) @ app.js?id=5edeff062047b08e8e66:15154
beforeEach @ app.js?id=5edeff062047b08e8e66:60972
iterator @ vendor.js?id=db1251c9aab40d18aa25:93278
step @ vendor.js?id=db1251c9aab40d18aa25:93004
runQueue @ vendor.js?id=db1251c9aab40d18aa25:93012
confirmTransition @ vendor.js?id=db1251c9aab40d18aa25:93305
transitionTo @ vendor.js?id=db1251c9aab40d18aa25:93192
init @ vendor.js?id=db1251c9aab40d18aa25:93892
beforeCreate @ vendor.js?id=db1251c9aab40d18aa25:92361
invokeWithErrorHandling @ vendor.js?id=db1251c9aab40d18aa25:95914
callHook @ vendor.js?id=db1251c9aab40d18aa25:98265
Vue._init @ vendor.js?id=db1251c9aab40d18aa25:99043
Vue @ vendor.js?id=db1251c9aab40d18aa25:99123
liftOff @ app.js?id=5edeff062047b08e8e66:53380
(anonymous) @ 9:269
Show 21 more frames

Thanks in advance

Usage of Checkboxes field

I'm trying to use the included Checkboxes field in another nova resource and I can't figure out how the options should be passed. Currently, my field looks like something like this which doesn't work:

Checkboxes::make(__('Foods'), 'foods')
    ->withGroups()
    ->options(collect(config('foods'))->map(function ($food, $key) {
        return [
             'group'  => ucfirst($food['group']),
             'option' => $key,
             'label'  => $food['name'],
        ];
    })->groupBy('group')->toArray()),

My config file looks something like this:

<?php

return [
    'apple' => [
        'name' => 'Apple',
        'group' => 'Fruit',
    ],

    'orange' => [
        'name' => 'Orange',
        'group' => 'Fruit',
    ],
    ...
];

Can you please show me how I should structure the config file and/or fields options to make this work?

Global search

Hi

It would be nice if you could add a method to disable the globalSearch option for the Permission and Role resource.

I solved it by extending your resources and setting

public static $globallySearchable = false;

A method ->disableGlobalSearch() when creating the tool would be a nicer solution :)

/Tim

Create / Update Undefined In User Attach Role

I just install the package, The Package Works fine except When I go to attach role page of an user it shows Update Undefined Error, Could not find the problem
Screenshot_3

Here Is My Code
`

return [

	ID::make()
	  ->sortable(),
	  
	Text::make('Email')
		->sortable()
		->rules('required', 'email', 'max:191')
		->creationRules('unique:users,email')
		->updateRules('unique:users,email,{{resourceId}}'),

	Password::make('Password')
			->onlyOnForms()
			->creationRules('required', 'string', 'min:6')
			->updateRules('nullable', 'string', 'min:6')
			->hideFromIndex()
			->hideWhenUpdating()
			->hideFromDetail(),
   
	MorphToMany::make('Roles', 'roles', \Eminiarts\NovaPermissions\Nova\Role::class),

	MorphToMany::make('Permissions', 'permissions', Permission::class)
			   ->hideFromDetail(),
];

`

super admin

on role detail page.
https://imgur.com/0YJ3Tx5
on permission details page
https://imgur.com/kOXcaj7

Exception: Class name must be a valid object or a string

    "message": "Class name must be a valid object or a string",
    "exception": "Symfony\\Component\\Debug\\Exception\\FatalThrowableError",
    "file": "/var/www/app/vendor/eminiarts/nova-permissions/src/Nova/Role.php",
    "line": 111,

If isset not exists guard name.

Production builds

Would it be better to provide production builds for js, css resources? Guess it is kind of nova convention?

Thanks for the awesome package.

Target class [RolesAndPermissionsSeeder] does not exist.

Illuminate\Contracts\Container\BindingResolutionException

Target class [RolesAndPermissionsSeeder] does not exist.

at E:\IMS\vendor\laravel\framework\src\Illuminate\Container\Container.php:811
807▕
808▕ try {
809▕ $reflector = new ReflectionClass($concrete);
810▕ } catch (ReflectionException $e) {
➜ 811▕ throw new BindingResolutionException("Target class [$concrete] does not exist.", 0, $e);
812▕ }
813▕
814▕ // If the type is not instantiable, the developer is attempting to resolve
815▕ // an abstract type such as an Interface or Abstract Class and there is

1 E:\IMS\vendor\laravel\framework\src\Illuminate\Container\Container.php:809
ReflectionException::("Class RolesAndPermissionsSeeder does not exist")

2 E:\IMS\vendor\laravel\framework\src\Illuminate\Container\Container.php:809
ReflectionClass::__construct("RolesAndPermissionsSeeder")

Model Policy not working for other role than super-admin

Hi Guys,

Great package so far. The UI is much better than "vyuldashev/nova-permission" package.

I have an issue and i don't know if i setup something wrong, or is a bug.

Basically i try to:

  • create a role and set limited permissions:
    image
  • attach the role to user. This user has only the new role.
  • create a new Policy which extends your policy:
    image

At this moment the navigation menu should be filtered based on the User-Role-Permission & Model Policy, right?
image

But, in my case all the models configured with policies are not displayed/accessible within the navigation menu.

image

For the super-admin role, the navigation menu is displayed with all the resources:

image

Any idea what i'm doing wrong?

Publishing Policy

I think Eminiarts\NovaPermissions\Policies\Policy should be published since the package itself does not directly use it.

Could be published as:
Eminiarts\NovaPermissions\Policies\Policy -> App\Policies\EminiartsPolicy.php

Policy.php user model

use App\User field will be set from settings. Because many other users using App\Models\Users it will be changeable from config file.

Help wanted

Hello i have a problem with this package. lets say i have a table Users, and a table UserIsWorking. And 2 roles AdminRole and WorkerRole.

WorkerRole has no permissions to table Users, and thats fine, but the WorkerRole has permission to table UserIsWorking.

And now the problem is here, WorkerRole should be able to add an User to the table UserIsWorking, but since he has no permission to view the table Users the WorkerRole cannot assign an User to table UserIsWorking.

Any ideas how to fix this so that the WorkerRole cannot access nova/resurces/users but can add an user to UserIsWorking?

Error on install

Getting an error on:

// in app/Providers/NovaServiceProvider.php

// ...

public function tools()
{
    return [
        // ...
        \Eminiarts\NovaPermissions\NovaPermissions(),
    ];
}

Throws:

Symfony \ Component \ Debug \ Exception \ FatalThrowableError (E_ERROR)
Call to undefined function Eminiarts\NovaPermissions\NovaPermissions()

ACL Tool not working properly

while viewing a particular role user's list is not coming.In other words I cant attached a role to the user because there is no user's list.

Creation/Edit of Role Names with Special Characters and Spaces

When creating or editing role names within Laravel Nova, there seems to be an issue regarding the acceptance of special characters and spaces. Currently, there is no built-in validation or restriction mechanism to prevent users from inputting role names with such characters.

Expected Behavior:

  • The system should restrict the creation or editing of role names to ensure they only contain alphanumeric characters, hyphens, and underscores.

Current Behavior:

  • Users are able to create or edit role names with special characters and spaces, which can lead to inconsistencies and potential errors in the system.

Proposed Solution:

  • Implement a validation mechanism within Laravel Nova to ensure that role names adhere to the desired format (i.e., alphanumeric characters, hyphens, and underscores only). This could be achieved by adding a custom validation rule or enhancing the existing validation mechanism.

Additional Context:

  • This issue impacts the consistency and integrity of role management within Laravel Nova installations.
  • The proposed solution aims to improve data consistency and prevent potential issues arising from role names with special characters and spaces.

Not showing in sidebar

Hello,

I have installed as described, but i don'get a option in the sidebar to manage roles.

Also ran npm install and npm run dev.

Strange layout

A piece of the checkbox has been moved to another column.

image

Registering Package Related Policies

For navigation to work properly and for the sake of security, policies related to spatie models must be registered in AuthServiceProvider.php I think this should be in Readme.

Example:
'Spatie\Permission\Models\Permission' => 'App\Policies\Policy',
'Spatie\Permission\Models\Role' => 'App\Policies\Policy',

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.