Make the acls app organizations aware.

This commit is contained in:
Roberto Rosario
2016-05-25 02:43:12 -04:00
parent 27c1a33762
commit c5f64d4805
7 changed files with 70 additions and 83 deletions

View File

@@ -74,14 +74,14 @@ class AccessControlListManager(models.Manager):
pass
user_roles = []
for group in user.groups.all():
for group in user.organization_groups.all():
for role in group.roles.all():
if set(stored_permissions).intersection(set(self.get_inherited_permissions(role=role, obj=obj))):
return True
user_roles.append(role)
if not self.filter(content_type=ContentType.objects.get_for_model(obj), object_id=obj.pk, permissions__in=stored_permissions, role__in=user_roles).exists():
if not self.model.on_organization.filter(content_type=ContentType.objects.get_for_model(obj), object_id=obj.pk, permissions__in=stored_permissions, role__in=user_roles).exists():
raise PermissionDenied(ugettext('Insufficient access.'))
def filter_by_access(self, permission, user, queryset):
@@ -89,7 +89,7 @@ class AccessControlListManager(models.Manager):
return queryset
user_roles = []
for group in user.groups.all():
for group in user.organization_groups.all():
for role in group.roles.all():
user_roles.append(role)

View File

@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import organizations.shortcuts
class Migration(migrations.Migration):
dependencies = [
('organizations', '0002_add_data_default_organization'),
('acls', '0002_auto_20150703_0513'),
]
operations = [
migrations.AddField(
model_name='accesscontrollist',
name='organization',
field=models.ForeignKey(default=organizations.shortcuts.get_current_organization, to='organizations.Organization'),
),
]

View File

