Files
mayan-edms/mayan/apps/acls/views.py
Roberto Rosario e5cd5a40c3 Improve ACL navigation
Update the ACL delete icon for uniformity.

Insert both the ACL and object in the view to also
display the ACL permissions and delete view when
viewing the ACL of an object.

Signed-off-by: Roberto Rosario <Roberto.Rosario@mayan-edms.com>
2019-02-01 04:15:16 -04:00

249 lines
8.1 KiB
Python

from __future__ import absolute_import, unicode_literals
import itertools
import logging
from django.shortcuts import get_object_or_404
from django.template import RequestContext
from django.urls import reverse
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
from mayan.apps.common.mixins import (
ContentTypeViewMixin, ExternalObjectMixin
)
from mayan.apps.common.generics import (
AssignRemoveView, SingleObjectCreateView, SingleObjectDeleteView,
SingleObjectListView
)
from mayan.apps.permissions import Permission, PermissionNamespace
from mayan.apps.permissions.models import Role, StoredPermission
from .classes import ModelPermission
from .forms import ACLCreateForm
from .icons import icon_acl_list
from .links import link_acl_create
from .models import AccessControlList
from .permissions import permission_acl_edit, permission_acl_view
logger = logging.getLogger(__name__)
class ACLCreateView(ContentTypeViewMixin, ExternalObjectMixin, SingleObjectCreateView):
external_object_permission = permission_acl_edit
external_object_pk_url_kwarg = 'object_id'
form_class = ACLCreateForm
def get_error_message_duplicate(self):
return _(
'An ACL for "%(object)s" using role "%(role)s" already exists. '
'Edit that ACL entry instead.'
) % {'object': self.get_external_object(), 'role': self.object.role}
def get_external_object_queryset(self):
# Here we get a queryset the object model for which an ACL will be
# created.
return self.get_content_type().model_class().objects.all()
def get_extra_context(self):
return {
'object': self.get_external_object(),
'title': _(
'New access control lists for: %s'
) % self.get_external_object()
}
def get_form_extra_kwargs(self):
return {
'field_name': 'role',
'label': _('Role'),
'queryset': Role.objects.exclude(
pk__in=self.get_external_object().acls.values('role')
),
'widget_attributes': {'class': 'select2'}
}
def get_instance_extra_data(self):
return {
'content_object': self.get_external_object()
}
def get_queryset(self):
self.get_external_object().acls.all()
def get_success_url(self):
return self.object.get_absolute_url()
class ACLDeleteView(SingleObjectDeleteView):
model = AccessControlList
object_permission = permission_acl_edit
pk_url_kwarg = 'acl_id'
def get_extra_context(self):
acl = self.get_object()
return {
'acl': acl,
'object': acl.content_object,
'navigation_object_list': ('object', 'acl'),
'title': _('Delete ACL: %s') % self.get_object(),
}
def get_post_action_redirect(self):
instance = self.get_object()
return reverse(
'acls:acl_list', kwargs={
'app_label': instance.content_type.app_label,
'model': instance.content_type.model,
'object_id': instance.object_id
}
)
class ACLListView(ContentTypeViewMixin, ExternalObjectMixin, SingleObjectListView):
external_object_permission = permission_acl_view
external_object_pk_url_kwarg = 'object_id'
def get_external_object_queryset(self):
# Here we get a queryset the object model for which an ACL will be
# created.
return self.get_content_type().model_class().objects.all()
def get_extra_context(self):
return {
'hide_object': True,
'no_results_icon': icon_acl_list,
'no_results_main_link': link_acl_create.resolve(
context=RequestContext(
self.request, {
'resolved_object': self.get_external_object()
}
)
),
'no_results_title': _(
'There are no ACLs for this object'
),
'no_results_text': _(
'ACL stands for Access Control List and is a precise method '
' to control user access to objects in the system. ACLs '
'allow granting a permission to a role but only for a '
'specific object or set of objects.'
),
'object': self.get_external_object(),
'title': _(
'Access control lists for: %s' % self.get_external_object()
),
}
def get_source_queryset(self):
return self.get_external_object().acls.all()
class ACLPermissionsView(AssignRemoveView):
grouped = True
left_list_title = _('Available permissions')
right_list_title = _('Granted permissions')
@staticmethod
def generate_choices(entries):
results = []
entries = sorted(
entries, key=lambda x: (
x.volatile_permission.namespace.label,
x.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)
)
return results
def add(self, item):
permission = get_object_or_404(klass=StoredPermission, pk=item)
self.get_object().permissions.add(permission)
def get_available_list(self):
return ModelPermission.get_for_instance(
instance=self.get_object().content_object
).exclude(id__in=self.get_granted_list().values_list('pk', flat=True))
def get_disabled_choices(self):
"""
Get permissions from a parent's acls but remove the permissions we
already hold for this object
"""
return map(
str, set(
self.get_object().get_inherited_permissions().values_list(
'pk', flat=True
)
).difference(
self.get_object().permissions.values_list('pk', flat=True)
)
)
def get_extra_context(self):
acl = self.get_object()
return {
'acl': acl,
'object': acl.content_object,
'navigation_object_list': ('object', 'acl'),
'title': _('Role "%(role)s" permission\'s for "%(object)s"') % {
'role': acl.role,
'object': acl.content_object,
}
}
def get_granted_list(self):
"""
Merge of permissions we hold for this object and the permissions we
hold for this object's parent via another ACL.
"""
merged_pks = self.get_object().permissions.values_list(
'pk', flat=True
) | self.get_object().get_inherited_permissions().values_list(
'pk', flat=True
)
return StoredPermission.objects.filter(pk__in=merged_pks)
def get_object(self):
return get_object_or_404(
klass=self.get_queryset(), pk=self.kwargs['acl_id']
)
def get_queryset(self):
return AccessControlList.objects.restrict_queryset(
permission=permission_acl_edit,
queryset=AccessControlList.objects.all(), user=self.request.user
)
def get_right_list_help_text(self):
if self.get_object().get_inherited_permissions():
return _(
'Disabled permissions are inherited from a parent object and '
'can\'t be removed from this view, they need to be removed '
'from the parent object\'s ACL view.'
)
return self.right_list_help_text
def left_list(self):
Permission.refresh()
return ACLPermissionsView.generate_choices(self.get_available_list())
def remove(self, item):
permission = get_object_or_404(klass=StoredPermission, pk=item)
self.get_object().permissions.remove(permission)
def right_list(self):
return ACLPermissionsView.generate_choices(self.get_granted_list())