JosephSilber / bouncer

Laravel Eloquent roles and abilities.
MIT License
3.42k stars 331 forks source link

Permission on belongToMany relation of entity #651

Open mix359 opened 3 weeks ago

mix359 commented 3 weeks ago

Hi to all,

I'm trying to figure out how to realize a special type of permission I need: I have an entity called Issue that have a belongToMany relation with the User entity, that represent who are involved in the issue resolution (the recipients of the issue). I would like to give the ability to see or edit the issue entity to anyone who is targeted by that relation. Usually in other case I would have solved giving the ownership of the entity to the user and checking the ability using the owning mechanism, but in this case multiple users should have access to this entity, and they're not the owner of the entity. The User entity that is part of that relation is also the one that have the abilities and roles relations and is Authenticatable. There's any way to check an ability on that type of relation? Any suggestion on how to manage this situation?

Many thanks Daniele

JosephSilber commented 3 weeks ago

That's what the ownedVia callback is for:

Bouncer::ownedVia(Issue::class, function ($issue, $user) {
    return $issue->users()->where('id', $user->id)->exists();
});

Once that's set up, you can add a regular ownership ability:

Bouncer::allow('developer')->toOwn(Issue::class);
mix359 commented 2 weeks ago

Many thanks @JosephSilber :D

That's really close to what I was looking for. There's any way to do something like that but without owning the entity? In my case I want to give read and write permission to the user that own the issue entity, and give read permission to some other "participants" to the issue. So I will need to check a manyToMany relation in one case and another relation in the second case. There's a way to have the ability name in the ownedVia callback, to make the check conditional?

Thanks again Daniele

JosephSilber commented 1 week ago

There's a way to have the ability name in the ownedVia callback, to make the check conditional?

Bouncer does not currently support this. I'll mark this issue as a feature proposal.


In the meantime, I would use a regular policy for this:

class IssuePolicy
{
    public function view(User $user, Issue $issue)
    {
        return $issue->created_by == $user->id
            || $issue->participants()->where('id', $user->id)->exists();
    }
}

If you want to be able to toggle it at runtime for specific users or based on roles, you can have a placeholder own ability in Bouncer for it...

Bouncer::allow('developer')->to('own', Issue::class);

...and then check that first in your policy:

class IssuePolicy
{
    public function view(User $user, Issue $issue)
    {
        if (! $user->can('own', $issue)) {
            return false;
        }

        return $issue->created_by == $user->id
            || $issue->participants()->where('id', $user->id)->exists();
    }
}