User rights update content

Ahoi,

#multiuser environment

there is a possibility that only the user + admin can change the content created by him and no other user ?

Greetings peery

In what kind of content structure setup?

You can set edit rights on a per blueprint basis per user role. But depending on your content structure that might not be enough.

roles: admin,member

/content/events/

every member has access to his profile page and the event page. he can create new events but cannot change the status, that remains the job of the admin.


can I use a webhook to prevent a member from editing only their own content?

You can probably use a route:before hook to prevent access to pages by checking a field value and the current user role.

I think I’m close to the goal, but the second hook always matches. how could I do better?

'hooks' => [
    'page.create:after' => function ($page) {
           if($page->template() == "event")
           {
             try {
                  $user = $this->user()->email();
                   $page->update([
                   'user' => $user
                   ]);

                   

                 } catch(Exception $e) 
                 {

                   $e->getMessage();

                 }
           }
       }
       ,
      'page.update:before' => function ($page) {
        if($page->template() == "event")
        {
          if ($this->user()->email() !== $page->user() &&  $page->user() != "") {
            throw new Exception('Only our overlord and savior can update pages');
          }
      } 
      }
  ]

You are comparing a string to a field object in this line with ===.

if ($this->user()->email() !== $page->user() &&  $page->user() != "") {

Should be

if ($this->user()->email() !== $page->user()->value() &&  $page->user() != "") {

But why don’t you use a default value for the user field at page creation and make this field disabled, then you don’t need the first hook at all.

And while the second hook will work, maybe better use a route:before hook so that the user cannot access a page that doesn’t belong to them in the first place instead of only finding they can’t store their edits after editing?

The hooks thing is new for me :thinking:

what I do wrong ?

 'hooks' => [
  'route:before' => function ($route, $path, $method) {
     if($this->site()->page()->template() == "event")
     {
      if ($this->user()->username() !== $this->site()->page()->user()->value()) {
        throw new Exception('you do not have the necessary access rights for this part');
      }
     }
 }
   

  ]

blueprint
user:
label: user
type: users
disabled: true

when is route: before triggered?

When a route is called but before it is executed.

I try to read the contents of a field, but I get the error message: Call to a member function title () on null. what am I doing wrong ?

edit: okay this work but only after a page-reload, why ?

  'hooks' => [
      'route:before' => function ($route, $path, $method) {
     
        if (Str::startsWith($path, 'panel/pages/veranstaltungen')) {


        $pagePath = explode("+",$path);
        $page = kirby()->page("veranstaltungen/".$pagePath[1]);
        $user = kirby()->user();
        $filedValue = explode("- ",$page->created()->value());


        echo ( $filedValue[1]." / ".$user);
        if($page->created()->value())
        {
          if($filedValue[1] != $user)
          {    
            die('You cannot access this page');

          }
        }
         
        }
      
      }
       
    
  ]

@texnixe is there any other solution? The panel content is probably not completely loaded with php but also with javascript.

I have to look into this. I think we have solved a similar approach before. To get the idea right:

You have an events folder and inside that folder there are subpages that should only be editable by the user who created the page, right?

yes, like that:

.
├── 1_veranstaltungen
│ ├── _drafts
│ │ ├── test-admin
│ │ │ └── event.de.txt
│ │ └── test-member
│ │ └── event.de.txt
│ └── events.de.txt

Does this here not work: Disable or control the panel search button?

Looks like it’s the same stuff.

yes is ± the same, it works but only after a page-reload

Hm, this test code works for me:

      'route:before' => function ($route, $path, $method) {
        if (Str::startsWith($path, 'api/pages/') && $method == 'GET') {
            $pagePath = str_replace('+', '/', str_replace('pages/', '', $route->arguments()[0]));
            $page = page($pagePath);
            $user = kirby()->user();
            if ($page && $user) {
                if ($user !== $page->author()->toUser()) {
                    throw new Exception('You cannot access this page');
                }
            }
            
        }
      },

Of course only when the user tries to access the page, not if they are already on the page (but that doesn’t make sense, anyway).

@texnixe thanks for your help, but it doesn’t work for me only after reload.

what is $ route-> arguments () [0]) ?
why api/pages/ and not /panel/pages ?

the rule should only be used within content /veranstaltungen / matches therefore (Str :: startsWith ($ path, 'api /pages/veranstaltungen') && $ method == 'GET')

‘hooks’ => [
‘route:before’ => function ($route, $path, $method) {

    if (Str::startsWith($path, 'api/pages/veranstaltungen') && $method == 'GET') {

      $pagePath = str_replace('+', '/', str_replace('pages/', '', $route->arguments()[0]));

      $page = kirby()->page($pagePath);
      $user = kirby()->user();

      echo($user." / ".$page->created()->toUser());
    if ($page && $user) {

      if ($user !== $page->created()->toUser()) {

          throw new Exception('You cannot access this page');

      }
    }
     
    }
  
  }

]

Because that’s the API route when you try to access a page, which you can see in the network tab when you open a page in the Panel, e.g. api/pages/notes+across-the-ocean

$route->arguments()returns an array like this

<pre>Array
(
    [0] => pages/notes+across-the-ocean
)
</pre>

What do you mean with “only after reload”. If you are on the dashboard and try to access a forbidden page, it should not be accessible. See this gif:

@texnixe thank you very much for your help!

solution

'hooks' => [
  'route:before' => function ($route, $path, $method) {
 
    if (Str::startsWith($path, 'api/pages') && $method == 'GET') {

      $pagePath = str_replace('+', '/', str_replace('pages/', '', $route->arguments()[0]));

      $page = kirby()->page($pagePath);
      $user = kirby()->user();

    if ($page && $user && $page->created()->toUser()) {
      
      if($user->username() == "Admin")
      {
        return;
      }
      
      if ($user !== $page->created()->toUser()) 
      {
          throw new Exception('You cannot access this page');
      }
    }
     
    }
  
  }
   

  ]