bouncer icon indicating copy to clipboard operation
bouncer copied to clipboard

Assign role for a particular model

Open titonova opened this issue 3 years ago • 2 comments

Considering that it is possible to do grant an ability only to a specific model

Bouncer::allow($user)->to('edit', $post);

I think it should also be possible to grant a role to a specific model. That is, take all the abilities a particular role has and give it to a user, but only for a particular model. That is:

Bouncer::assign('admin', $post)->to($user); rather than just Bouncer::assign('admin')->to($user);

titonova avatar May 30 '22 15:05 titonova

This is a feature request that keeps on coming up, but it's more complicated than it sounds. Caching becomes really complicated. See here.


In your case, you could use the toManage method:

Bouncer::allow($user)->toManage($post);

This allows all abilities on that model. It's syntactic sugar for:

Bouncer::allow($user)->to('*', $post);

JosephSilber avatar May 31 '22 12:05 JosephSilber

Ah okay, that makes sense. However, the solution you proposed allows all abilities on that model. But what if we need(as in my case), to only assign abilities of a particular role( that is not an admin or super admin, say editor).

What I came up with though, is a little hack, which I'm 100% sure isnt a great solution at all and I haven't written custom tests for it. But it works.... I'd like your opinion on it please.

I created a helper class called BouncerExt, and within it I put:

    /**
     * Assign a given user with a role(e.g admin etc), but only  for the given model.
     * @link https://github.com/JosephSilber/bouncer/issues/592
     *
     * @param User $user
     * @param string $role
     * @param Object $model
     * @return void
     */
    public static function assignUserWithRoleForModel(User $user, string $role, Object $model)
    {

        $fake_user = User::factory()->create();
        Bouncer::assign($role)->to($fake_user);

        $abilities_of_roles = collect($fake_user->getAbilities()->all());

        // Give all the fake user's abilities to the user
        $abilities_of_roles->map(function($ability) use ($user,$model) {
            // If user already has  such ability, then skip it.
            #if(!$user->abilities()->where('name',$ability->name)->exists()) {
                Bouncer::allow($user)->to($ability->name,$model);
            #}

        });

        $fake_user->delete();

        #dd($fake_user->getAbilities()->all(), $user->getAbilities()->unique('original.name')->all());
    }

Then used as follows:

BouncerExt::assignUserWithRoleForModel(auth()->user(),'editor',$post);

titonova avatar Jun 03 '22 20:06 titonova