Access Control for Artist Pages Based on User Name Matching Artist Name

I have a website where each artist has their own artist page and account. Anyone can access their own artist page. The issue arises when a user “Artist One” changes the URL from ‘pages/artists+artist-one?tab=content’ to ‘pages/artists+artist-two?tab=content,’ they gain access to the page of User/Artist 2 as well. Is there a way I can check with an ‘IF’ statement like the following: ‘if user.name == page.title’ to only allow access to the user who has the same name as the artist, ensuring they can access only their URL?

This should be possible with page.changeSlug:before
However, I’m stumped as to how the if query is constructed.

I’m not talking about this “Change URL”:
image

I’m talking about the URL in the Browser:
image

I am logged in with “Artist One” but if i am changing the URL to “panel/pages/artists+Artist-Two” - I am able to edit the Page of Artist-Two!

What do you do to prevent users visiting other artist pages without manually changing the URL?

I’ve got following Code in my “blueprints/editor/pages/artists.yml”:

columns:
  main:
    sections:
      pages:
        type: pagesdisplay
        layout: cards
        query: "site.find('artists').children.filterBy('title', kirby.user.name)"
        controls: false

What type of blueprint is that? A page blueprint? A user blueprint? Path looks weird.

But anyway, this just limits the the pages a user sees, but does not do anything regarding user rights.

So you would either have to use the Bouncer plugin: Bouncer | Kirby CMS

Or use a hook to prevent access to other pages.

The Code I’ve provided above is a pages Blueprint. I’ve already tried the Bouncer plugin, but that didn’t work for me, because the artist is completely bound to his page. However, I would like that the user can then, for example, use the focus plugin to change the focus of all his images.

How would the whole thing theoretically work with hooks? Is there possibly an example?

What does that mean, I don’t understand what you mean.

What exactly do you want to block for the artist user in question? If I understand correctly, such a user should only have access to their user account and their dedicated artist page in the Panel, but not to any other pages?

The Artist should only be able to access his own page and the Image Focus Page.
When I was using the Bouncer Plugin and clicked on an Image on the Artist Page to get to the Image Focus, I was redirected back to the Artist Page. I want the user to be able to open only his Artist Page and his Image Focus Page.

The artist is a user, right? Why do you have the extra artist pages in the first place and don’t use the user account page data also to display data on the frontend (aka virtual children)?

I did not know that the whole thing is also possible with the user data. Does this work in the same way as with own artist pages (is the frontend staying the same)? Is there possibly a tutorial or docs how the whole thing works?

You could basically follow one of the Virtual pages guides, e.g. Content from a database | Kirby CMS

Instead of using data from the database, you would use the user collection (filtered by user type artist), and assign the content as needed.

So what you still need is the artists parent page, and then you create an ArtistsPage model where you define the children.

1 Like

Thank you! I am going to try that!

How do I use the user collection instead of a DB?

$kirby->users()

I’ve created the Virtual Pages as suggested.

In the User Blueprint I’ve got following fields:

          mainimage:
            type: files
            layout: cards
            headline: Main Image
            template: mainimage
            required: true
          large:
            type: files
            layout: cards
            headline: Large Image
            template: large
            required: true
          gallery:
            type: files
            layout: cards
            headline: Gallery
            template: gallery

In the “Models” I’m firstly trying to get the “Largimage”:

  foreach (kirby()->users()->filterBy('role','artist') as $artist) {
            $artists[] = [
                'slug'     => strtolower(str_replace(' ', '-', $artist->name())),
                'num'      => 0,
                'template' => 'artist',
                'files'    => $page ? $page->files()->toArray() : null,
                'content'  => [
                    'text'  => $artist->name(),
                    'user'  => $artist->name(),
                    'since' => $artist->since(),
                    'largeimage' => $artist->images()->template('large'),
                    'description' => $artist->description(),
                    'uuid'  => Uuid::generate(),
                ]
            ];
        }

The Question is:
How do I get the Large Image Url? I’m just gettiing CXmJWwot/dsc06350.jpg (The UserID\Image) as image url…

 <?php $largeemage = $page->largeimage(); ?>
  <?php foreach ($largeImage as $image): ?>
      <?= $image ?>
      <img class="w-full h-full object-cover" alt=""
           src="<?= $image ?>"
           style="object-fit: cover; object-position: <?= $image->focusPercentageX() ?>% <?= $image->focusPercentageY() ?>%;">
  <?php endforeach ?>

Think you need to store these as an array:

 'largeimage' => $artist->images()->template('large')->toArray(), // should store the values in yml format

And in any case when rendering, convert the field value toFile() for a single file, or toFiles() for a file collection.

See docs on how to use a files field in templates.

It is working now. I’ve just added this line in the artists model:

'files'    => $artist ? $artist->files()->toArray() : null,

and the template code is working like this:

   <?php $largeImage = $page->images()->template('large'); ?>
                <?php foreach ($largeImage as $image): ?>
                    <img class="w-full h-full object-cover" alt=""
                         src="<?= $image->url() ?>"
                         style="object-fit: cover; object-position: <?= $image->focusPercentageX() ?>% <?= $image->focusPercentageY() ?>%;">
                <?php endforeach ?>

But I just got a new Problem:

<?php $galleryImages = $page->images()->template('gallery'); ?>
                    <?php foreach ($galleryImages as $image): ?>
                        <?= dump($image) ?>
                        <li class="splide__slide rounded-xl">
                            <div class="splidewrapper">
                                <?= $image->focusCrop(500, 600, ['focusX' => $image->focusX(), 'focusY' => $image->focusY()]); ?>
                            </div>
                        </li>
                    <?php endforeach; ?>

The FocusCrop Plugin doesn’t work anymore. On the Page the image src is: “(https://www.siriusstudios.at/media/pages/artists/samuel-leeb/ffd42c9be1-1696189247/img-1215-500x600-crop-72-50.jpg)”. But there is no cropped image in my folder. I’ve just got an .json file:
image

I’ve just dumped the image:

<?=dump($image)?>

I found out, that the content, where the focus informations are normally saved is empty on the virtual page:

[template] => gallery
[content] => Kirby\Cms\Content Object
(
)

But on the old Artist Pages, where the file was saved in the content folder it looked like this:

[template] => gallery
[content] => Kirby\Cms\Content Object
(
[focus] => {"x":0.4,"y":0.46}
[sort] => 4
[uuid] => ShSnYALzINeuhgsb
[template] => gallery
)

My theory is, that this code:

'files'    => $artist ? $artist->files()->toArray() : null,

overwrites the image informations…