Docs

Permissions and rules

Every model says which roles may do what with its records. Evlet checks this on every read and every write, from the browser, the API and every other caller.

#Roles and rules

Each user has a role. The common roles are admin, editor and viewer. A model lists what each role may do in its permissions:

Python
from evlet import Model, Rule


class Customer(Model):
    permissions = {
        'admin': Rule(('read', 'create', 'update', 'delete')),
        'editor': Rule(('read', 'create', 'update')),
        'viewer': Rule(('read',)),
    }

The rules:

  • Default deny. A model with permissions gives nothing to a role it does not name.
  • Operations. read, create, update and delete. Writing needs read access too.
  • Every caller. The list page, the record page, the API, actions, attachments and Link values all check the same rules.

A child table follows its document. Someone who may read the invoice may read its lines. Someone who may update the invoice may add, change and remove lines.

#Limit fields

A rule can name the fields a role may read and write. Leave a list out to mean every field. An empty tuple means no fields.

Python
permissions = {
    'admin': Rule(('read', 'create', 'update', 'delete')),
    'editor': Rule(('read', 'update'), write_fields=('email', 'phone')),
    'viewer': Rule(('read',), read_fields=('customer_name', 'active')),
}

With these rules:

  • An editor may change a customer's phone number. Changing the customer's name fails with a 403: One or more fields cannot be written.
  • A viewer sees only id, customer_name and active. The other fields are left out of every answer, not just hidden on screen.

#Limit rows with a scope

A scope is a function that takes the user and returns a filter. The role then sees and changes only the rows that match:

Python
class Deal(Model):
    permissions = {
        'admin': Rule(('read', 'create', 'update', 'delete')),
        'editor': Rule(('read', 'create', 'update'), scope=lambda user: {'stage': 'open'}),
    }

Editors see open deals only. The scope is applied in the database query, before paging and counting, so totals and page numbers match what the role may see. A save that would move a record out of the scope is refused.

#Code you write is trusted

Permissions guard people and API clients. Your own app code is trusted:

  • context calls such as context.create(...) check the permissions of the user you pass in.
  • The session inside a move or an action, self.context.session, writes without permission checks. It is your code, running inside a step that was already checked.
  • Hiding a field or a button in the browser grants nothing and removes nothing. Only the rules decide.