Permissions queries

Most of the time, queries to django-tutelary to find out whether actions are permitted will happen automatically through the PermissionRequiredMixin or APIPermissionRequiredMixin classes and django-tutelary’s custom authentication backend. However, there are cases where it can be useful to make these queries explicitly, and django-tutelary supports a couple of other query types that are documented here.

Simple permissions queries

The simplest query type involves calling User.has_perm to determine whether a particular action is permitted on a particular object. For example:

user = User.objects.get(username='iross')
page = Page.objects.get(id=1345)
result = user.has_perm('page.edit', page)

This tests whether user iross has permissions to perform the page.edit action on the Page object with id 1345. This of course requires that the Page model be enabled for django-tutelary permissioning (see Permissioning models).

Accessing permission objects

Each instance of a Django model marked up using the permissioned_model decorator has an associated django-tutelary object path. This object path can be retrieved using the get_permissions_object method added to the model by the permissioned_model decorator. The value returned from get_permissions_object is of type tutelary.engine.Object, a low-level type used for representing object paths. Values of this type can be converted to strings, so, assuming that the Page model is set up for django-tutelary versioning (with perm_type='page' and path_fields=['chapter','pageno']) the following works:

> page = Page.objects.get(chapter=3, pageno=1345)
> print('Object path:', str(page.get_permissions_object()))
Object path: page/3/1345

Permitted actions queries

As well as querying for permissions for individual actions on individual objects, it can be useful to know what actions are permitted, either for a single object or a class of objects. The django-tutelary authentication backend provides a permitted_actions method to perform this kind of query. You can get hold of the backend using Django’s get_backends function (from django.contrib.auth). Assuming you only have a single authentication backend set up, something like this will work:

> from django.contrib.auth import get_backends
> from django.contrib.auth.models import User
> from .models import Page
> backend = get_backends()[0]
> user = User.objects.get(username='iross')
> page = Page.objects.get(pageno=1345)
> page_obj = page.get_permissions_object()
> acts = backend.permitted_actions(user, page_obj)
> print([str(a) for a in acts])
['page.edit', 'page.view', 'page.delete']

The permitted_actions method takes as arguments a user object and an object or object pattern (as a tutelary.engine.Object value, which is why we call get_permissions_object on the Page object here). It returns a list of permitted actions as tutelary.engine.Action values. These are convertible to strings, which is how we display them here.

The ultimate intention of this kind of query is to implement a sort of permission-drive HATEOAS within applications: the front-end of a web application should be able to find out what actions a user is allowed to perform and modify the user interface that it displays accordingly. (Getting a list of the permitted actions for an object is only a part of that, of course, but it’s an important part!)