October: Permission option for lists, forms and filters

Created on 9 Mar 2016  路  20Comments  路  Source: octobercms/october

I can set permissions for back-end pages. However I would like to add permission for lists columns, forms fields and filters elements. It would be nice a similar solution for this issue:

fields.yaml

fields:
    title:
        label: Title
        permission: author.plugin.access_view

columns.yaml

columns:
    name:
        label: Name
        permission: author.plugin.access_view

config_filter.yaml

scopes:
    category:
        label: autumn.tools::lang.categories.categories 
        permission: author.plugin.access_view
Medium Completed Enhancement

Most helpful comment

@bennothommo @SebastiaanKloos PR created :) https://github.com/octobercms/october/pull/4520

All 20 comments

Interesting idea.

I also need permissions for scope filters. Or how/where should I modify the query which is getting the rows for the filter? Any suggestions, @daftspunk?

public function listExtendQuery() in the controller @danielschweiger

@LukeTowers thx, I have some code there to handle access for the list, but this dont work for the filter. for list it works, but I use this filter scope also:

filter:
scopes:
region:
label: Regions
modelClass: Acme\Plugin\Models\Region
conditions: region_id in (:filtered)
nameFrom: region_code

this will be rendered as dropdown at the top of the list. in the dropdown I get ALL "Regions". even regions I don't have access to when the list loads. I just need to find a way that the regions will not be loaded into the dropdown for which I dont have access.

I think when october loads the data for the dropdowns it don't includes the query changes listExtendQuery ...

Couldn't you specify a custom method to output the available region_ids for filtering the list by?

@LukeTowers Yes I want to do this. I need to know where to place the custom method and how I can bind it to the filter scope.

gotcha. http://octobercms.com/docs/backend/lists#filter-scope-options
The options property on your filter definition will refer to a method on the modelClass Class

we definitely need this, it would be fantastic, so so useful

Also hit a point where I would need something like this. My initial solution to this was to manage the fields in the database and then extend the form fields and list columns with the fields from the database based on the users permissions. This currently won't work for scopes though at least I couldn't figure out how to dynamically add scopes. But this feature here would help me a lot and I might be able to contribute to the code myself.

So I got it working for form fields with the filterFields method. As I want a read and a edit permission for each field I generated them from the config:

    public function registerPermissions()
    {
        // Generate permissions for each field
        $config = Yaml::parseFile('plugins/author/plugin/models/model/fields.yaml');

        $fields = array_get($config, 'fields', []) +
                  array_get($config, 'tabs.fields', []) +
                  array_get($config, 'secondaryTabs.fields', []);

        $permissions = [];
        $permissionTypes = ['read', 'edit'];
        foreach ($fields as $name => $definition) {
            foreach ($permissionTypes as $type) {
                $niceName = array_get($definition, 'label', ucfirst($name));
                $permissions['author.plugin.'.$name.'.'.$type] =  [
                    'tab' => 'Your Tab Name',
                    'label' => ucfirst($type).' the '.$niceName.' field',
                ];
            }
        }
        return $permissions;
    }

and then I filter the fields based on the users permission by adding the following filterFields function to the model:

    public function filterFields($fields, $context = null)
    {
        $user = BackendAuth::getUser();
        foreach ($fields as $name => $field) {
            if (!$user->hasAccess('author.plugin.'.$name.'.edit')) {
                $field->readOnly = true;
                if (!$user->hasAccess('author.plugin.'.$name.'.read')) {
                    $field->hidden = true;
                }
            }
        }
    }

Of course author and plugin have to be changed to whatever you need.
To do what was requested here this should probably work (not tested):

    public function filterFields($fields, $context = null)
    {
        $user = BackendAuth::getUser();
        foreach ($fields as $name => $field) {                
                if (isset($field->permission) && !$user->hasAccess($field->permission)) {
                    $field->hidden = true;
                }
            }
        }
    }

Seems odd that you would grant access to the record but not to an individual attribute. Can someone give a real world example where this is useful? Just to help get a deep understanding of what we are trying to solve here.

Otherwise, a PR would be accepted that implemented this, along with supporting documentation.

We use october mostly as a data managing backend. We need this for account related data so that some people can only see or edit a limit fields/column set. Some private data or relations are only visible to selected team members and most fields are readOnly for nearly all users.

Also as an update this is easily doable by including a trait like this into the controller:

trait ColumnPermissions
{
    public function formExtendFields($form)
    {
        $user = $this->user;
        foreach ($form->getFields() as $name => $field) {
            if (!$user->hasAccess('author.plugin.'.$name.'.edit')) {
                if (!$user->hasAccess('author.plugin.'.$name.'.read')) {
                    $form->removeField($name);
                } else {
                    $field->readOnly = true;
                    $field->disabled = true;
                }
            }
        }
    }

    public function listExtendColumns($list)
    {
        foreach ($list->columns as $name => $config) {
            if (!$this->user->hasAccess('author.plugin.'.$name.'.read') &&
                !$this->user->hasAccess('author.plugin.'.$name.'.edit')) {
                $list->removeColumn($name);
            }
        }
    }
}

This together with the registerPermissions() posted above works pretty well for us as we really only need it on the controller. But if @daftspunk is considering this to be useful as part of october itself, may be I can find the time to make a PR at some point.

There are also some outstanding bugs/ missing features for readOnly fields, e.g. I couldn't get the repeater to be readOnly. Also note that disabled is important hidden is not enough :).

Well alright, PR FTW.

@CSNWEB Repeater now supports being disabled / previewMode

Great thanks a lot for the note!

@Samuell1 is going to have a crack at this.

This is very importent when working with person related data in the EU (GDPR). Would love to see such an option!

@bennothommo @SebastiaanKloos PR created :) https://github.com/octobercms/october/pull/4520

This has been merged in https://github.com/octobercms/october/commit/348040a4e485ec1499c5bc26803938142821c1b6. It'll be available in Build 460+

Was this page helpful?
0 / 5 - 0 ratings