Working with permissions

Overview

Permission in merengue are strongly based on wonderful django-permissions application.

Main change (but important) is not using GenericForeignKey for granting permissions to objects. We prefer use a ForeignKey to BaseContent for performance reasons. Besides, in merengue all managed content are BaseContent instances.

What is an permission?

Permissions are granted to roles (and only to roles) in order to allow something to users or groups which have these roles.

What is an role?

Roles are used to grant permissions. Typical roles are Reader, Manager or Editor.

What is a local role?

Local roles are roles which are assigned to users and groups for a specific content objects.

Users

  • Users are actors which may need a permission to do something within the system.
  • Users can be member of several groups.
  • User can have several roles, directly or via a membership to a group (these are considered as global).
  • User can have local roles, directly or via a membership to a group. That is roles for a specific object.
  • Users have all roles of their groups - global and local ones.
  • Users have all permissions of their roles - global and local ones.

Groups

  • Groups combines users together.
  • Groups can have roles (these are considered as global).
  • Groups can have local roles, that is roles for a specific object.
  • Groups has all permissions of their roles - global and local ones.
  • Users of a Group have the group’s roles and permissions.

Builtin permissions on merengue

A builtin permission will appears in the manage permission view of every content.

The builtin permissions in merengue are:

View (view)
A non published content will be visible for anonymous if this permission is activated for this content.
Edit (edit)
If a user is member of a role with this permission or for a content which has activated that permission for a user role, user will can edit the content.
Delete (delete)
If user has this permission in a content, user will be able to delete it.
Can set as draft (can_draft)
If user has this permission in a content, user will can to change the content status to draft.
Can set as pending (can_pending)
If user has this permission in a content, user will can to change the content status to pending.
Can set as published (can_published)
If user has this permission in a content, user will can to change the content status to published.

Global permissions on merengue

Manage section (manage_section)
If user has this permission, user will be able to edit, delete and add sections.
Manage link portal (manage_link)
If user has this permission, user will be able to edit, delete and add portal links.
Manage menu portal (manage_menu)
If user has this permission, user will be able to edit, delete and add portal menus.
Manage multimedia (manage_multimedia)
If user has this permission, user will be able to edit, delete and add any multimedia content.
Manage plugin content (manage_plugin_content)
If user has this permission, user will be able to manage all contents from installed plugins.
Manage category (manage_category)
If user has this permission, user will be able to edit, delete and add categories.
Manage block (manage_block)
If user has this permission, user will be able to move or add blocks in public views.
Manage site (manage_site)
If user has this permission, user is like the webmaster, and he will be able to manage plugins, themes, registered items and save/restore configuration.
Manage user (manage_user)
If user has this permission, user will be able to manage groups, users, roles and permissions.

Admin interface

You can access to the permissions configuration clicking groups, users, roles or permissions in the main admin page in “User Management” portlet.

Creating a role and assigning user to role

To create a role, first you should click in “Roles” in the main admin page or go to the url http://localhost:8000/admin/perms/role/, then you click in “Add role” button. You fill the form with a name and mark the permissions for this role.

../_images/add_role.png

Finally, you must go a users admin page clicking “Users” in the main admin page or go to the url http://localhost:8000/admin/auth/user/, choose a user, add previously created role and save the form.

../_images/assign_role_to_user.png

Assigning role to group

This step is same as above, except that the user is assigned in the group admin view. You must go a groups admin page clicking “Groups” in the main admin page or go to the url http://localhost:8000/admin/auth/group/, choose a group, add previously created role and save the form.

Granting a permission to all contents

To guarantee a permission to all contents, you must assign a permission to a role. For example, if you want give edit permission for all contents to “editor” role, you must be assign the “edit” permission in role admin page.

../_images/assign_edit_permission.png

Granting a permission to a content

To see the permissions in a content, you have to go content admin page and click in “Permissions” button. Note this button is only shown if content type is basecontent.

The content permission admin page show a table with permissions and roles availables. The best way to change the permission in an object is changing the permissions for the content state, in the workflow system (see permissions and workflows), because if the content state changes, the permissions you define in this form are cleared and reset to the permissions defined for the new state.

../_images/assign_permission_content.png

Local roles

