Laravel 5: check if user belongs to the moderators list before allowing him to edit

I am using Gate authorization to check if the user has permissions to access or see something.

For example I have a update-post gate definition that checks if the user owns the post or owns the sub, if yes, he will be able to see the “Edit” link and access the Edit route. If not, he won’t be able to see anything.

I am now trying to add another permissions to check if the user belongs to the “moderators” table, if yes, he will also be able to see the “Edit” link on subreddit/show

It works great for the first 2 checks, but fails on the third and the “Edit” link is always visible now, even though I cannot access the edit route of posts that aren’t mine or belong to the subreddit I own.

EDIT: I have edited $moderators_list it now check if the logged in user is a moderator of the subreddit that the post he’s viewing. dd($moderators_list gets me a list with correct values. But I can’t use $moderators_list->user_id that will give Undefined property: Illuminate\Database\Eloquent\Collection::$user_id

EDIT 2: I have fixed the query that gets the user_id of the user who is a moderator in a subreddit. So now using $moderators_list->user-id gets me the id of 3 which is the user id of the current logged in. But the gate checking still fails, unable to edit posts in the subreddit I am moderator in.

My tables

users: id, name, email...
subreddits: id, user_id...
posts: id, user_id, subreddit_id...
moderators: id, user_id, subreddit_id...

This is the $gate definitions

$gate->define('update-post', function ($user, $post, $moderators_list) {
        // Check if user is subreddit owner
        if ($user->id === $post->subreddit->user->id) {
            return true;
        }

        // Check if user is the post author
        if ($user->id === $post->user_id) {
            return true;
        }

        // Check if user is a moderator of a subreddit
        if ($user->id === $moderators_list->user_id) {
            return true;
        }

        return false;
});

And this is show() method on PostsController

Please note that dd($moderators_list) will output a list of all moderators of the subreddit this post is located in, so I am getting the correct result.

public function show(Post $post, Subreddit $subreddit, Moderator $moderator)
{
        $post = Post::with('user.votes')->findOrFail($post->id);
        $moderator = Moderator::where('user_id', '=', Auth::id())->first();
        $moderators_list = Moderator::where('subreddit_id', '=', $post->subreddit->id)->where('user_id', '=', Auth::id())->first();

        return view('post/show')->with('post', $post)
                                ->with('moderator', $moderator)
                                ->with('moderators_list', $moderators_list);
}

And this is how I check to see if user has access to see the “Edit” link on the view

@can('update-post', [$post, $moderator, $moderators_list])
     <a href="{{ action('[email protected]', $post->id) }}" rel="nofollow noreferrer noopener">Edit</a>
@endcan

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

You can check if the user is a moderator directly in the DB:

$isModerator = $post->subreddit->moderators()->where('user_id', $user->id)->exists();

Solution 2

$gate->define('update-post', function ($user, $post, $moderators_list) {
        // Check if user is subreddit owner
        if ($user->id === $post->subreddit->user->id) {
            return true;
        }

        // Check if user is the post author
        if ($user->id === $post->user_id) {
            return true;
        }

        // Check if user is a moderator of a subreddit
        if (in_array($user->id, $moderators_list)) { //will need to add ->toArray(); after the ->get() in the $moderators_list query.
            return true;
        }

        return false;
});

Now you will need to add ->toArray(); after the ->get() in the $moderators_list query:

public function show(Post $post, Subreddit $subreddit, Moderator $moderator)
{
        $post = Post::with('user.votes')->findOrFail($post->id);
        $moderator = Moderator::where('user_id', '=', Auth::id())->first();
        $moderators_list = Moderator::where('subreddit_id', '=', $post->subreddit->id)->get()->toArray;

        return view('post/show')->with('post', $post)
                                ->with('moderator', $moderator)
                                ->with('moderators_list', $moderators_list);
}

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply