User role that is only allowed to create files for a page that is a child

Instead of using the depth() and add ‘image-post’ as template, I’d like to check for the user role instead and add ‘image-author’ if it’s an author uploading the file.

if ($user->role() === 'author' && $file->type() === 'image' && $file->template() !== 'avatar') {
  ...

The above isn’t working :thinking: any ideas?

When making comparisons, you have to check what each method returns, otherwise your code won’t work as expected.

$user->role() returns a role object, not a string, so a strict comparison with === won’t work. Use

if ($user->role()->name() === 'author' //...rest of code)

instead.

$file->type() returns a string, so $file->type() === 'image' is ok.

$file->template() also returns a string, so ok.

The documentation for each and every method shows the return type, so checking the documentation for such use cases helps prevent these errors.

Thanks! But still not working, tried with === 'Author' and === 'author'

My author.yml

title: Author
description: Can create and publish posts.

extends: users/default

permissions:
  access:
    settings: false
  site:
    update: false
  user:
    changeRole: false
    create: false
    delete: false
  users: false

Are we still in the hook context? And are the $user and $file variables defined?

Yes.

'file.create:after' => function($file, $user) {
  if ($user->role()->name() === 'author' && $file->type() === 'image' && $file->template() !== 'avatar') {
    $file->update([
      'Alt'      => '',
      'Caption'  => '',
      'Template' => 'image-author'
    ]);
  } elseif ($file->type() === 'image' && $file->template() !== 'avatar') {
    $file->update([
      'Alt'      => '',
      'Caption'  => '',
      'Template' => 'image'
    ]);
  }
}

No, $user is not defined. You are passing it as a parameter, but a $user parameter doesn’t exist. You have to define it inside the callback.

      'file.create:after' => function($file) {
          if ($user = kirby()->user()) {
            if ($user->role()->name() === 'author' && $file->type() === 'image' && $file->template() !== 'avatar') {
              $file->update([
                'Alt'      => '',
                'Caption'  => '',
                'Template' => 'image-author'
              ]);
            } elseif ($file->type() === 'image' && $file->template() !== 'avatar') {
              $file->update([
                'Alt'      => '',
                'Caption'  => '',
                'Template' => 'image'
              ]);
            }
          }
        },

Awesome, works now :+1: full code for anyone interested :slight_smile:

'file.create:after' => function($file) {

  // Define the right field data when uploading a file
  $mediaImage = [
    'Alt'     => '',
    'Caption' => '',
  ];
  $mediaVideo = [
    'Caption'     => '',
    'Autoplay'    => 'true',
    'Controls'    => 'true',
    'Loop'        => 'true',
    'Muted'       => 'true',
    'Playsinline' => 'false',
  ];

  // Append the data and template name
  if ($user = kirby()->user()) {
    if ((($file->page() && $file->page()->parent()) || $user->role()->name() === 'author') && $file->type() === 'image' && $file->template() !== 'avatar') {
      $file->update(
        A::append($mediaImage, ['template' => 'image-author'])
      );
    } elseif ($file->type() === 'image' && $file->template() !== 'avatar') {
      $file->update(
        A::append($mediaImage, ['template' => 'image'])
      );
    } elseif ((($file->page() && $file->page()->parent()) || $user->role()->name() === 'author') && $file->type() === 'video') {
      $file->update(
        A::append($mediaVideo, ['template' => 'video-author'])
      );
    } elseif ($file->type() === 'video') {
      $file->update(
        A::append($mediaVideo, ['template' => 'video'])
      );
    }
  }
}

Edit: Added $file->page() && $file->page()->parent() because if and admin or another user role uploaded a file to a blog post, the author couldn’t edit the file or delete etc.

@texnixe Might you have a look at this one: https://github.com/getkirby/ideas/issues/492

IMHO, problems as outlined in this thread would be easily solvable then, isn’t it?

I’m faced with very similar requirements. But to “abuse” hooks for ACLs feels very odd to me.

@steirico Yes, I’ve already seen this issue and I wish there was an easier way to set ACLs than using hooks. While I’m with @lukasbestle that the callbacks we had in Kirby 2 introduced other issues and were difficult to handle, these hooks don’t make it more reliable in my opinion.

If we could at least set permissions on the blueprint level using queries, something like:

options:
  read: "{{ page.authorIsCurrentUser }}"

that would introduce a lot more flexibility, I think.

1 Like

That‘s a nice idea!

That’s another way to address the issue.

Where is the right place to discuss this?

But as far as I’m familiar with kirby’s core code base, I doubt that the proposed solution will be more reliable.

I have added the idea to the GitHub issue to keep everything in one place.

1 Like