@@ -8,6 +8,9 @@ from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _
from organizations.models import Organization
from organizations.managers import CurrentOrganizationManager
from organizations.shortcuts import get_current_organization
from permissions.models import Role, StoredPermission
from .managers import AccessControlListManager
@@ -30,6 +33,9 @@ class AccessControlList(models.Model):
ct_field='content_type',
fk_field='object_id',
)
organization = models.ForeignKey(
Organization, default=get_current_organization
)
# TODO: limit choices to the permissions valid for the content_object
permissions = models.ManyToManyField(
StoredPermission, blank=True, related_name='acls',
@@ -38,6 +44,7 @@ class AccessControlList(models.Model):
role = models.ForeignKey(Role, related_name='acls', verbose_name=_('Role'))
objects = AccessControlListManager()
on_organization = CurrentOrganizationManager()
class Meta:
unique_together = ('content_type', 'object_id', 'role')

View File

@@ -1,16 +1,17 @@
from __future__ import absolute_import, unicode_literals
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from django.core.exceptions import PermissionDenied
from django.test import TestCase, override_settings
from documents.models import Document, DocumentType
from documents.permissions import permission_document_view
from documents.tests import TEST_SMALL_DOCUMENT_PATH, TEST_DOCUMENT_TYPE
from organizations.utils import create_default_organization
from permissions.classes import Permission
from permissions.models import Role
from permissions.tests.literals import TEST_ROLE_LABEL
from user_management.models import MayanGroup
from user_management.tests.literals import TEST_USER_USERNAME, TEST_GROUP
from ..models import AccessControlList
@@ -21,11 +22,13 @@ TEST_DOCUMENT_TYPE_2 = 'test document type 2'
@override_settings(OCR_AUTO_OCR=False)
class PermissionTestCase(TestCase):
def setUp(self):
self.document_type_1 = DocumentType.objects.create(
create_default_organization()
self.document_type_1 = DocumentType.on_organization.create(
label=TEST_DOCUMENT_TYPE
)
self.document_type_2 = DocumentType.objects.create(
self.document_type_2 = DocumentType.on_organization.create(
label=TEST_DOCUMENT_TYPE_2
)
@@ -44,19 +47,19 @@ class PermissionTestCase(TestCase):
file_object=file_object
)
self.user = get_user_model().objects.create(
self.user = get_user_model().on_organization.create(
username=TEST_USER_USERNAME
)
self.group = Group.objects.create(name=TEST_GROUP)
self.role = Role.objects.create(label=TEST_ROLE_LABEL)
self.group = MayanGroup.on_organization.create(name=TEST_GROUP)
self.role = Role.on_organization.create(label=TEST_ROLE_LABEL)
self.group.user_set.add(self.user)
self.role.groups.add(self.group)
self.role.organization_groups.add(self.group)
Permission.invalidate_cache()
def tearDown(self):
for document_type in DocumentType.objects.all():
for document_type in DocumentType.on_organization.all():
document_type.delete()
def test_check_access_without_permissions(self):
@@ -75,7 +78,7 @@ class PermissionTestCase(TestCase):
)
def test_check_access_with_acl(self):
acl = AccessControlList.objects.create(
acl = AccessControlList.on_organization.create(
content_object=self.document_1, role=self.role
)
acl.permissions.add(permission_document_view.stored_permission)
@@ -91,7 +94,7 @@ class PermissionTestCase(TestCase):
def test_filtering_with_permissions(self):
self.role.permissions.add(permission_document_view.stored_permission)
acl = AccessControlList.objects.create(
acl = AccessControlList.on_organization.create(
content_object=self.document_1, role=self.role
)
acl.permissions.add(permission_document_view.stored_permission)
@@ -104,7 +107,7 @@ class PermissionTestCase(TestCase):
)
def test_check_access_with_inherited_acl(self):
acl = AccessControlList.objects.create(
acl = AccessControlList.on_organization.create(
content_object=self.document_type_1, role=self.role
)
acl.permissions.add(permission_document_view.stored_permission)
@@ -118,12 +121,12 @@ class PermissionTestCase(TestCase):
self.fail('PermissionDenied exception was not expected.')
def test_check_access_with_inherited_acl_and_local_acl(self):
acl = AccessControlList.objects.create(
acl = AccessControlList.on_organization.create(
content_object=self.document_type_1, role=self.role
)
acl.permissions.add(permission_document_view.stored_permission)
acl = AccessControlList.objects.create(
acl = AccessControlList.on_organization.create(
content_object=self.document_3, role=self.role
)
acl.permissions.add(permission_document_view.stored_permission)
@@ -139,7 +142,7 @@ class PermissionTestCase(TestCase):
def test_filtering_with_inherited_permissions(self):
self.role.permissions.add(permission_document_view.stored_permission)
acl = AccessControlList.objects.create(
acl = AccessControlList.on_organization.create(
content_object=self.document_type_1, role=self.role
)
acl.permissions.add(permission_document_view.stored_permission)
@@ -155,12 +158,12 @@ class PermissionTestCase(TestCase):
def test_filtering_with_inherited_permissions_and_local_acl(self):
self.role.permissions.add(permission_document_view.stored_permission)
acl = AccessControlList.objects.create(
acl = AccessControlList.on_organization.create(
content_object=self.document_type_1, role=self.role
)
acl.permissions.add(permission_document_view.stored_permission)
acl = AccessControlList.objects.create(
acl = AccessControlList.on_organization.create(
content_object=self.document_3, role=self.role
)
acl.permissions.add(permission_document_view.stored_permission)

View File

@@ -33,7 +33,7 @@ class AccessControlListViewTestCase(GenericDocumentViewTestCase):
)
self.assertEquals(response.status_code, 403)
self.assertEqual(AccessControlList.objects.count(), 0)
self.assertEqual(AccessControlList.on_organization.count(), 0)
def test_acl_create_view_with_permission(self):
self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD)
@@ -49,7 +49,7 @@ class AccessControlListViewTestCase(GenericDocumentViewTestCase):
)
self.assertContains(response, text='created', status_code=200)
self.assertEqual(AccessControlList.objects.count(), 1)
self.assertEqual(AccessControlList.on_organization.count(), 1)
def test_acl_create_duplicate_view_with_permission(self):
"""
@@ -57,7 +57,7 @@ class AccessControlListViewTestCase(GenericDocumentViewTestCase):
Result: Should redirect to existing ACL for object + role combination
"""
acl = AccessControlList.objects.create(
acl = AccessControlList.on_organization.create(
content_object=self.document, role=self.role
)
@@ -76,8 +76,8 @@ class AccessControlListViewTestCase(GenericDocumentViewTestCase):
self.assertContains(
response, text='vailable permissions', status_code=200
)
self.assertEqual(AccessControlList.objects.count(), 1)
self.assertEqual(AccessControlList.objects.first().pk, acl.pk)
self.assertEqual(AccessControlList.on_organization.count(), 1)
self.assertEqual(AccessControlList.on_organization.first().pk, acl.pk)
def test_orphan_acl_create_view_with_permission(self):
"""
@@ -93,7 +93,7 @@ class AccessControlListViewTestCase(GenericDocumentViewTestCase):
recent_entry = self.document.add_as_recent_document_for_user(self.user)
content_type = ContentType.objects.get_for_model(recent_entry)
content_type = ContentType.on_organization.get_for_model(recent_entry)
view_arguments = {
'app_label': content_type.app_label,
@@ -108,4 +108,4 @@ class AccessControlListViewTestCase(GenericDocumentViewTestCase):
)
self.assertNotContains(response, text='optgroup', status_code=200)
self.assertEqual(AccessControlList.objects.count(), 1)
self.assertEqual(AccessControlList.on_organization.count(), 1)

View File

@@ -26,7 +26,6 @@ logger = logging.getLogger(__name__)
class ACLCreateView(SingleObjectCreateView):
fields = ('role',)
model = AccessControlList
def dispatch(self, request, *args, **kwargs):
self.content_type = get_object_or_404(
@@ -52,14 +51,9 @@ class ACLCreateView(SingleObjectCreateView):
return super(ACLCreateView, self).dispatch(request, *args, **kwargs)
def get_instance_extra_data(self):
return {
'content_object': self.content_object
}
def form_valid(self, form):
try:
acl = AccessControlList.objects.get(
acl = AccessControlList.on_organization.get(
content_type=self.content_type,
object_id=self.content_object.pk,
role=form.cleaned_data['role']
@@ -79,6 +73,14 @@ class ACLCreateView(SingleObjectCreateView):
) % self.content_object
}
def get_instance_extra_data(self):
return {
'content_object': self.content_object
}
def get_queryset(self):
return AccessControlList.on_organization.all()
def get_success_url(self):
if self.object.pk:
return reverse('acls:acl_permissions', args=(self.object.pk,))
@@ -87,8 +89,6 @@ class ACLCreateView(SingleObjectCreateView):
class ACLDeleteView(SingleObjectDeleteView):
model = AccessControlList
def dispatch(self, request, *args, **kwargs):
acl = get_object_or_404(AccessControlList, pk=self.kwargs['pk'])
@@ -118,6 +118,9 @@ class ACLDeleteView(SingleObjectDeleteView):
)
)
def get_queryset(self):
return AccessControlList.on_organization.all()
class ACLListView(SingleObjectListView):
def dispatch(self, request, *args, **kwargs):
@@ -152,7 +155,7 @@ class ACLListView(SingleObjectListView):
}
def get_queryset(self):
return AccessControlList.objects.filter(
return AccessControlList.on_organization.filter(
content_type=self.content_type, object_id=self.content_object.pk
)

View File

@@ -1,47 +0,0 @@
from __future__ import unicode_literals
from django.apps import apps
from django.core.management.color import no_style
from django.db import DEFAULT_DB_ALIAS, connections, router
from django.db.models import signals
def create_default_organization(app_config, verbosity=2, interactive=True, using=DEFAULT_DB_ALIAS, **kwargs):
"""
Creates the default Organization object.
"""
try:
Organization = apps.get_model('organizations', 'Organization')
except LookupError:
return
if not router.allow_migrate(using, Organization):
return
if not Organization.objects.using(using).exists():
# The default settings set ORGANIZATION_ID = 1, and some tests in Django's test
# suite rely on this value. However, if database sequences are reused
# (e.g. in the test suite after flush/syncdb), it isn't guaranteed that
# the next id will be 1, so we coerce it. See #15573 and #16353. This
# can also crop up outside of tests - see #15346.
if verbosity >= 2:
print("Creating default Organization object")
Organization(pk=1, label='Default').save(using=using)
# We set an explicit pk instead of relying on auto-incrementation,
# so we need to reset the database sequence. See #17415.
sequence_sql = connections[using].ops.sequence_reset_sql(no_style(), [Organization])
if sequence_sql:
if verbosity >= 2:
print('Resetting sequence')
with connections[using].cursor() as cursor:
for command in sequence_sql:
cursor.execute(command)
Organization.objects.clear_cache()
signals.post_migrate.connect(
create_default_organization, sender=apps.get_app_config('organizations')
)