Laravel 5: allow user to edit post if he's the owner of the post or the owner of the forum category

16,964

So how can I check if the users is the owner of the article OR the owner of the category to display and allow EDIT?

Use Laravel’s new authorization component.

EDIT: I think you’re misunderstanding how authorization should be used. It should be used to check if the current user can perform an action (or not). Therefore, you don’t want to be defining multiple methods for different users types.

Take editing a post for example. There’s the name of your authorization check: @can('edit', $post). You don’t need to define a different one for regular users, and another for moderators. Just add the logic to your edit post method:

class PostPolicy
{
    public function edit(User $user, Post $post)
    {
        // If user is administrator, then can edit any post
        if ($user->isModerator()) {
            return true;
        }

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

        return false;
    }
}

As you can see, I’m doing the different checks in the same method, so in your Blade template you can just do this:

@can('edit', $post)
    <a href="{{ route('post.edit', $post->getRouteKey()) }}">Edit post</a>
@endcan

Hope this clears things up.

Share:
16,964

Related videos on Youtube

Halnex
Author by

Halnex

Updated on September 15, 2022

Comments

  • Halnex
    Halnex over 1 year

    So far I was able to allow the user to edit his own posts but whenever I through the if he's owner of the subreddit/category condition, it stops working altogether.

    I have these 3 table

    Users: id, name, email...
    Subreddits: id, name, user_id...
    Posts: id, link, title, user_id, subreddit_id...
    

    This is the edit() method in PostsController.php

    public function edit(Post $post, Subreddit $subreddit)
        {
            if(Auth::id() !== $post->user_id) {
                return view('home')->withErrors('You cannot do that');
            } else {
                return view('post/edit')->with('post', $post)->with('subreddit', $subreddit);
            }
        }
    

    And this is the view

    @if(Auth::id() == $post->user_id)
          <a href="{{ action('PostsController@edit', [$post->id]) }}">Edit</a>
    @endif
    

    This works fine, it only checks if the logged in user_id is the same as the posts's user_id and updating goes through.

    But if I added if(Auth::id() == $subreddit->user_id) it stops working. It displays the "Edit" link on the view on all the posts but clicking on any of them gives me the validation error You cannot do that even for posts that I own.

    So how can I check if the users is the owner of the article OR the owner of the category to display and allow EDIT?

    Updated method with $subreddit->user_id

    public function edit(Post $post, Subreddit $subreddit)
        {
            if(Auth::id() == $post->user_id || Auth::id() == $subreddit->user_id) {
                return view('post/edit')->with('post', $post)->with('subreddit', $subreddit);
            } else {
                return view('home')->withErrors('You cannot do that');
            }
        }
    

    View

    @if(Auth::id() == $post->user_id || Auth::id() == $subreddit->user_id)
          <a href="{{ action('PostsController@edit', [$post->id]) }}">Edit</a>
    @endif
    

    This will allow me to edit my own posts but will still give me the validation error You cannot do that on posts in my own forum category/subreddit.

    This is the Gate policies that I've tried but it also didn't work

    class AuthServiceProvider extends ServiceProvider
    {
        // Authorizations and Permissions
        public function boot(GateContract $gate)
        {
            parent::registerPolicies($gate);
    
            $gate->define('update-post', function ($user, $post) {
                    return $user->id === $post->user_id;
            });
    
            $gate->define('mod-update-post', function ($user, $subreddit) {
                return $user->id === $subreddit->user_id;
            });
        }
    

    PostsController.php

    public function edit(Post $post, Subreddit $subreddit, User $user)
        {
            if(Gate::denies('update-post', $post) && Gate::denies('mod-update-post', $subreddit)) {
            return view('home')->withErrors('You cannot do that');
        } else {
            return view('post/edit')->with('post', $post)->with('subreddit', $subreddit);
        }
        }
    

    View

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

    With the above code, I am finally able to edit posts if 'update-post' is true but I cannot check if mod-update-post is also true, I keep receiving the validation error You cannot do this

    dd($subreddit) inside edit() method shows an empty array. https://cryptbin.com/x6V6wX#26810f755a62f6c8837c0c0fe0371dcf

    EDIT: I think I've solved it. I used $post->subreddit->user->id instead of $subreddit->user_id because that was returning null. And now it all seems to work based on if posts belongs to user or user is forum owner.

    But the edit link on the view still shows whether or not I have access. I am unable to double check for update-post and mod-update-post simultaneously. and using @can('update-post', $post) only works once, I cannot double check that.

  • Halnex
    Halnex over 8 years
    I tried that before, I added a new policy mod-update-post that would return $user->id === $subreddit->user_id; but I couldn't check for two @can on the view and I found no documentation on the subject.
  • Martin Bean
    Martin Bean over 8 years
    That’s because you’re supposed to define a role for what you’re checking for, instead of combining them, i.e. @can('edit', $post). Just do two boolean checks in that method on your policy instead of trying to combine checks in your view (which you shouldn’t be).
  • Halnex
    Halnex over 8 years
    I have edited my post and added my gate policies, but it is still not working properly. I can see the EDIT link now on my posts but cannot edit them, getting the validation error.
  • Halnex
    Halnex over 8 years
    I refined my code, Gate policy update-post is working, but mod-update-post is not. And I still need to use @can on the view otherwise everyone would be able to see the EDIT link.
  • Martin Bean
    Martin Bean over 8 years
    Yes. So use @can('edit', $post) and then add your logic that determines whether the user can edit the post or not, and show the link if so.
  • Halnex
    Halnex over 8 years
    Well I solved it by using the Gate facade within the if statement. Works like a charm. and I switched back to the Gate policies, better.
  • Martin Bean
    Martin Bean over 8 years
    I’ve updated my answer to give you an example of how you should be doing authorization checks.
  • Halnex
    Halnex over 8 years
    Thank you for that. But I am still confused about isModerator where is that coming from? in PhpStorm, I'm getting Method not found in App\User - do I need to create that?
  • Martin Bean
    Martin Bean over 8 years
    Yes. It’s example code for demonstration purposes; not to be copy-and-pasted. I don’t know how you designate how users are moderators; that’s up to you to implement.
  • Lord Jesus
    Lord Jesus about 3 years
    I use the same policy as you mentioned. However, how do you handle if I copied the edit URL of the post and logout then login to a different user and paste it, still allowing me to edit the post (even though I am not the rightful owner to edit).