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

I’ve created a user role called “Author”. Is it possible to only allow this user to upload files when creating a post (page that is a child of another page)? For example I have a media section in site.yml, don’t want this user role to be able to add files/delete files there.

I think I’ve read you can’t set permissions per field?

If you assign a file blueprint to files, you can control what each role can do with this file “type”: https://getkirby.com/docs/reference/panel/blueprints/file

You mean assigning a template on upload? Currently if the user uploads an image, I have a template “image” assigned to the file. A template “video” if it’s a video. Can you assign multiple templates?

No, you can only assign one template per file. But you can assign different templates for files in different locations. So in a post type page you would assign a different template than in site.yml.

1 Like

Ah indeed!

Currently I assign the template with a hook and not from the blueprint. Is there a way to know you’re uploading a file from a page that is a child? In order to assign a template name called “image-post” in that case.

if ($file->type() === 'image' && $file->template() !== 'avatar') {
  $file->update([
    'Alt'      => '',
    'Caption'  => '',
    'Template' => 'image'
  ]);
} elseif ($file->type() === 'video') {
  $file->update([
    'Caption'     => '',
    'Autoplay'    => 'true',
    'Controls'    => 'true',
    'Loop'        => 'true',
    'Muted'       => 'true',
    'Playsinline' => 'false',
    'Template'    => 'video'
  ]);
}

Why? For videos you assign some default values, but for images you don’t so the hook is not really necessary. And shouldn’t it be possible to assign those default values via the blueprint for videos as well?

Child of what? Of any given page, no matter its depth? Or child of a first level page?

What if the user uploads a pdf? I need to assign the right template depending on the file the user uploads :thinking:

Same, not sure how to do this from the blueprint? I don’t know if the user picks a video or an image when uploading a file :thinking: that’s the reason I added this hook.

Ok, so you don’t use different sections for different file types? Or do you mean when they upload via a textarea or files field?

Exactly, one upload area. Same with the textarea. They all go through this hook to assign the right template.

I see, that makes sense then. As regards the conditions when to assign which template, you could for example check the page depth or other criteria (“has parents of type X” etc.), depending on what type of child page should get a different template.

I just use one level down. This seems to work, adding $file->page()->parent():

if ($file->page()->parent() && $file->type() === 'image' && $file->template() !== 'avatar') {
  $file->update([
    'Alt'      => '',
    'Caption'  => '',
    'Template' => 'image-post'
  ]);
} elseif ($file->type() === 'image' && $file->template() !== 'avatar') {
  $file->update([
    'Alt'      => '',
    'Caption'  => '',
    'Template' => 'image'
  ]);
} elseif ($file->page()->parent() && $file->type() === 'video') {
  $file->update([
    'Caption'     => '',
    'Autoplay'    => 'true',
    'Controls'    => 'true',
    'Loop'        => 'true',
    'Muted'       => 'true',
    'Playsinline' => 'false',
    'Template'    => 'video-post'
  ]);
} elseif ($file->type() === 'video') {
  $file->update([
    'Caption'     => '',
    'Autoplay'    => 'true',
    'Controls'    => 'true',
    'Loop'        => 'true',
    'Muted'       => 'true',
    'Playsinline' => 'false',
    'Template'    => 'video'
  ]);
}

To make your code a bit less repetitive, you could do it like this:

$imageFields = [
  'Alt'      => '',
  'Caption'  => '',
];
$videoFields = [
  'Caption'     => '',
  'Autoplay'    => 'true',
  'Controls'    => 'true',
  'Loop'        => 'true',
  'Muted'       => 'true',
  'Playsinline' => 'false',
];

if ($file->page()->parent() && $file->type() === 'image' && $file->template() !== 'avatar') {
  $file->update(
    A::append($imageFields, ['template' => 'image-post'])
  );
} elseif ($file->type() === 'image' && $file->template() !== 'avatar') {
  $file->update(
    A::append($imageFields, ['template' => 'image'])
  );
} elseif ($file->page()->parent() && $file->type() === 'video') {
  $file->update(
    A::append($videoFields, ['template' => 'video-post'])
  );
} elseif ($file->type() === 'video') {
  $file->update(
    A::append($imageFields, ['template' => 'video'])
  );
}

Very nice! Thanks!

I noticed that I had to add $file->page() as well or I would get “Call to a member function parent() on null” when uploading files to site.yml, thus $file->page() && $file->page()->parent().

Maybe better use the depth() as suggested above?

if ($file->parent()->depth() > 1) {
  //…
}
1 Like

Thanks!

This is a tiny problem, not that bad:

My files blueprint default.yml:

title: File

accept: image/gif, image/ico, image/jpeg, image/jpg, image/png, video/mp4, video/ogg, video/webm

Because no files fields have a template set in the blueprint, they all go through default.yml. And because of this a user with user role “Author” can add files anywhere. But after the file is added, the user can’t delete or anything, only from posts. Which is expected :+1: The issue is only that the user can add new files at places where he’s not allowed :oncoming_police_car:

I was thinking of having a secondary default-post.yml file for my files section in posts, which works… but then files won’t show up because it will only show files with that template… because files change template name after the hook :sweat_smile: Is it possible to list files from multiple templates? It’s a files section.

A files section only allows a single template (or no template at all), you can’t set multiple templates.

It’s not to set multiple templates but to show files from multiple templates. The same way I do with a query for a files field:

query: page.files.filterBy('template', 'in', ['image', 'image-post'])

Yes, but that’s the same thing in this case. There is only a template option that is responsible for filtering by template and to set the template.

With a file.create:before hook you could prevent uploads though on a per user basis as well. The downside of this approach is that the user only learns they can upload files after they tried.

An alternative would be a custom file section with a query, like this one here: GitHub - texnixe/k3-filesdisplay-section with the downside that you can’t upload files via this plugin (although such an option could be added).

1 Like

Thanks for all the details!