# Make field readonly for certain user group

**URL:** <https://discourse.getcockpit.com/t/make-field-readonly-for-certain-user-group/2055>\
**Category:** Support\
**Created:** [August 27, 2021, 11:40am UTC](https://discourse.getcockpit.com/t/make-field-readonly-for-certain-user-group/2055 "2021-08-27T11:40:42Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![math](https://avatars.discourse-cdn.com/v4/letter/m/ea666f/32.png) [@math](https://discourse.getcockpit.com/u/math)\
**Post date:** [August 27, 2021, 11:40am UTC](https://discourse.getcockpit.com/t/make-field-readonly-for-certain-user-group/2055/1 "2021-08-27T11:40:42Z")

</div>

I have a `key` field inside my collection. This field should only be editable by the admin. Any other user group should be able to view the value, but not edit it. Is this possible?

What I tried:  
Inside the Permission settings of the collection, I enabled `UPDATE` and added this php code:

```auto
<?php

if ($context->user && $context->user['group'] != 'admin')
    $context->options['fields']['key'] = false;

```

But it doesn’t seem to be working. A non-admin user can still edit and update the `key` field.

Thanks for your support!

---

<div class="post-metadata">

**Author:** ![abernh](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.getcockpit.com/abernh/32/859_2.png) [@abernh](https://discourse.getcockpit.com/u/abernh)\
**Post date:** [August 27, 2021, 1:28pm UTC](https://discourse.getcockpit.com/t/make-field-readonly-for-certain-user-group/2055/2 "2021-08-27T13:28:07Z")

</div>

There are 2 parts to your request:

## (1) Preventing the form field to be editable

Afaik there is currently no direct option you could utilize to change the collections form behavior.  
You’re facing the same question as stated here [Extend "view" class of Collections module](https://discourse.getcockpit.com/t/extend-view-class-of-collections-module/1404)

What you want is to extend the view and maybe append a JS snipped that turns your readonly-field into `readonly` for non-admins.

There is an event triggered when a template is rendered. You can hook into that event and extend the to-be-rendered-template-source.

Something along those lines

```auto
// config/bootstrap.php
<?php

$this->on('collections.entry.aside', function($collectionName){
  if(collectionName != 'YOUR_COLLECTION_NAME') return;
  
  echo '<script>document.querySelector('input[name="YOURFIELDNAME"]').readOnly = true;</script>';  

})

```

## (2) Preventing values to be saved to the DB

For preventing a value to be set I’d say you’re on the right track.

In the `UPDATE` rule scripts `$context` variable you also have the key `entry`.  
If I am not mistaken, you could screen for “is admin” and if not, then remove the admin-only-keys from the `entry` object.

```auto
<?php

if ($context->user && $context->user['group'] != 'admin'){
    unset($context->entry['key']);
}

```

This should prevent anybody but admins to “save” a value for that field.

---

<div class="post-metadata">

**Author:** ![math](https://avatars.discourse-cdn.com/v4/letter/m/ea666f/32.png) [@math](https://discourse.getcockpit.com/u/math)\
**Post date:** [August 30, 2021, 7:14am UTC](https://discourse.getcockpit.com/t/make-field-readonly-for-certain-user-group/2055/3 "2021-08-30T07:14:54Z")

</div>

Great, thanks a lot for your help!

I had trouble setting up (1) so I ended up using (2), which is totally fine for now.

The problem with (1) is that I couldn’t access the `key` input-field. Somehow Cockpit is not applying any id or name to distinguish it by.

---

<div class="post-metadata">

**Author:** ![abernh](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.getcockpit.com/abernh/32/859_2.png) [@abernh](https://discourse.getcockpit.com/u/abernh)\
**Post date:** [August 30, 2021, 7:39am UTC](https://discourse.getcockpit.com/t/make-field-readonly-for-certain-user-group/2055/4 "2021-08-30T07:39:51Z")

</div>

For (1) I see a `bind` attribute that references the fields name:

```auto
<input ref="input" class="uk-width-1-1" bind="entry.field1" type="text">

```

You could go for that instead of the input `name` attribute.

```auto
// config/bootstrap.php
<?php

$this->on('collections.entry.aside', function ($collectionName) {
    if (collectionName != 'YOUR_COLLECTION_NAME') return;

    $user = $this->module('cockpit')->getUser();
    
    if (!$user || $user['group'] != 'admin') {
        // IE11 not supported because `?.`
        echo "document.querySelector('input[bind=\"entry.key\"]')?.readOnly = true;";
    }
});
    

```

---

<div class="post-metadata">

**Author:** ![math](https://avatars.discourse-cdn.com/v4/letter/m/ea666f/32.png) [@math](https://discourse.getcockpit.com/u/math)\
**Post date:** [August 30, 2021, 9:44am UTC](https://discourse.getcockpit.com/t/make-field-readonly-for-certain-user-group/2055/5 "2021-08-30T09:44:58Z")

</div>

The idea is good. Unfortunately, in my case I cannot access any relevant input fields at all. Even using `document.querySelectorAll('input')` in the function only returns 3 input fields from another level (i.e. the search field on top), but none of the form.

Maybe you have another idea? Thanks again for the help!

---

<div class="post-metadata">

**Author:** ![abernh](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.getcockpit.com/abernh/32/859_2.png) [@abernh](https://discourse.getcockpit.com/u/abernh)\
**Post date:** [August 30, 2021, 1:48pm UTC](https://discourse.getcockpit.com/t/make-field-readonly-for-certain-user-group/2055/6 "2021-08-30T13:48:43Z")

</div>

I’m new to Cockpit and haven’t dived at all into how the Javascript lib Riot is used in the whole rendering process of the templates.

I’m suspecting this is “just” a little race-condition, where the form is not yet initialized while the template in general is mostly rendered.

So - easy hacknfix is to delay the script.

```auto
setTimeout(function(){
  document.querySelector('input[bind="entry.key"]')?.readOnly = true;
}, 100); // 100ms delay might be enough

```

The clean solution would be to “wait” until the element is present (with a `setInterval` and an additional `setTimeout` for a timeout) - but that might be just overkill and the little delay hack might do “just fine”.

---

<div class="post-metadata">

**Author:** ![math](https://avatars.discourse-cdn.com/v4/letter/m/ea666f/32.png) [@math](https://discourse.getcockpit.com/u/math)\
**Post date:** [August 30, 2021, 2:11pm UTC](https://discourse.getcockpit.com/t/make-field-readonly-for-certain-user-group/2055/7 "2021-08-30T14:11:15Z")

</div>

Nice, that was exactly what was missing to make it work. Here is my final code inside `bootstrap.php`:

```auto
        // ...

        // Disable key field:
        $app->on('collections.entry.aside', function ($collectionName) {
          if ($collectionName != 'translations') return;
          $user = $this->module('cockpit')->getUser();
          if (!$user || $user['group'] != 'admin') {
            echo "<script>
                  setTimeout(function() {
                    var inputField = document.querySelector('input[bind=\"entry.key\"]')
                    if (inputField) {
                      inputField.readOnly = true
                    }
                  }, 100);
                 </script>";
          }
        });

```

Thanks again! Glad it is working now!
