Refactor acls app
This commit is contained in:
@@ -2,15 +2,14 @@ from __future__ import unicode_literals
|
||||
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import AccessEntry
|
||||
from .models import AccessControlList
|
||||
|
||||
|
||||
class AccessEntryAdmin(admin.ModelAdmin):
|
||||
model = AccessEntry
|
||||
class AccessControlListAdmin(admin.ModelAdmin):
|
||||
list_display = ('pk', 'role', 'permission', 'content_object')
|
||||
list_display_links = ('pk',)
|
||||
related_lookup_fields = {
|
||||
'generic': (('content_type', 'object_id'),),
|
||||
}
|
||||
|
||||
admin.site.register(AccessEntry, AccessEntryAdmin)
|
||||
admin.site.register(AccessControlList, AccessControlListAdmin)
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db.models.signals import post_migrate
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from common import (
|
||||
MayanAppConfig, menu_multi_item, menu_object, menu_secondary, menu_setup,
|
||||
menu_sidebar
|
||||
)
|
||||
from common import MayanAppConfig, menu_object, menu_sidebar
|
||||
|
||||
from .links import link_acl_new, link_acl_delete, link_acl_permissions
|
||||
from .models import AccessControlList
|
||||
|
||||
from .classes import (
|
||||
AccessHolder, AccessObject, AccessObjectClass
|
||||
)
|
||||
from .links import (
|
||||
link_acl_detail, link_acl_grant, link_acl_holder_new, link_acl_revoke
|
||||
)
|
||||
|
||||
class ACLsApp(MayanAppConfig):
|
||||
name = 'acls'
|
||||
@@ -22,6 +15,5 @@ class ACLsApp(MayanAppConfig):
|
||||
def ready(self):
|
||||
super(ACLsApp, self).ready()
|
||||
|
||||
menu_multi_item.bind_links(links=[link_acl_grant, link_acl_revoke], sources=['acls:acl_detail'])
|
||||
menu_object.bind_links(links=[link_acl_detail], sources=[AccessHolder])
|
||||
menu_sidebar.bind_links(links=[link_acl_holder_new], sources=[AccessObject])
|
||||
menu_object.bind_links(links=[link_acl_permissions, link_acl_delete], sources=[AccessControlList])
|
||||
menu_sidebar.bind_links(links=[link_acl_new], sources=['acls:acl_list'])
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import logging
|
||||
import sys
|
||||
import types
|
||||
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
@@ -138,12 +136,3 @@ class AccessObject(EncapsulatedObject):
|
||||
|
||||
class AccessObjectClass(EncapsulatedObject):
|
||||
source_object_name = 'cls'
|
||||
|
||||
|
||||
if sys.version_info < (2, 5):
|
||||
# Prior to Python 2.5, Exception was an old-style class
|
||||
def subclass_exception(name, parents, unused):
|
||||
return types.ClassType(name, parents, {})
|
||||
else:
|
||||
def subclass_exception(name, parents, module):
|
||||
return type(name, parents, {'__module__': module})
|
||||
|
||||
@@ -3,9 +3,7 @@ from __future__ import absolute_import, unicode_literals
|
||||
from django import forms
|
||||
from django.contrib.auth.models import User, Group
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.functional import SimpleLazyObject
|
||||
|
||||
from common.models import AnonymousUserSingleton
|
||||
from common.utils import get_object_name
|
||||
from permissions.models import Role
|
||||
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from navigation import Link
|
||||
|
||||
from .permissions import acls_edit_acl, acls_view_acl
|
||||
from .permissions import permission_acl_view, permission_acl_edit
|
||||
|
||||
link_acl_list = Link(permissions=[acls_view_acl], text=_('ACLs'), view='acls:acl_list')
|
||||
|
||||
link_acl_detail = Link(permissions=[acls_view_acl], text=_('Details'), view='acls:acl_detail', args=['access_object.gid', 'object.gid'])
|
||||
link_acl_grant = Link(permissions=[acls_edit_acl], text=_('Grant'), view='acls:acl_multiple_grant')
|
||||
link_acl_revoke = Link(permissions=[acls_edit_acl], text=_('Revoke'), view='acls:acl_multiple_revoke')
|
||||
link_acl_holder_new = Link(permissions=[acls_edit_acl], text=_('New holder'), view='acls:acl_holder_new', args='access_object.gid')
|
||||
def get_kwargs_factory(variable_name):
|
||||
def get_kwargs(context):
|
||||
content_type = ContentType.objects.get_for_model(context[variable_name])
|
||||
return {'app_label': '"{}"'.format(content_type.app_label), 'model': '"{}"'.format(content_type.model), 'object_id': '{}.pk'.format(variable_name)}
|
||||
|
||||
return get_kwargs
|
||||
|
||||
|
||||
link_acl_delete = Link(permissions=[permission_acl_edit], tags='dangerous', text=_('Delete'), view='acls:acl_delete', args='resolved_object.pk')
|
||||
link_acl_new = Link(permissions=[permission_acl_edit], text=_('New entry'), view='acls:acl_new', kwargs=get_kwargs_factory('resolved_object'))
|
||||
link_acl_list = Link(permissions=[permission_acl_view], text=_('ACLs'), view='acls:acl_list', kwargs=get_kwargs_factory('resolved_object'))
|
||||
link_acl_permissions = Link(permissions=[permission_acl_edit], text=_('Permissions'), view='acls:acl_permissions', args='resolved_object.pk')
|
||||
|
||||
@@ -18,6 +18,27 @@ from .classes import AccessHolder, get_source_object
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AccessControlListManager(models.Manager):
|
||||
"""
|
||||
Implement a 3 tier permission system, involving a permissions, an actor
|
||||
and an object
|
||||
"""
|
||||
|
||||
def check_access(self, permission, actor, obj):
|
||||
if actor.is_superuser or actor.is_staff:
|
||||
return True
|
||||
|
||||
user_roles = []
|
||||
for group in user.groups.all():
|
||||
for role in group.roles.all():
|
||||
user_roles.append(role)
|
||||
|
||||
if not self.filter(content_object=obj, permissions=permission, role__in=user_roles):
|
||||
raise PermissionDenied(ugettext('Insufficient access.'))
|
||||
|
||||
# TODO: add filter_objects_by_access
|
||||
|
||||
|
||||
class AccessEntryManager(models.Manager):
|
||||
"""
|
||||
Implement a 3 tier permission system, involving a permissions, an actor
|
||||
@@ -252,80 +273,3 @@ class AccessEntryManager(models.Manager):
|
||||
raise PermissionDenied
|
||||
|
||||
return object_list
|
||||
|
||||
|
||||
class DefaultAccessEntryManager(models.Manager):
|
||||
"""
|
||||
Implement a 3 tier permission system, involving a permission, an actor
|
||||
and a class or content type. This model keeps track of the access
|
||||
control lists that will be added when an instance of the recorded
|
||||
content type is created.
|
||||
"""
|
||||
def get_holders_for(self, cls):
|
||||
cls = get_source_object(cls)
|
||||
content_type = ContentType.objects.get_for_model(cls)
|
||||
holder_list = []
|
||||
#for access_entry in self.model.objects.filter(content_type=content_type):
|
||||
#if access_entry.holder_object:
|
||||
# Don't add references to non existant content type objects
|
||||
#TODO: FIX
|
||||
#entry = ClassAccessHolder.encapsulate(access_entry.holder_object)
|
||||
|
||||
#if entry not in holder_list:
|
||||
# holder_list.append(entry)
|
||||
|
||||
return holder_list
|
||||
|
||||
def has_access(self, permission, actor, cls):
|
||||
if isinstance(actor, User):
|
||||
if actor.is_superuser or actor.is_staff:
|
||||
return True
|
||||
|
||||
try:
|
||||
self.model.objects.get(
|
||||
permission=permission.stored_permission,
|
||||
holder_type=ContentType.objects.get_for_model(actor),
|
||||
holder_id=actor.pk,
|
||||
content_type=ContentType.objects.get_for_model(cls),
|
||||
)
|
||||
except self.model.DoesNotExist:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def grant(self, permission, actor, cls):
|
||||
"""
|
||||
Grant a permission (what), (to) an actor, (on) a specific class
|
||||
"""
|
||||
access_entry, created = self.model.objects.get_or_create(
|
||||
permission=permission,
|
||||
holder_type=ContentType.objects.get_for_model(actor),
|
||||
holder_id=actor.pk,
|
||||
content_type=ContentType.objects.get_for_model(cls),
|
||||
)
|
||||
return created
|
||||
|
||||
def revoke(self, permission, actor, cls):
|
||||
"""
|
||||
Revoke a permission (what), (from) an actor, (on) a specific class
|
||||
"""
|
||||
try:
|
||||
access_entry = self.model.objects.get(
|
||||
permission=permission,
|
||||
holder_type=ContentType.objects.get_for_model(actor),
|
||||
holder_id=actor.pk,
|
||||
content_type=ContentType.objects.get_for_model(cls),
|
||||
)
|
||||
access_entry.delete()
|
||||
return True
|
||||
except self.model.DoesNotExist:
|
||||
return False
|
||||
|
||||
def get_holder_permissions_for(self, cls, actor):
|
||||
if isinstance(actor, User):
|
||||
if actor.is_superuser or actor.is_staff:
|
||||
return Permission.all()
|
||||
|
||||
actor_type = ContentType.objects.get_for_model(actor)
|
||||
content_type = ContentType.objects.get_for_model(cls)
|
||||
return [access.permission for access in self.model.objects.filter(content_type=content_type, holder_type=actor_type, holder_id=actor.pk)]
|
||||
|
||||
47
mayan/apps/acls/migrations/0002_auto_20150629_1852.py
Normal file
47
mayan/apps/acls/migrations/0002_auto_20150629_1852.py
Normal file
@@ -0,0 +1,47 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('permissions', '0002_auto_20150628_0533'),
|
||||
('acls', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel(
|
||||
name='CreatorSingleton',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='defaultaccessentry',
|
||||
name='content_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='defaultaccessentry',
|
||||
name='holder_type',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='defaultaccessentry',
|
||||
name='permission',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='DefaultAccessEntry',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='accessentry',
|
||||
name='holder_id',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='accessentry',
|
||||
name='holder_type',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='accessentry',
|
||||
name='role',
|
||||
field=models.ForeignKey(default=1, verbose_name='Role', to='permissions.Role'),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
37
mayan/apps/acls/migrations/0003_auto_20150630_0442.py
Normal file
37
mayan/apps/acls/migrations/0003_auto_20150630_0442.py
Normal file
@@ -0,0 +1,37 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('contenttypes', '0001_initial'),
|
||||
('permissions', '0002_auto_20150628_0533'),
|
||||
('acls', '0002_auto_20150629_1852'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='AccessControlList',
|
||||
fields=[
|
||||
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
||||
('object_id', models.PositiveIntegerField()),
|
||||
('content_type', models.ForeignKey(related_name='object_content_type', to='contenttypes.ContentType')),
|
||||
('permissions', models.ManyToManyField(related_name='acls', verbose_name='Permissions', to='permissions.StoredPermission')),
|
||||
('role', models.ForeignKey(related_name='acls', verbose_name='Role', to='permissions.Role')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Access entry',
|
||||
'verbose_name_plural': 'Access entries',
|
||||
},
|
||||
bases=(models.Model,),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='accessentry',
|
||||
name='content_type',
|
||||
field=models.ForeignKey(related_name='object_content_type_1', to='contenttypes.ContentType'),
|
||||
preserve_default=True,
|
||||
),
|
||||
]
|
||||
18
mayan/apps/acls/migrations/0004_auto_20150630_0544.py
Normal file
18
mayan/apps/acls/migrations/0004_auto_20150630_0544.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models, migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('acls', '0003_auto_20150630_0442'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterUniqueTogether(
|
||||
name='accesscontrollist',
|
||||
unique_together=set([('content_type', 'object_id', 'role')]),
|
||||
),
|
||||
]
|
||||
@@ -6,19 +6,46 @@ from django.contrib.contenttypes import generic
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db import models
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.translation import ugettext_lazy as _, ugettext
|
||||
|
||||
from solo.models import SingletonModel
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from permissions.models import Role, StoredPermission
|
||||
|
||||
from .api import get_classes
|
||||
from .classes import AccessObjectClass
|
||||
from .managers import AccessEntryManager, DefaultAccessEntryManager
|
||||
from .managers import AccessControlListManager, AccessEntryManager
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class AccessControlList(models.Model):
|
||||
"""
|
||||
Model that hold the permission, object, actor relationship
|
||||
"""
|
||||
|
||||
content_type = models.ForeignKey(
|
||||
ContentType,
|
||||
related_name='object_content_type'
|
||||
)
|
||||
object_id = models.PositiveIntegerField()
|
||||
content_object = generic.GenericForeignKey(
|
||||
ct_field='content_type',
|
||||
fk_field='object_id'
|
||||
)
|
||||
# TODO: limit choices to the permissions valid for the content_object
|
||||
permissions = models.ManyToManyField(StoredPermission, blank=True, related_name='acls', verbose_name=_('Permissions'))
|
||||
role = models.ForeignKey(Role, related_name='acls', verbose_name=_('Role'))
|
||||
|
||||
objects = AccessControlListManager()
|
||||
|
||||
class Meta:
|
||||
unique_together = ('content_type', 'object_id', 'role')
|
||||
verbose_name = _('Access entry')
|
||||
verbose_name_plural = _('Access entries')
|
||||
|
||||
def __str__(self):
|
||||
return '{} <=> {}'.format(self.content_object, self.role)
|
||||
|
||||
|
||||
# TODO: remove
|
||||
@python_2_unicode_compatible
|
||||
class AccessEntry(models.Model):
|
||||
"""
|
||||
@@ -28,7 +55,7 @@ class AccessEntry(models.Model):
|
||||
role = models.ForeignKey(Role, verbose_name=_('Role'))
|
||||
content_type = models.ForeignKey(
|
||||
ContentType,
|
||||
related_name='object_content_type'
|
||||
related_name='object_content_type_1'
|
||||
)
|
||||
object_id = models.PositiveIntegerField()
|
||||
content_object = generic.GenericForeignKey(
|
||||
|
||||
@@ -4,7 +4,7 @@ from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from permissions import PermissionNamespace
|
||||
|
||||
acls_namespace = PermissionNamespace('acls', _('Access control lists'))
|
||||
namespace = PermissionNamespace('acls', _('Access control lists'))
|
||||
|
||||
acls_edit_acl = acls_namespace.add_permission(name='acl_edit', label=_('Edit ACLs'))
|
||||
acls_view_acl = acls_namespace.add_permission(name='acl_view', label=_('View ACLs'))
|
||||
permission_acl_edit = namespace.add_permission(name='acl_edit', label=_('Edit ACLs'))
|
||||
permission_acl_view = namespace.add_permission(name='acl_view', label=_('View ACLs'))
|
||||
|
||||
@@ -2,13 +2,12 @@ from __future__ import unicode_literals
|
||||
|
||||
from django.conf.urls import patterns, url
|
||||
|
||||
from .views import ACLCreateView, ACLDeleteView, ACLListView, ACLPermissionsView
|
||||
|
||||
urlpatterns = patterns(
|
||||
'acls.views',
|
||||
url(r'^new_holder_for/(?P<app_label>[-\w]+)/(?P<model_name>[-\w]+)/(?P<object_id>\d+)/$', 'acl_new_holder_for', name='acl_new_holder_for'),
|
||||
url(r'^list_for/(?P<app_label>[-\w]+)/(?P<model_name>[-\w]+)/(?P<object_id>\d+)/$', 'acl_list', name='acl_list'),
|
||||
url(r'^details/(?P<access_object_gid>[.\w]+)/holder/(?P<holder_object_gid>[.\w]+)/$', 'acl_detail', name='acl_detail'),
|
||||
url(r'^holder/new/(?P<access_object_gid>[.\w]+)/$', 'acl_holder_new', name='acl_holder_new'),
|
||||
|
||||
url(r'^multiple/grant/$', 'acl_grant', name='acl_multiple_grant'),
|
||||
url(r'^multiple/revoke/$', 'acl_revoke', name='acl_multiple_revoke'),
|
||||
url(r'^(?P<app_label>[-\w]+)/(?P<model>[-\w]+)/(?P<object_id>\d+)/new/$', ACLCreateView.as_view(), name='acl_new'),
|
||||
url(r'^(?P<app_label>[-\w]+)/(?P<model>[-\w]+)/(?P<object_id>\d+)/list/$', ACLListView.as_view(), name='acl_list'),
|
||||
url(r'^(?P<pk>\d+)/delete/$', ACLDeleteView.as_view(), name='acl_delete'),
|
||||
url(r'^(?P<pk>\d+)/permissions/$', ACLPermissionsView.as_view(), name='acl_permissions'),
|
||||
)
|
||||
|
||||
@@ -1,29 +1,24 @@
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import itertools
|
||||
import logging
|
||||
from json import loads
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import Http404, HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404, render_to_response
|
||||
from django.template import RequestContext
|
||||
from django.utils.http import urlencode
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.http import Http404
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from common.utils import encapsulate
|
||||
from common.widgets import two_state_template
|
||||
from permissions import Permission
|
||||
from common.views import (
|
||||
AssignRemoveView, SingleObjectCreateView, SingleObjectDeleteView,
|
||||
SingleObjectListView
|
||||
)
|
||||
from permissions import Permission, PermissionNamespace
|
||||
from permissions.models import StoredPermission
|
||||
|
||||
from .api import get_class_permissions_for
|
||||
from .classes import AccessHolder, AccessObject, AccessObjectClass
|
||||
from .forms import ClassHolderSelectionForm, HolderSelectionForm
|
||||
from .models import AccessEntry
|
||||
from .permissions import acls_edit_acl, acls_view_acl
|
||||
from .widgets import object_indentifier
|
||||
from .models import AccessControlList
|
||||
from .permissions import permission_acl_edit, permission_acl_view
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -32,327 +27,143 @@ def _permission_titles(permission_list):
|
||||
return ', '.join([unicode(permission) for permission in permission_list])
|
||||
|
||||
|
||||
def acl_list_for(request, obj, extra_context=None):
|
||||
try:
|
||||
Permission.check_permissions(request.user, [acls_view_acl])
|
||||
except PermissionDenied:
|
||||
AccessEntry.objects.check_access(acls_view_acl, request.user, obj)
|
||||
class ACLListView(SingleObjectListView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.content_type = get_object_or_404(ContentType, app_label=self.kwargs['app_label'], model=self.kwargs['model'])
|
||||
|
||||
logger.debug('obj: %s', obj)
|
||||
try:
|
||||
self.content_object = self.content_type.get_object_for_this_type(pk=self.kwargs['object_id'])
|
||||
except self.content_type.model_class().DoesNotExist:
|
||||
raise Http404
|
||||
|
||||
context = {
|
||||
'object_list': AccessEntry.objects.get_holders_for(obj),
|
||||
'title': _('Access control lists for: %s' % obj),
|
||||
'extra_columns': [
|
||||
{'name': _('Holder'), 'attribute': encapsulate(lambda x: object_indentifier(x.source_object))},
|
||||
{'name': _('Permissions'), 'attribute': encapsulate(lambda x: _permission_titles(AccessEntry.objects.get_holder_permissions_for(obj, x.source_object, db_only=True)))},
|
||||
],
|
||||
'hide_object': True,
|
||||
'access_object': AccessObject.encapsulate(obj),
|
||||
'object': obj,
|
||||
'navigation_object_list': ['object', 'access_object'],
|
||||
}
|
||||
try:
|
||||
Permission.check_permissions(request.user, permissions=(permission_acl_view,))
|
||||
except PermissionDenied:
|
||||
AccessControlList.objects.check_access(permission_acl_view, request.user, self.content_object)
|
||||
|
||||
if extra_context:
|
||||
context.update(extra_context)
|
||||
return super(ACLListView, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
return render_to_response('appearance/generic_list.html', context,
|
||||
context_instance=RequestContext(request))
|
||||
def get_queryset(self):
|
||||
return AccessControlList.objects.filter(content_type=self.content_type, object_id=self.content_object.pk)
|
||||
|
||||
|
||||
def acl_list(request, app_label, model_name, object_id):
|
||||
ct = get_object_or_404(ContentType, app_label=app_label, model=model_name)
|
||||
obj = get_object_or_404(ct.get_object_for_this_type, pk=object_id)
|
||||
return acl_list_for(request, obj)
|
||||
|
||||
|
||||
def acl_detail(request, access_object_gid, holder_object_gid):
|
||||
try:
|
||||
holder = AccessHolder.get(gid=holder_object_gid)
|
||||
access_object = AccessObject.get(gid=access_object_gid)
|
||||
except ObjectDoesNotExist:
|
||||
raise Http404
|
||||
|
||||
# return acl_detail_for(request, holder.source_object, access_object.source_object)
|
||||
return acl_detail_for(request, holder, access_object)
|
||||
|
||||
|
||||
def acl_detail_for(request, actor, obj):
|
||||
try:
|
||||
Permission.check_permissions(request.user, [acls_view_acl])
|
||||
except PermissionDenied:
|
||||
AccessEntry.objects.check_accesses([acls_view_acl], actor, obj)
|
||||
|
||||
permission_list = get_class_permissions_for(obj.source_object)
|
||||
# TODO : get all globally assigned permission, new function get_permissions_for_holder (roles aware)
|
||||
subtemplates_list = [
|
||||
{
|
||||
'name': 'appearance/generic_list_subtemplate.html',
|
||||
'context': {
|
||||
'title': _('Permissions available to: %(actor)s for %(obj)s' % {
|
||||
'actor': actor,
|
||||
'obj': obj
|
||||
}
|
||||
),
|
||||
'object_list': permission_list,
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ACLListView, self).get_context_data(**kwargs)
|
||||
context.update(
|
||||
{
|
||||
'hide_object': True,
|
||||
'object': self.content_object,
|
||||
'title': _('Access control lists for: %s' % self.content_object),
|
||||
'extra_columns': [
|
||||
{'name': _('Namespace'), 'attribute': 'namespace'},
|
||||
{'name': _('Label'), 'attribute': 'label'},
|
||||
{
|
||||
'name': _('Has permission'),
|
||||
'attribute': encapsulate(lambda permission: two_state_template(AccessEntry.objects.has_access(permission, actor, obj, db_only=True)))
|
||||
'name': _('Role'),
|
||||
'attribute': 'role'
|
||||
},
|
||||
{
|
||||
'name': _('Permissions'),
|
||||
'attribute': encapsulate(lambda x: _permission_titles(x.permissions.all()))
|
||||
},
|
||||
],
|
||||
'hide_object': True,
|
||||
}
|
||||
},
|
||||
]
|
||||
)
|
||||
|
||||
context = {
|
||||
'object': obj.source_object,
|
||||
'subtemplates_list': subtemplates_list,
|
||||
'multi_select_item_properties': {
|
||||
'permission_pk': lambda x: x.pk,
|
||||
'holder_gid': lambda x: actor.gid,
|
||||
'object_gid': lambda x: obj.gid,
|
||||
},
|
||||
'access_object': obj,
|
||||
'navigation_object_list': ['object', 'access_object'],
|
||||
'read_only': True,
|
||||
}
|
||||
|
||||
return render_to_response('appearance/generic_form.html', context,
|
||||
context_instance=RequestContext(request))
|
||||
return context
|
||||
|
||||
|
||||
def acl_grant(request):
|
||||
items_property_list = loads(request.GET.get('items_property_list', []))
|
||||
class ACLCreateView(SingleObjectCreateView):
|
||||
model = AccessControlList
|
||||
fields = ('role',)
|
||||
|
||||
next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))))
|
||||
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))))
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
content_type = get_object_or_404(ContentType, app_label=self.kwargs['app_label'], model=self.kwargs['model'])
|
||||
|
||||
items = {}
|
||||
title_suffix = []
|
||||
navigation_object = None
|
||||
navigation_object_count = 0
|
||||
|
||||
for item_properties in items_property_list:
|
||||
try:
|
||||
permission = Permission.get({'pk': item_properties['permission_pk']})
|
||||
except Permission.DoesNotExist:
|
||||
self.content_object = content_type.get_object_for_this_type(pk=self.kwargs['object_id'])
|
||||
except content_type.model_class().DoesNotExist:
|
||||
raise Http404
|
||||
|
||||
try:
|
||||
requester = AccessHolder.get(gid=item_properties['holder_gid'])
|
||||
access_object = AccessObject.get(gid=item_properties['object_gid'])
|
||||
except ObjectDoesNotExist:
|
||||
raise Http404
|
||||
|
||||
try:
|
||||
Permission.check_permissions(request.user, [acls_edit_acl])
|
||||
Permission.check_permissions(request.user, permissions=(permission_acl_edit,))
|
||||
except PermissionDenied:
|
||||
try:
|
||||
AccessEntry.objects.check_access(acls_edit_acl, request.user, access_object)
|
||||
except PermissionDenied:
|
||||
raise
|
||||
else:
|
||||
items.setdefault(requester, {})
|
||||
items[requester].setdefault(access_object, [])
|
||||
items[requester][access_object].append(permission)
|
||||
navigation_object = access_object
|
||||
navigation_object_count += 1
|
||||
else:
|
||||
items.setdefault(requester, {})
|
||||
items[requester].setdefault(access_object, [])
|
||||
items[requester][access_object].append(permission)
|
||||
navigation_object = access_object
|
||||
navigation_object_count += 1
|
||||
AccessControlList.objects.check_access(permission_acl_edit, request.user, self.content_object)
|
||||
|
||||
for requester, obj_ps in items.items():
|
||||
for obj, ps in obj_ps.items():
|
||||
title_suffix.append(_(', ').join(['"%s"' % unicode(p) for p in ps]))
|
||||
title_suffix.append(_(' for %s') % obj)
|
||||
title_suffix.append(_(' to %s') % requester)
|
||||
return super(ACLCreateView, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
if len(items_property_list) == 1:
|
||||
title_prefix = _('Are you sure you wish to grant the permission %(title_suffix)s?')
|
||||
else:
|
||||
title_prefix = _('Are you sure you wish to grant the permissions %(title_suffix)s?')
|
||||
def form_valid(self, form):
|
||||
instance = form.save(commit=False)
|
||||
instance.content_object = self.content_object
|
||||
instance.save()
|
||||
|
||||
if request.method == 'POST':
|
||||
for requester, object_permissions in items.items():
|
||||
for obj, permissions in object_permissions.items():
|
||||
for permission in permissions:
|
||||
if AccessEntry.objects.grant(permission, requester.source_object, obj.source_object):
|
||||
messages.success(request, _('Permission "%(permission)s" granted to %(actor)s for %(object)s.') % {
|
||||
'permission': permission,
|
||||
'actor': requester,
|
||||
'object': obj
|
||||
})
|
||||
else:
|
||||
messages.warning(request, _('%(actor)s, already had the permission "%(permission)s" granted for %(object)s.') % {
|
||||
'actor': requester,
|
||||
'permission': permission,
|
||||
'object': obj,
|
||||
})
|
||||
return super(ACLCreateView, self).form_valid(form)
|
||||
|
||||
return HttpResponseRedirect(next)
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ACLCreateView, self).get_context_data(**kwargs)
|
||||
context.update(
|
||||
{
|
||||
'object': self.content_object,
|
||||
'title': _('New access control lists for: %s' % self.content_object),
|
||||
}
|
||||
)
|
||||
|
||||
context = {
|
||||
'previous': previous,
|
||||
'next': next,
|
||||
}
|
||||
|
||||
context['title'] = title_prefix % {
|
||||
'title_suffix': ''.join(title_suffix),
|
||||
}
|
||||
|
||||
logger.debug('navigation_object_count: %d', navigation_object_count)
|
||||
logger.debug('navigation_object: %s', navigation_object)
|
||||
if navigation_object_count == 1:
|
||||
context['object'] = navigation_object.source_object
|
||||
|
||||
return render_to_response('appearance/generic_confirm.html', context,
|
||||
context_instance=RequestContext(request))
|
||||
return context
|
||||
|
||||
|
||||
def acl_revoke(request):
|
||||
items_property_list = loads(request.GET.get('items_property_list', []))
|
||||
class ACLDeleteView(SingleObjectDeleteView):
|
||||
model = AccessControlList
|
||||
object_permission = permission_acl_edit
|
||||
|
||||
next = request.POST.get('next', request.GET.get('next', request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))))
|
||||
previous = request.POST.get('previous', request.GET.get('previous', request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))))
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ACLDeleteView, self).get_context_data(**kwargs)
|
||||
context.update(
|
||||
{
|
||||
'object': self.get_object().content_object,
|
||||
}
|
||||
)
|
||||
|
||||
items = {}
|
||||
title_suffix = []
|
||||
navigation_object = None
|
||||
navigation_object_count = 0
|
||||
|
||||
for item_properties in items_property_list:
|
||||
try:
|
||||
permission = Permission.get({'pk': item_properties['permission_pk']})
|
||||
except Permission.DoesNotExist:
|
||||
raise Http404
|
||||
|
||||
try:
|
||||
requester = AccessHolder.get(gid=item_properties['holder_gid'])
|
||||
access_object = AccessObject.get(gid=item_properties['object_gid'])
|
||||
except ObjectDoesNotExist:
|
||||
raise Http404
|
||||
|
||||
try:
|
||||
Permission.check_permissions(request.user, [acls_edit_acl])
|
||||
except PermissionDenied:
|
||||
try:
|
||||
AccessEntry.objects.check_access(acls_edit_acl, request.user, access_object)
|
||||
except PermissionDenied:
|
||||
raise
|
||||
else:
|
||||
items.setdefault(requester, {})
|
||||
items[requester].setdefault(access_object, [])
|
||||
items[requester][access_object].append(permission)
|
||||
navigation_object = access_object
|
||||
navigation_object_count += 1
|
||||
else:
|
||||
items.setdefault(requester, {})
|
||||
items[requester].setdefault(access_object, [])
|
||||
items[requester][access_object].append(permission)
|
||||
navigation_object = access_object
|
||||
navigation_object_count += 1
|
||||
|
||||
for requester, obj_ps in items.items():
|
||||
for obj, ps in obj_ps.items():
|
||||
title_suffix.append(_(', ').join(['"%s"' % unicode(p) for p in ps]))
|
||||
title_suffix.append(_(' for %s') % obj)
|
||||
title_suffix.append(_(' from %s') % requester)
|
||||
|
||||
if len(items_property_list) == 1:
|
||||
title_prefix = _('Are you sure you wish to revoke the permission %(title_suffix)s?')
|
||||
else:
|
||||
title_prefix = _('Are you sure you wish to revoke the permissions %(title_suffix)s?')
|
||||
|
||||
if request.method == 'POST':
|
||||
for requester, object_permissions in items.items():
|
||||
for obj, permissions in object_permissions.items():
|
||||
for permission in permissions:
|
||||
if AccessEntry.objects.revoke(permission, requester.source_object, obj.source_object):
|
||||
messages.success(request, _('Permission "%(permission)s" revoked of %(actor)s for %(object)s.') % {
|
||||
'permission': permission,
|
||||
'actor': requester,
|
||||
'object': obj
|
||||
})
|
||||
else:
|
||||
messages.warning(request, _('%(actor)s, didn\'t had the permission "%(permission)s" for %(object)s.') % {
|
||||
'actor': requester,
|
||||
'permission': permission,
|
||||
'object': obj,
|
||||
})
|
||||
|
||||
return HttpResponseRedirect(next)
|
||||
|
||||
context = {
|
||||
'previous': previous,
|
||||
'next': next,
|
||||
}
|
||||
|
||||
context['title'] = title_prefix % {
|
||||
'title_suffix': ''.join(title_suffix),
|
||||
}
|
||||
|
||||
logger.debug('navigation_object_count: %d', navigation_object_count)
|
||||
logger.debug('navigation_object: %s', navigation_object)
|
||||
if navigation_object_count == 1:
|
||||
context['object'] = navigation_object.source_object
|
||||
|
||||
return render_to_response('appearance/generic_confirm.html', context,
|
||||
context_instance=RequestContext(request))
|
||||
return context
|
||||
|
||||
|
||||
def acl_new_holder_for(request, obj, extra_context=None, navigation_object=None):
|
||||
try:
|
||||
Permission.check_permissions(request.user, [acls_edit_acl])
|
||||
except PermissionDenied:
|
||||
AccessEntry.objects.check_access(acls_edit_acl, request.user, obj)
|
||||
class ACLPermissionsView(AssignRemoveView):
|
||||
grouped = True
|
||||
object_permission = permission_acl_edit
|
||||
left_list_title = _('Available permissions')
|
||||
right_list_title = _('Granted permissions')
|
||||
|
||||
if request.method == 'POST':
|
||||
form = HolderSelectionForm(request.POST)
|
||||
if form.is_valid():
|
||||
try:
|
||||
access_object = AccessObject.encapsulate(obj)
|
||||
access_holder = AccessHolder.get(form.cleaned_data['holder_gid'])
|
||||
def add(self, item):
|
||||
permission = get_object_or_404(StoredPermission, pk=item)
|
||||
self.get_object().permissions.add(permission)
|
||||
|
||||
query_string = {'navigation_object': navigation_object}
|
||||
def get_object(self):
|
||||
return get_object_or_404(AccessControlList, pk=self.kwargs['pk'])
|
||||
|
||||
return HttpResponseRedirect(
|
||||
'%s?%s' % (
|
||||
reverse('acls:acl_detail', args=[access_object.gid, access_holder.gid]),
|
||||
urlencode(query_string)
|
||||
)
|
||||
)
|
||||
except ObjectDoesNotExist:
|
||||
raise Http404
|
||||
else:
|
||||
form = HolderSelectionForm()
|
||||
def left_list(self):
|
||||
results = []
|
||||
for namespace, permissions in itertools.groupby(StoredPermission.objects.exclude(id__in=self.get_object().permissions.values_list('pk', flat=True)), lambda entry: entry.namespace):
|
||||
permission_options = [(unicode(permission.pk), permission) for permission in permissions]
|
||||
results.append((PermissionNamespace.get(namespace), permission_options))
|
||||
|
||||
context = {
|
||||
'form': form,
|
||||
'title': _('Add new holder for: %s') % obj,
|
||||
'submit_label': _('Select'),
|
||||
'object': obj,
|
||||
'access_object': AccessObject.encapsulate(obj),
|
||||
'navigation_object_list': ['object', 'access_object'],
|
||||
}
|
||||
return results
|
||||
|
||||
if extra_context:
|
||||
context.update(extra_context)
|
||||
def right_list(self):
|
||||
results = []
|
||||
for namespace, permissions in itertools.groupby(self.get_object().permissions.all(), lambda entry: entry.namespace):
|
||||
permission_options = [(unicode(permission.pk), permission) for permission in permissions]
|
||||
results.append((PermissionNamespace.get(namespace), permission_options))
|
||||
|
||||
return render_to_response('appearance/generic_form.html', context,
|
||||
context_instance=RequestContext(request))
|
||||
return results
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ACLPermissionsView, self).get_context_data(**kwargs)
|
||||
context.update(
|
||||
{
|
||||
'object': self.get_object().content_object,
|
||||
'title': _('Role "%(role)s" permission\'s for "%(object)s"') % {
|
||||
'role': self.get_object().role,
|
||||
'object': self.get_object().content_object,
|
||||
}
|
||||
}
|
||||
)
|
||||
return context
|
||||
|
||||
def acl_holder_new(request, access_object_gid):
|
||||
try:
|
||||
access_object = AccessObject.get(gid=access_object_gid)
|
||||
except ObjectDoesNotExist:
|
||||
raise Http404
|
||||
|
||||
return acl_new_holder_for(request, access_object.source_object)
|
||||
def remove(self, item):
|
||||
permission = get_object_or_404(StoredPermission, pk=item)
|
||||
self.get_object().permissions.remove(permission)
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.db.models.base import ModelBase
|
||||
|
||||
|
||||
def object_indentifier(obj):
|
||||
content_type = ContentType.objects.get_for_model(obj)
|
||||
|
||||
ct_fullname = '%s.%s' % (content_type.app_label, content_type.name)
|
||||
if isinstance(obj, ModelBase):
|
||||
label = getattr(obj._meta, 'verbose_name_plural', unicode(content_type))
|
||||
else:
|
||||
if ct_fullname == 'auth.user':
|
||||
label = obj.get_full_name()
|
||||
else:
|
||||
label = unicode(obj)
|
||||
|
||||
return mark_safe('<span>{}</span>'.format(label))
|
||||
Reference in New Issue
Block a user