Refactor the permissions app

Use the new AddRemove View for the Role's group and
permissions views as well as the Group's role views.

Convert the API to use viewsets.

Add more tests.

Add role created and edited events.

Add event subscription support to roles.

Signed-off-by: Roberto Rosario <Roberto.Rosario@mayan-edms.com>
This commit is contained in:
Roberto Rosario
2019-02-12 03:36:16 -04:00
parent 1fee7260e4
commit f3f7b4bb7d
13 changed files with 1269 additions and 521 deletions

View File

@@ -1,77 +1,180 @@
from __future__ import unicode_literals
from rest_framework import generics
from rest_framework import status, viewsets
from rest_framework.response import Response
from rest_framework.decorators import action
from mayan.apps.rest_api.filters import MayanObjectPermissionsFilter
from mayan.apps.rest_api.permissions import MayanPermission
from mayan.apps.rest_api.viewsets import MayanAPIModelViewSet
from mayan.apps.user_management.permissions import permission_group_view
from mayan.apps.user_management.serializers import GroupSerializer
from .classes import Permission
from .classes import PermissionNamespace
from .models import Role
from .permissions import (
permission_role_create, permission_role_delete, permission_role_edit,
permission_role_view
)
from .serializers import (
PermissionSerializer, RoleSerializer, WritableRoleSerializer
PermissionNamespaceSerializer, PermissionSerializer, RoleGroupAddRemoveSerializer,
RolePermissionAddRemoveSerializer, RoleSerializer
)
class APIPermissionList(generics.ListAPIView):
"""
get: Returns a list of all the available permissions.
"""
class PermissionNamespaceViewSet(viewsets.ReadOnlyModelViewSet):
lookup_field = 'name'
lookup_url_kwarg = 'permission_namespace_name'
serializer_class = PermissionNamespaceSerializer
def get_object(self):
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
return PermissionNamespace.get(**filter_kwargs)
@action(
detail=True, serializer_class=PermissionSerializer,
url_name='permission-list', url_path='permissions'
)
def permission_list(self, request, *args, **kwargs):
queryset = self.get_object().permissions
page = self.paginate_queryset(queryset)
serializer = self.get_serializer(
queryset, many=True, context={'request': request}
)
if page is not None:
return self.get_paginated_response(serializer.data)
return Response(serializer.data)
def get_queryset(self):
return PermissionNamespace.all()
class PermissionViewSet(viewsets.ReadOnlyModelViewSet):
lookup_field = 'pk'
lookup_url_kwarg = 'permission_name'
lookup_value_regex = r'[\w\.]+'
serializer_class = PermissionSerializer
queryset = Permission.all()
def get_object(self):
namespace = PermissionNamespace.get(name=self.kwargs['permission_namespace_name'])
permissions = namespace.get_permissions()
return permissions.get(self.kwargs['permission_name'])
class APIRoleListView(generics.ListCreateAPIView):
"""
get: Returns a list of all the roles.
post: Create a new role.
"""
filter_backends = (MayanObjectPermissionsFilter,)
mayan_object_permissions = {'GET': (permission_role_view,)}
mayan_view_permissions = {'POST': (permission_role_create,)}
permission_classes = (MayanPermission,)
queryset = Role.objects.all()
def get_serializer(self, *args, **kwargs):
if not self.request:
return None
return super(APIRoleListView, self).get_serializer(*args, **kwargs)
def get_serializer_class(self):
if self.request.method == 'GET':
return RoleSerializer
elif self.request.method == 'POST':
return WritableRoleSerializer
class APIRoleView(generics.RetrieveUpdateDestroyAPIView):
"""
delete: Delete the selected role.
get: Return the details of the selected role.
patch: Edit the selected role.
put: Edit the selected role.
"""
mayan_object_permissions = {
'GET': (permission_role_view,),
'PUT': (permission_role_edit,),
'PATCH': (permission_role_edit,),
'DELETE': (permission_role_delete,)
class RoleAPIViewSet(MayanAPIModelViewSet):
lookup_url_kwarg = 'role_id'
object_permission_map = {
'destroy': permission_role_delete,
'group_add': permission_role_edit,
'group_list': permission_role_view,
'group_remove': permission_role_edit,
'list': permission_role_view,
'partial_update': permission_role_edit,
'retrieve': permission_role_view,
'update': permission_role_edit,
}
permission_classes = (MayanPermission,)
queryset = Role.objects.all()
serializer_class = RoleSerializer
view_permission_map = {
'create': permission_role_create
}
def get_serializer(self, *args, **kwargs):
if not self.request:
return None
@action(
detail=True, lookup_url_kwarg='role_id', methods=('post',),
serializer_class=RoleGroupAddRemoveSerializer,
url_name='group-add', url_path='groups/add'
)
def group_add(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.groups_add(instance=instance)
headers = self.get_success_headers(data=serializer.data)
return Response(
serializer.data, status=status.HTTP_200_OK, headers=headers
)
return super(APIRoleView, self).get_serializer(*args, **kwargs)
@action(
detail=True, lookup_url_kwarg='role_id',
serializer_class=GroupSerializer, url_name='group-list',
url_path='groups'
)
def group_list(self, request, *args, **kwargs):
queryset = self.get_object().get_groups(
permission=permission_group_view, user=self.request.user
)
page = self.paginate_queryset(queryset)
def get_serializer_class(self):
if self.request.method == 'GET':
return RoleSerializer
elif self.request.method in ('PATCH', 'PUT'):
return WritableRoleSerializer
serializer = self.get_serializer(
queryset, many=True, context={'request': request}
)
if page is not None:
return self.get_paginated_response(serializer.data)
return Response(serializer.data)
@action(
detail=True, lookup_url_kwarg='role_id',
methods=('post',), serializer_class=RoleGroupAddRemoveSerializer,
url_name='group-remove', url_path='groups/remove'
)
def group_remove(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.groups_remove(instance=instance)
headers = self.get_success_headers(data=serializer.data)
return Response(
serializer.data, status=status.HTTP_200_OK, headers=headers
)
@action(
detail=True, lookup_url_kwarg='role_id', methods=('post',),
serializer_class=RolePermissionAddRemoveSerializer,
url_name='permission-add', url_path='permissions/add'
)
def permission_add(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.permissions_add(instance=instance)
headers = self.get_success_headers(data=serializer.data)
return Response(
serializer.data, status=status.HTTP_200_OK, headers=headers
)
@action(
detail=True, lookup_url_kwarg='role_id',
serializer_class=PermissionSerializer, url_name='permission-list',
url_path='permissions'
)
def permission_list(self, request, *args, **kwargs):
queryset = self.get_object().permissions.all()
page = self.paginate_queryset(queryset)
serializer = self.get_serializer(
queryset, many=True, context={'request': request}
)
if page is not None:
return self.get_paginated_response(serializer.data)
return Response(serializer.data)
@action(
detail=True, lookup_url_kwarg='role_id',
methods=('post',), serializer_class=RolePermissionAddRemoveSerializer,
url_name='permission-remove', url_path='permissions/remove'
)
def permission_remove(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.permissions_remove(instance=instance)
headers = self.get_success_headers(data=serializer.data)
return Response(
serializer.data, status=status.HTTP_200_OK, headers=headers
)

View File

@@ -13,14 +13,20 @@ from mayan.apps.common import (
menu_secondary, menu_setup
)
from mayan.apps.common.signals import perform_upgrade
from mayan.apps.events import ModelEventType
from mayan.apps.events.links import (
link_events_for_object, link_object_event_types_user_subcriptions_list
)
from mayan.apps.navigation import SourceColumn
from .events import event_role_created, event_role_edited
from .handlers import handler_purge_permissions
from .links import (
link_group_roles, link_permission_grant, link_permission_revoke,
link_role_create, link_role_delete, link_role_edit, link_role_groups,
link_role_list, link_role_permissions
)
from .methods import method_group_roles_add, method_group_roles_remove
from .permissions import (
permission_role_delete, permission_role_edit, permission_role_view
)
@@ -37,10 +43,18 @@ class PermissionsApp(MayanAppConfig):
def ready(self):
super(PermissionsApp, self).ready()
from actstream import registry
Role = self.get_model('Role')
Group = apps.get_model(app_label='auth', model_name='Group')
Group.add_to_class(name='roles_add', value=method_group_roles_add)
Group.add_to_class(name='roles_remove', value=method_group_roles_remove)
ModelEventType.register(
event_types=(event_role_created, event_role_edited), model=Role
)
ModelPermission.register(
model=Role, permissions=(
permission_acl_edit, permission_acl_view,
@@ -53,7 +67,9 @@ class PermissionsApp(MayanAppConfig):
menu_list_facet.bind_links(
links=(
link_acl_list, link_role_groups, link_role_permissions,
link_acl_list, link_events_for_object,
link_object_event_types_user_subcriptions_list,
link_role_groups, link_role_permissions,
), sources=(Role,)
)
menu_list_facet.bind_links(
@@ -78,3 +94,5 @@ class PermissionsApp(MayanAppConfig):
dispatch_uid='permissions_handler_purge_permissions',
receiver=handler_purge_permissions
)
registry.register(Role)

View File

@@ -2,15 +2,12 @@ from __future__ import unicode_literals
import itertools
import logging
import warnings
from django.apps import apps
from django.core.exceptions import PermissionDenied
from django.utils.encoding import force_text, python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
from mayan.apps.common.warnings import InterfaceWarning
from .exceptions import InvalidNamespace
logger = logging.getLogger(__name__)
@@ -49,6 +46,13 @@ class PermissionNamespace(object):
self.permissions.append(permission)
return permission
def get_permissions(self):
result = {}
for permission in self.permissions:
result[permission.pk] = permission
return result
@python_2_unicode_compatible
class Permission(object):

View File

@@ -0,0 +1,16 @@
from __future__ import absolute_import, unicode_literals
from django.utils.translation import ugettext_lazy as _
from mayan.apps.events import EventTypeNamespace
namespace = EventTypeNamespace(
label=_('Permissions'), name='permissions'
)
event_role_created = namespace.add_event_type(
label=_('Role created'), name='role_created'
)
event_role_edited = namespace.add_event_type(
label=_('Role edited'), name='role_edited'
)

View File

@@ -0,0 +1,43 @@
from __future__ import unicode_literals
from django.apps import apps
from django.db import transaction
from mayan.apps.user_management.events import event_group_edited
from .events import event_role_edited
def method_group_get_roles(self, permission, _user):
AccessControlList = apps.get_model(
app_label='acls', model_name='AccessControlList'
)
return AccessControlList.objects.restrict_queryset(
permission=permission, queryset=self.roles.all(),
user=_user
)
def method_group_roles_add(self, queryset, _user):
with transaction.atomic():
event_group_edited.commit(
actor=_user, target=self
)
for role in queryset:
self.roles.add(role)
event_role_edited.commit(
actor=_user, action_object=self, target=role
)
def method_group_roles_remove(self, queryset, _user):
with transaction.atomic():
event_group_edited.commit(
actor=_user, target=self
)
for role in queryset:
self.roles.remove(role)
event_role_edited.commit(
actor=_user, action_object=self, target=role
)

View File

@@ -2,13 +2,17 @@ from __future__ import unicode_literals
import logging
from django.apps import apps
from django.contrib.auth.models import Group
from django.db import models
from django.db import models, transaction
from django.urls import reverse
from django.utils.encoding import force_text, python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
from mayan.apps.user_management.events import event_group_edited
from .classes import Permission
from .events import event_role_created, event_role_edited
from .managers import RoleManager, StoredPermissionManager
logger = logging.getLogger(__name__)
@@ -118,9 +122,70 @@ class Role(models.Model):
def grant(self, permission):
self.permissions.add(permission.stored_permission)
def get_groups(self, permission, user):
AccessControlList = apps.get_model(
app_label='acls', model_name='AccessControlList'
)
return AccessControlList.objects.restrict_queryset(
permission=permission, queryset=self.groups.all(),
user=user
)
def groups_add(self, queryset, _user=None):
with transaction.atomic():
event_role_edited.commit(
actor=_user, target=self
)
for obj in queryset:
self.groups.add(obj)
event_group_edited.commit(
actor=_user, action_object=self, target=obj
)
def groups_remove(self, queryset, _user=None):
with transaction.atomic():
event_role_edited.commit(
actor=_user, target=self
)
for obj in queryset:
self.groups.remove(obj)
event_group_edited.commit(
actor=_user, action_object=self, target=obj
)
def natural_key(self):
return (self.label,)
natural_key.dependencies = ['auth.Group', 'permissions.StoredPermission']
def permissions_add(self, queryset, _user=None):
with transaction.atomic():
event_role_edited.commit(
actor=_user, target=self
)
self.permissions.add(*queryset)
def permissions_remove(self, queryset, _user=None):
with transaction.atomic():
event_role_edited.commit(
actor=_user, target=self
)
self.permissions.remove(*queryset)
def revoke(self, permission):
self.permissions.remove(permission.stored_permission)
def save(self, *args, **kwargs):
_user = kwargs.pop('_user', None)
with transaction.atomic():
is_new = not self.pk
super(Role, self).save(*args, **kwargs)
if is_new:
event_role_created.commit(
actor=_user, target=self
)
else:
event_role_edited.commit(
actor=_user, target=self
)

View File

@@ -4,18 +4,45 @@ from django.contrib.auth.models import Group
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from mayan.apps.user_management.serializers import GroupSerializer
from mayan.apps.rest_api.mixins import ExternalObjectListSerializerMixin
from mayan.apps.rest_api.relations import MultiKwargHyperlinkedIdentityField
from mayan.apps.user_management.permissions import permission_group_edit
from .classes import Permission
from .models import Role, StoredPermission
class PermissionNamespaceSerializer(serializers.Serializer):
name = serializers.CharField(read_only=True)
label = serializers.CharField(read_only=True)
permissions_url = serializers.HyperlinkedIdentityField(
lookup_field='name',
lookup_url_kwarg='permission_namespace_name',
view_name='rest_api:permission_namespace-permission-list'
)
url = serializers.HyperlinkedIdentityField(
lookup_field='name',
lookup_url_kwarg='permission_namespace_name',
view_name='rest_api:permission_namespace-detail'
)
class PermissionSerializer(serializers.Serializer):
namespace = serializers.CharField(read_only=True)
pk = serializers.CharField(read_only=True)
label = serializers.CharField(read_only=True)
url = MultiKwargHyperlinkedIdentityField(
view_kwargs=(
{
'lookup_field': 'namespace.name', 'lookup_url_kwarg': 'permission_namespace_name',
},
{
'lookup_field': 'pk', 'lookup_url_kwarg': 'permission_name',
}
),
view_name='rest_api:permission-detail'
)
def to_representation(self, instance):
if isinstance(instance, StoredPermission):
@@ -28,85 +55,85 @@ class PermissionSerializer(serializers.Serializer):
)
class RoleGroupAddRemoveSerializer(ExternalObjectListSerializerMixin, serializers.Serializer):
group_id_list = serializers.CharField(
help_text=_(
'Comma separated list of group primary keys that will be added or '
'removed.'
), required=False, write_only=True
)
class Meta:
external_object_list_model = Group
external_object_list_permission = permission_group_edit
external_object_list_pk_list_field = 'group_id_list'
def groups_add(self, instance):
instance.groups_add(
queryset=self.get_external_object_list(),
_user=self.context['request'].user
)
def groups_remove(self, instance):
instance.groups_remove(
queryset=self.get_external_object_list(),
_user=self.context['request'].user
)
class RolePermissionAddRemoveSerializer(ExternalObjectListSerializerMixin, serializers.Serializer):
permission_id_list = serializers.CharField(
help_text=_(
'Comma separated list of permission primary keys that will be added or '
'removed.'
), required=False, write_only=True
)
class Meta:
external_object_list_model = Permission
external_object_list_pk_list_field = 'permission_id_list'
def permissions_add(self, instance):
instance.permissions.add(
*self.get_external_object_list()
)
def permissions_remove(self, instance):
instance.permissions.remove(
*self.get_external_object_list()
)
class RoleSerializer(serializers.HyperlinkedModelSerializer):
groups = GroupSerializer(many=True, read_only=True)
permissions = PermissionSerializer(many=True, read_only=True)
group_add_url = serializers.HyperlinkedIdentityField(
lookup_url_kwarg='role_id', view_name='rest_api:role-group-add'
)
group_list_url = serializers.HyperlinkedIdentityField(
lookup_url_kwarg='role_id', view_name='rest_api:role-group-list'
)
group_remove_url = serializers.HyperlinkedIdentityField(
lookup_url_kwarg='role_id', view_name='rest_api:role-group-remove'
)
permission_add_url = serializers.HyperlinkedIdentityField(
lookup_url_kwarg='role_id', view_name='rest_api:role-permission-add'
)
permission_list_url = serializers.HyperlinkedIdentityField(
lookup_url_kwarg='role_id', view_name='rest_api:role-permission-list'
)
permission_remove_url = serializers.HyperlinkedIdentityField(
lookup_url_kwarg='role_id', view_name='rest_api:role-permission-remove'
)
class Meta:
extra_kwargs = {
'url': {'view_name': 'rest_api:role-detail'},
'url': {
'lookup_url_kwarg': 'role_id',
'view_name': 'rest_api:role-detail'
}
}
fields = ('groups', 'id', 'label', 'permissions', 'url')
fields = (
'id', 'label', 'url', 'group_add_url', 'group_list_url',
'group_remove_url', 'permission_add_url', 'permission_list_url',
'permission_remove_url'
)
model = Role
class WritableRoleSerializer(serializers.HyperlinkedModelSerializer):
groups_pk_list = serializers.CharField(
help_text=_(
'Comma separated list of groups primary keys to add to, or replace'
' in this role.'
), required=False
)
permissions_pk_list = serializers.CharField(
help_text=_(
'Comma separated list of permission primary keys to grant to this '
'role.'
), required=False
)
class Meta:
fields = ('groups_pk_list', 'id', 'label', 'permissions_pk_list')
model = Role
def create(self, validated_data):
self.groups_pk_list = validated_data.pop('groups_pk_list', '')
self.permissions_pk_list = validated_data.pop(
'permissions_pk_list', ''
)
instance = super(WritableRoleSerializer, self).create(validated_data)
if self.groups_pk_list:
self._add_groups(instance=instance)
if self.permissions_pk_list:
self._add_permissions(instance=instance)
return instance
def _add_groups(self, instance):
instance.groups.add(
*Group.objects.filter(pk__in=self.groups_pk_list.split(','))
)
def _add_permissions(self, instance):
for pk in self.permissions_pk_list.split(','):
try:
stored_permission = Permission.get(pk=pk)
instance.permissions.add(stored_permission)
instance.save()
except KeyError:
raise ValidationError(_('No such permission: %s') % pk)
def update(self, instance, validated_data):
result = validated_data.copy()
self.groups_pk_list = validated_data.pop('groups_pk_list', '')
self.permissions_pk_list = validated_data.pop(
'permissions_pk_list', ''
)
result = super(WritableRoleSerializer, self).update(
instance, validated_data
)
if self.groups_pk_list:
instance.groups.clear()
self._add_groups(instance=instance)
if self.permissions_pk_list:
instance.permissions.clear()
self._add_permissions(instance=instance)
return result

View File

@@ -1,11 +1,11 @@
from __future__ import unicode_literals
TEST_CASE_ROLE_LABEL = 'test case role'
TEST_CASE_ROLE_LABEL = 'test case role label'
TEST_INVALID_PERMISSION_NAMESPACE_NAME = 'invalid namespace'
TEST_INVALID_PERMISSION_NAME = 'invalid name'
TEST_PERMISSION_NAMESPACE_LABEL = 'test namespace label'
TEST_PERMISSION_NAMESPACE_NAME = 'test namespace'
TEST_PERMISSION_LABEL = 'test name label'
TEST_PERMISSION_NAME = 'test name'
TEST_ROLE_LABEL = 'test role 2'
TEST_PERMISSION_NAMESPACE_LABEL = 'test permission namespace label'
TEST_PERMISSION_NAMESPACE_NAME = 'test_permission_namespace_name'
TEST_PERMISSION_LABEL = 'test permission name label'
TEST_PERMISSION_NAME = '{}.{}'.format(TEST_PERMISSION_NAMESPACE_NAME, 'test_permission_name')
TEST_ROLE_LABEL = 'test role label'
TEST_ROLE_LABEL_EDITED = 'test role label edited'

View File

@@ -1,8 +1,25 @@
from __future__ import unicode_literals
from ..classes import PermissionNamespace
from ..models import Role
from .literals import TEST_CASE_ROLE_LABEL, TEST_ROLE_LABEL
from .literals import (
TEST_CASE_ROLE_LABEL, TEST_PERMISSION_LABEL, TEST_PERMISSION_NAME,
TEST_PERMISSION_NAMESPACE_LABEL, TEST_PERMISSION_NAMESPACE_NAME,
TEST_ROLE_LABEL
)
class PermissionTestMixin(object):
def _create_test_permission(self):
self.test_permission_namespace = PermissionNamespace(
label=TEST_PERMISSION_NAMESPACE_LABEL,
name=TEST_PERMISSION_NAMESPACE_NAME
)
self.test_permission = self.test_permission_namespace.add_permission(
label=TEST_PERMISSION_LABEL,
name=TEST_PERMISSION_NAME
)
class RoleTestCaseMixin(object):

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,9 @@ from __future__ import unicode_literals
from django.conf.urls import url
from .api_views import APIPermissionList, APIRoleListView, APIRoleView
from .api_views import (
PermissionNamespaceViewSet, PermissionViewSet, RoleAPIViewSet
)
from .views import (
GroupRolesView, RoleCreateView, RoleDeleteView, RoleEditView,
RoleGroupsView, RoleListView, RolePermissionsView
@@ -36,14 +38,14 @@ urlpatterns = [
url(regex=r'^roles/list/$', name='role_list', view=RoleListView.as_view()),
]
api_urls = [
url(
regex=r'^permissions/$', name='permission-list',
view=APIPermissionList.as_view(),
),
url(regex=r'^roles/$', name='role-list', view=APIRoleListView.as_view()),
url(
regex=r'^roles/(?P<role_id>[0-9]+)/$', name='role-detail',
view=APIRoleView.as_view()
),
]
api_router_entries = (
{
'prefix': r'permission_namespaces', 'viewset': PermissionNamespaceViewSet,
'basename': 'permission_namespace'
},
{
'prefix': r'permission_namespaces/(?P<permission_namespace_name>[^/.]+)/permissions',
'viewset': PermissionViewSet, 'basename': 'permission'
},
{'prefix': r'roles', 'viewset': RoleAPIViewSet, 'basename': 'role'},
)

View File

@@ -1,22 +1,17 @@
from __future__ import unicode_literals
import itertools
from django.contrib.auth.models import Group
from django.shortcuts import get_object_or_404
from django.template import RequestContext
from django.urls import reverse_lazy
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
from mayan.apps.acls.models import AccessControlList
from mayan.apps.common.generics import (
AssignRemoveView, SingleObjectCreateView, SingleObjectDeleteView,
AddRemoveView, SingleObjectCreateView, SingleObjectDeleteView,
SingleObjectEditView, SingleObjectListView
)
from mayan.apps.user_management.permissions import permission_group_edit
from .classes import Permission, PermissionNamespace
from .icons import icon_role_list
from .links import link_role_create
from .models import Role, StoredPermission
@@ -26,45 +21,33 @@ from .permissions import (
)
class GroupRolesView(AssignRemoveView):
grouped = False
left_list_title = _('Available roles')
right_list_title = _('Group roles')
object_permission = permission_group_edit
class GroupRolesView(AddRemoveView):
action_add_method = 'roles_add'
action_remove_method = 'roles_remove'
main_object_model = Group
main_object_permission = permission_group_edit
main_object_pk_url_kwarg = 'group_id'
secondary_object_model = Role
secondary_object_permission = permission_role_edit
list_available_title = _('Available roles')
list_added_title = _('Group roles')
related_field = 'roles'
def add(self, item):
role = get_object_or_404(klass=Role, pk=item)
self.get_object().roles.add(role)
def get_actions_extra_kwargs(self):
return {'_user': self.request.user}
def get_extra_context(self):
return {
'object': self.get_object(),
'title': _('Roles of group: %s') % self.get_object()
'object': self.main_object,
'title': _('Roles of group: %s') % self.main_object,
}
def get_object(self):
return get_object_or_404(klass=Group, pk=self.kwargs['group_id'])
def left_list(self):
return [
(force_text(role.pk), role.label) for role in set(Role.objects.all()) - set(self.get_object().roles.all())
]
def right_list(self):
return [
(force_text(role.pk), role.label) for role in self.get_object().roles.all()
]
def remove(self, item):
role = get_object_or_404(klass=Role, pk=item)
self.get_object().roles.remove(role)
class RoleCreateView(SingleObjectCreateView):
fields = ('label',)
model = Role
view_permission = permission_role_create
post_action_redirect = reverse_lazy(viewname='permissions:role_list')
view_permission = permission_role_create
class RoleDeleteView(SingleObjectDeleteView):
@@ -81,43 +64,31 @@ class RoleEditView(SingleObjectEditView):
pk_url_kwarg = 'role_id'
class RoleGroupsView(AssignRemoveView):
grouped = False
left_list_title = _('Available groups')
right_list_title = _('Role groups')
object_permission = permission_role_edit
class RoleGroupsView(AddRemoveView):
action_add_method = 'groups_add'
action_remove_method = 'groups_remove'
main_object_model = Role
main_object_permission = permission_role_edit
main_object_pk_url_kwarg = 'role_id'
secondary_object_model = Group
secondary_object_permission = permission_group_edit
list_available_title = _('Available groups')
list_added_title = _('Role groups')
related_field = 'groups'
def add(self, item):
group = get_object_or_404(klass=Group, pk=item)
self.get_object().groups.add(group)
def get_actions_extra_kwargs(self):
return {'_user': self.request.user}
def get_extra_context(self):
return {
'object': self.get_object(),
'title': _('Groups of role: %s') % self.get_object(),
'object': self.main_object,
'title': _('Groups of role: %s') % self.main_object,
'subtitle': _(
'Add groups to be part of a role. They will '
'inherit the role\'s permissions and access controls.'
),
}
def get_object(self):
return get_object_or_404(klass=Role, pk=self.kwargs['role_id'])
def left_list(self):
return [
(force_text(group.pk), group.name) for group in set(Group.objects.all()) - set(self.get_object().groups.all())
]
def remove(self, item):
group = get_object_or_404(klass=Group, pk=item)
self.get_object().groups.remove(group)
def right_list(self):
return [
(force_text(group.pk), group.name) for group in self.get_object().groups.all()
]
class RoleListView(SingleObjectListView):
model = Role
@@ -143,64 +114,48 @@ class RoleListView(SingleObjectListView):
}
class RolePermissionsView(AssignRemoveView):
class RolePermissionsView(AddRemoveView):
action_add_method = 'permissions_add'
action_remove_method = 'permissions_remove'
grouped = True
left_list_title = _('Available permissions')
object_permission = permission_role_edit
right_list_title = _('Granted permissions')
main_object_model = Role
main_object_permission = permission_role_edit
main_object_pk_url_kwarg = 'role_id'
list_available_title = _('Available permissions')
list_added_title = _('Granted permissions')
related_field = 'permissions'
secondary_object_model = StoredPermission
@staticmethod
def generate_choices(entries):
results = []
def generate_choices(self, queryset):
namespaces_dictionary = {}
entries = sorted(
entries, key=lambda x: (
x.volatile_permission.namespace.label,
x.volatile_permission.label
)
# Sort permissions by their translatable label
object_list = sorted(
queryset, key=lambda permission: permission.volatile_permission.label
)
for namespace, permissions in itertools.groupby(entries, lambda entry: entry.namespace):
permission_options = [
(force_text(permission.pk), permission) for permission in permissions
]
results.append(
(PermissionNamespace.get(name=namespace), permission_options)
# Group permissions by namespace
for permission in object_list:
namespaces_dictionary.setdefault(
permission.volatile_permission.namespace.label,
[]
)
namespaces_dictionary[permission.volatile_permission.namespace.label].append(
(permission.pk, force_text(permission))
)
return results
# Sort permissions by their translatable namespace label
return sorted(namespaces_dictionary.items())
def add(self, item):
permission = get_object_or_404(klass=StoredPermission, pk=item)
self.get_object().permissions.add(permission)
def get_actions_extra_kwargs(self):
return {'_user': self.request.user}
def get_extra_context(self):
return {
'object': self.get_object(),
'object': self.main_object,
'subtitle': _(
'Permissions granted here will apply to the entire system '
'and all objects.'
),
'title': _('Permissions for role: %s') % self.get_object(),
'title': _('Permissions for role: %s') % self.main_object,
}
def get_object(self):
return get_object_or_404(klass=Role, pk=self.kwargs['role_id'])
def left_list(self):
Permission.refresh()
return RolePermissionsView.generate_choices(
entries=StoredPermission.objects.exclude(
id__in=self.get_object().permissions.values_list('pk', flat=True)
)
)
def remove(self, item):
permission = get_object_or_404(klass=StoredPermission, pk=item)
self.get_object().permissions.remove(permission)
def right_list(self):
return RolePermissionsView.generate_choices(
entries=self.get_object().permissions.all()
)