Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

ufodisko's avatar

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('PostsController@edit', $post->id) }}">Edit</a>
    @endcan
0 likes
7 replies
sid405's avatar

@ufodisko i'm gonna go ahead and safely assume you're trying to achieve this in the scope of https://github.com/Halnex/laravel-reddit

and i see you are storing your acl logic on AuthServiceProvider. Personally i would extend the 'update-post' permission and define on the user model a method that checks the user-moderator relation and returns a truth value if such a thing exists.

ps. this suggestion perhaps can be implemented with an efficient Count. Basically if a truthy value is returned from counting the times the current user is in the moderator relation

have a look at this http://softonsofa.com/tweaking-eloquent-relations-how-to-get-hasmany-relation-count-efficiently/

If you can't get it to work i can help later with some actual implementation but the idea would be this

public function boot(GateContract $gate)
{
    parent::registerPolicies($gate);

    $gate->define('update-post', function ($user, $post) {
        // 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;
        }

        return false;
    });

    $gate->define('update-sub', function($user, $subreddit) {
        if($user->id === $subreddit->user->id) {
            return true;
        }

        return false;
    });    

//NEW CODE
$gate->define('update-whatever-as-moderator', function($user, $subreddit) {
        if($user->moderator_relation) { //or perhaps you could just see if once you've logged in the user and eager-loaded 
                                //the relationship, it has a truthy value instead of counting
            return true;
        }

        return false;
    });
}
ufodisko's avatar

@sid405 Thank you for replying. Yes, you are correct. I'm still working on the same project "laravel-reddit"

The link you shared is giving 404 not found.

Where is moderator_relation coming from?

ufodisko's avatar

@sid405 I gave up on trying to get it to work within the Gate authorization, so I'm doing it manually in the controller and the view. But there is also a snag.

The edit link now appears twice if the user is both the owner of the post and a moderator of the sub.

And I can't check for 2 @can

@can('update-post', $post)
            <a href="{{ action('PostsController@edit', $post->id) }}">Edit</a>
@endcan

@if(count($modCheck))
       @if($modCheck->user->id)
                 <a href="{{ action('PostsController@edit', $post->id) }}">Edit</a>
        @endif
@endif
sid405's avatar

@ufodisko Strange. when i click the link it works. moderation_relation was just a term i used to refer to the moderator relation on your user model.

Try that link again as it would help you , and then to solve the two link issue, include it in the 'can-update' check, so that for either of the reasons the link i returned only once.

1 like

Please or to participate in this conversation.