To create a local role for a content, you have to go content admin page and click in “Permissions” button. With the form shown in the image, you can assign a local role a user or a group for current content. For example, you want that a user or a group has “editor” role only for “welcome” page. You just have to fill the user or group and role fields and click in “create” button. The user and group fields will be autocompleted.

../_images/add_local_role.png

When you’ve created local roles, you can modify assigning new roles.

../_images/edit_local_role.png

Manage all permissions

There is a admin view to edit all builtin and global permissions for each role. To access to this view, you have to click on “Permissions” in the main admin page or go to the url http://localhost:8000/admin/perms/objectpermission/

../_images/global_permissions.png

Permission inheritance

Permissions in Merengue can be inherited if the ACQUIRE_SECTION_ROLES setting is defined as True. If so, every user who is accessing to an object will acquire the roles of the content’ section. So, if you set the Reviewer local role to an user in a section, he will be also Reviewer in all the section contents (news items, documents, events, etc.). Of course he will acquire also all the permissions of the Reviewer role.

Permissions and workflows

Usually, the permissions in the content are defined by its workflow. So, a content in draft status with the basic workflow workflow will have the permissions defined in the draft status inside the workflow admin view.

This is an important fact because you have to think about workflow and statuses and not thinking about the content itself.

So if for example you want to change the content permission to be visible only for the Reviewer role, the best task to do is create a new visible by reviewer status, define the permission for this status and create the transitions to make sure you can pass your content to this transition. So, doing that you will gain that if you have the same need in another content, you only have to put the content in this status.

Using the python API

Creating a custom permission

>>> from merengue.perms.utils import register_permission
>>> register_permission('Vote', 'vote')
<Permission: Vote (vote)>
>>> from merengue.perms.utils import register_permission
>>> register_permission('Vote', 'vote')

You can create a custom permission available only for some models (inherited from BaseContent):

>>> from merengue.section.models import Document
>>> from plugins.news.models import NewsItem
>>> register_permission('My permission', 'myperm',
                        for_models=[Document, NewsItem])
<Permission: My permission (myperm)>

Creating a role and assigning user to role

>>> staff_user = User.objects.create(username='roque')
>>> plain_user = User.objects.create(username='other')
>>> from merengue.perms.utils import register_role
>>> editor = register_role('Editor')
>>> editor.add_principal(staff_user) # add user to role 'Editor'

Granting a permission to a content

>>> from merengue.base.models import BaseContent
>>> content = BaseContent.objects.create(slug='mycontent', name_en='My content')
>>> from merengue.perms.utils import grant_permission
>>> grant_permission(editor, 'vote', content)

Granting a permission to all contents

>>> grant_permission(editor, 'vote')

Checking permissions

>>> from merengue.perms.utils import has_permission
>>> has_permission(content, staff_user, 'vote')
True

Removing a permission to a content

>>> from merengue.perms.utils import remove_permission
>>> remove_permission(editor, 'vote', content)

Removing a permission to all contents

>>> remove_permission(editor, 'vote')

Local roles

You can assign a role to an user or a group, globally (for all contents) or locally (to one content).

>>> othercontent = BaseContent.objects.create(slug='othercontent', name_en='Other content')
>>> grant_permission(editor, 'vote', othercontent) # like "content"
>>> from merengue.perms.utils import add_local_role
>>> add_local_role(othercontent, plain_user, editor)
# plain_user will be editor only in othercontent
>>> has_permission(content, plain_user, 'vote')
False
>>> has_permission(othercontent, plain_user, 'vote')
True # because is local editor for that content
>>> has_permission(othercontent, staff_user, 'vote')
True # because is a global editor (for all contents)

Permissions in plugins

You can create permissions for your plugins defining the function get_perms in the config.py file. These permissions can be globals or related to models and content types.

To define specific permissions, for example, to edit news:

from merengue.pluggable import Plugin
from plugins.news.models import NewsItem

class PluginConfig(Plugin):

    def get_perms(self):
        return (
            ('edit_newsitem', _('Edit news items'), [NewsItem, ]),)

To define global permissions to vote any such content:

from merengue.pluggable import Plugin

class PluginConfig(Plugin):

    def get_perms(self):
        return (
            ('vote', _('Vote content')),)