Site()->user() not working in panel for user forms?

I ran into something strange, whilst trying to change the visibility of fields in the user form:

# /site/users/default.yml
fields:
  arbeitsgruppen:
    label: Arbeitsgruppen
    type: checkboxes
    options: url
    url: api/arbeitsgruppen.json
    icon: users
# /site/config.php
  [
    'pattern' => 'api/arbeitsgruppen.json',
    'action' => function() {

      $groups = [];
      if( site()->user()->isAdmin() ) {
        foreach (site()->arbeitsgruppen()->yaml() as $v) {
          $groups[str::slug($v['group'])] = $v['group'];
        }
      }
      return response::json($groups);
    }
  ],
# output of URL /api/arbeitsgruppen.json as admin
{"brainpool-edi-17":"Brainpool Edi.17","service-public":"Service Public","arbeitsgruppe-3":"Arbeitsgruppe 3"}
# apache.log
PHP Fatal error:  Call to a member function isAdmin() on boolean in /site/config/config.php on line 71

So the idea is: I have a lot of users on the site. Each user is member of a group. The membership should be controlled by admin only. The groups are defined dynamically in the Site Options.
Now with the /users/default.yml any user can add himself to any group he likes.
Now my Idea was, that only admins can see the fields, all other users will not see the fields.
But now strangely enough, I can’t get the code above to work in the user form.
(also using site()->user()->hasRole('admin') is not working)

NB: I tried using a permissions hook (panel.user.update), but I was confused as to how to remove the field arbeitsgruppen from the update so I tried this way.

Any ideas? Or am I just using this wrong?
Best

//edit: I don’t necessarily have to use this way, I am open to any suggestions as to how I can prevent users from changing the field. But I thought it might have been worth mentioning, if I have encountered a bug or if it is on purpose :wink:

Unfortunately, you cannot limit access to a single field via Kirby’s permission feature, either the user can edit his/her own profile or they can’t, that’s it.

As regards the fatal error, you can prevent that kind of errors if you first check if site()->user() is true (i.e. the objects exists) before you you call a user object method.

if( site()->user() && site()->user()->isAdmin() ) {
// do stuff
}

But I don’t think this will work, anyway. If you have no options to read from, then the field would be empty and the empty status would be saved to file.

So I think the best option would be a custom field that is disabled depending on user role.

Why is that so?
[I can limit it, see https://getkirby.com/docs/cheatsheet/permissions/panel-page-update, “Intercept update data”]

Regarding the site()->user(): I am logged into the panel, therefore site()->user() must be true.
Even if I do this, the foreach will not be triggered as in site()->user() = false, which again makes no sense, as I am logged into the panel :wink:

That is strange because I only get this error message when logged out. But see my edits above as to why this solution wouldn’t work even if you could get to work.

Because Kirby’s permission features are great, but that does not mean that they cover everything. And that’s probably something nobody thought about when designing it (or whatever). So please feel free to add a feature wish on GitHub.

No you are correct as to the pre check for site()->user()
If I do this, then there is no error message, but the expression will still evaluate to false, although I am logged in.

So I think the best option would be a custom field that is disabled depending on user role.
I tried using default.yml and admin.yml with the option readonly: false / true but admin coudn’t edit it.
I will test again :slight_smile:

This does not work. Or at least as I need it:
It does make the checkboxes readonly for all users of a specific role, but this also means, admins can’t edit them either

That is a misunderstanding, I meant to create a custom panel field, you can’t set readonly options based on user roles via a blueprint.

And I don’t think the “intercept user data” permissions works like you think, you can only decide depending on some conditions if the user can update the profile or not (as in the example you linked to, the user can update any page where the title is not “Keep me”, but not that single field).

The user should be allowed to make updates, but just not to this field :wink:
This is the same advice you gave here:

But I could not work out as to how the data looks like. Eg I wanted to do

    'panel.user.update'     => function() {
      return print_r($this->target()->data());
    }

but this didn’t work, so I gave up :wink:

Yes, I understand what you want to achieve, but as I also said, it is not possible via the permissions feature.

The only solution I see is a custom Panel field.

(I’m sorry to say that I was mistaken in the other post)

oki doki :slight_smile:
at least I know not to chase that foxhole :wink:

Thanks again so so much for for your quick help!

Here’s a simple copy of the checkboxes field called “groupboxes” with disabled inputs if Panel user is not Admin:

<?php

class GroupboxesField extends RadioField {

  public function input() {

    $value = func_get_arg(0);
    $input = parent::input($value);

    $input->replaceClass('radio', 'checkbox');
    $input->attr(array(
      'name'     => $this->name() . '[]',
      'type'     => 'checkbox',
      'value'    => $value,
      'checked'  => ($this->value === 'all') ? true : in_array($value, (array)$this->value()),
      'required' => false,
      'disabled' => (panel()->user()->isAdmin()) ? false : true,
    ));


    return $input;

  }

  public function value() {

    $value = InputListField::value();

    if(!is_array($value)) {
      $value = str::split($value, ',');
    }

    // Remove items from value array that are not present in the options array
    return array_keys(array_intersect_key(array_flip($value), $this->options()));

  }

  public function result() {
    $result = parent::result();
    return is_array($result) ? implode(', ', $result) : '';
  }

  public function item($value, $text) {
    $item = parent::item($value, $text);
    $item->replaceClass('input-with-radio', 'input-with-checkbox');
    return $item;
  }

}

Save in /site/fields/groupboxes/groupboxes.php

Use in blueprint:

# /site/users/default.yml
fields:
  arbeitsgruppen:
    label: Arbeitsgruppen
    type: groupboxes
    options: url
    url: api/arbeitsgruppen.json
    icon: users

(name it whatever you like, couldn’t think of anything more intelligent right now)

1 Like

woooooooow!!!
Thank you so so much!!
This works perfectly!