Add support for users ACLs. Add support for groups ACLs.

Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
This commit is contained in:
Roberto Rosario
2018-04-02 04:53:03 -04:00
parent 27bca4c438
commit db235a7e78
4 changed files with 161 additions and 147 deletions

View File

@@ -103,7 +103,11 @@
- Mark the feature to detect and fix the orientatin of PDF as experimental.
- Don't show documents with 0 duplicates in the duplicated document list.
- Clean up the duplicated document model after a document is deleted.
- Add support Role ACLs.
- Add support for roles ACLs.
- Add support for users ACLs.
- Add support for groups ACLs.
- Sort permission namespaces and permissions in the role permission views.
2.7.3 (2017-09-11)
==================

View File

@@ -5,6 +5,8 @@ from django.contrib.auth import get_user_model
from django.utils.translation import ugettext_lazy as _
from acls import ModelPermission
from acls.links import link_acl_list
from acls.permissions import permission_acl_edit, permission_acl_view
from common import menu_multi_item, menu_object, menu_secondary, menu_setup
from common.apps import MayanAppConfig
from common.widgets import two_state_template
@@ -70,12 +72,14 @@ class UserManagementApp(MayanAppConfig):
)
ModelPermission.register(
model=Group, permissions=(
permission_acl_edit, permission_acl_view,
permission_group_delete, permission_group_edit,
permission_group_view,
)
)
ModelPermission.register(
model=User, permissions=(
permission_acl_edit, permission_acl_view,
permission_user_delete, permission_user_edit,
permission_user_view
)
@@ -112,12 +116,12 @@ class UserManagementApp(MayanAppConfig):
sources=(Group,)
)
menu_object.bind_links(
links=(link_group_delete,), position=99, sources=(Group,)
links=(link_acl_list, link_group_delete,), position=99, sources=(Group,)
)
menu_object.bind_links(
links=(
link_user_edit, link_user_set_password, link_user_groups,
link_user_delete
link_acl_list, link_user_delete
), sources=(User,)
)
menu_secondary.bind_links(

View File

@@ -14,10 +14,14 @@ from metadata.tests.literals import (
)
from ..permissions import (
permission_user_delete, permission_user_edit, permission_user_view
permission_user_create, permission_user_delete, permission_user_edit,
permission_user_view
)
from .literals import TEST_USER_PASSWORD_EDITED, TEST_USER_USERNAME
from .literals import (
TEST_USER_PASSWORD_EDITED, TEST_USER_USERNAME, TEST_USER_2_USERNAME,
TEST_USER_2_USERNAME_EDITED
)
TEST_USER_TO_DELETE_USERNAME = 'user_to_delete'
@@ -27,157 +31,157 @@ class UserManagementViewTestCase(GenericViewTestCase):
super(UserManagementViewTestCase, self).setUp()
self.login_user()
def _request_user_create_view(self):
return self.post(
viewname='user_management:user_add', data={
'username': TEST_USER_2_USERNAME
}
)
def test_user_create_view_no_permission(self):
response = self._request_user_create_view()
self.assertEqual(response.status_code, 403)
self.assertEqual(get_user_model().objects.count(), 2)
self.assertFalse(TEST_USER_2_USERNAME in get_user_model().objects.values_list('username', flat=True))
def test_user_create_view_with_permission(self):
self.grant_permission(permission=permission_user_create)
response = self._request_user_create_view()
self.assertEqual(response.status_code, 302)
self.assertEqual(get_user_model().objects.count(), 3)
self.assertTrue(TEST_USER_2_USERNAME in get_user_model().objects.values_list('username', flat=True))
def _request_set_password(self, password):
return self.post(
'user_management:user_set_password', args=(self.user.pk,), data={
viewname='user_management:user_set_password', args=(self.user_2.pk,),
data={
'new_password1': password, 'new_password2': password
}
)
def _create_test_user_2(self):
self.user_2 = get_user_model().objects.create(
username=TEST_USER_2_USERNAME
)
def test_user_set_password_view_no_access(self):
self._create_test_user_2()
response = self._request_set_password(
password=TEST_USER_PASSWORD_EDITED
)
self.assertEqual(response.status_code, 403)
self.logout()
with self.assertRaises(AssertionError):
self.login(
username=TEST_USER_2_USERNAME, password=TEST_USER_PASSWORD_EDITED
)
response = self.get('common:current_user_details')
self.assertEqual(response.status_code, 302)
def test_user_set_password_view_with_access(self):
self._create_test_user_2()
self.grant_access(permission=permission_user_edit, obj=self.user_2)
response = self._request_set_password(
password=TEST_USER_PASSWORD_EDITED
)
self.assertEqual(response.status_code, 302)
self.logout()
self.login(
username=TEST_USER_2_USERNAME, password=TEST_USER_PASSWORD_EDITED
)
response = self.get('common:current_user_details')
self.assertEqual(response.status_code, 200)
def _request_multiple_user_set_password(self, password):
return self.post(
'user_management:user_multiple_set_password', data={
'id_list': self.user.pk,
'id_list': self.user_2.pk,
'new_password1': password,
'new_password2': password
}, follow=True
)
def test_user_set_password_view_no_permissions(self):
self.grant_permission(permission=permission_user_view)
response = self._request_set_password(
password=TEST_USER_PASSWORD_EDITED
)
self.assertEqual(response.status_code, 403)
self.logout()
with self.assertRaises(AssertionError):
self.login(
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD_EDITED
)
response = self.get('common:current_user_details')
self.assertEqual(response.status_code, 302)
def test_user_set_password_view_with_permissions(self):
self.grant_permission(permission=permission_user_edit)
self.grant_permission(permission=permission_user_view)
response = self._request_set_password(
password=TEST_USER_PASSWORD_EDITED
)
self.assertEqual(response.status_code, 302)
self.logout()
self.login(
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD_EDITED
)
response = self.get('common:current_user_details')
self.assertEqual(response.status_code, 200)
def test_user_multiple_set_password_view_no_permissions(self):
self.grant_permission(permission=permission_user_view)
response = self._request_multiple_user_set_password(
password=TEST_USER_PASSWORD_EDITED
)
self.assertEqual(response.status_code, 403)
self.logout()
with self.assertRaises(AssertionError):
self.login(
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD_EDITED
)
response = self.get('common:current_user_details')
self.assertEqual(response.status_code, 302)
def test_user_multiple_set_password_view_with_permissions(self):
self.grant_permission(permission=permission_user_edit)
self.grant_permission(permission=permission_user_view)
response = self._request_multiple_user_set_password(
password=TEST_USER_PASSWORD_EDITED
)
self.assertEqual(response.status_code, 200)
self.logout()
self.login(
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD_EDITED
)
response = self.get('common:current_user_details')
self.assertEqual(response.status_code, 200)
def test_user_delete_view_no_permissions(self):
user = get_user_model().objects.create(
username=TEST_USER_TO_DELETE_USERNAME
)
self.grant_permission(permission=permission_user_view)
response = self.post(
'user_management:user_delete', args=(user.pk,)
)
self.assertEqual(response.status_code, 403)
self.assertEqual(get_user_model().objects.count(), 3)
def test_user_delete_view_with_permissions(self):
user = get_user_model().objects.create(
username=TEST_USER_TO_DELETE_USERNAME
)
self.grant_permission(permission=permission_user_delete)
self.grant_permission(permission=permission_user_view)
response = self.post(
'user_management:user_delete', args=(user.pk,), follow=True
)
self.assertContains(response, text='deleted', status_code=200)
self.assertEqual(get_user_model().objects.count(), 2)
def test_user_multiple_delete_view_no_permissions(self):
user = get_user_model().objects.create(
username=TEST_USER_TO_DELETE_USERNAME
)
self.grant_permission(permission=permission_user_view)
response = self.post(
'user_management:user_multiple_delete', data={
'id_list': user.pk
}
)
def test_user_multiple_set_password_view_no_access(self):
self._create_test_user_2()
response = self._request_multiple_user_set_password(
password=TEST_USER_PASSWORD_EDITED
)
self.assertEqual(response.status_code, 403)
self.logout()
with self.assertRaises(AssertionError):
self.login(
username=TEST_USER_2_USERNAME, password=TEST_USER_PASSWORD_EDITED
)
response = self.get('common:current_user_details')
self.assertEqual(response.status_code, 302)
def test_user_multiple_set_password_view_with_access(self):
self._create_test_user_2()
self.grant_access(permission=permission_user_edit, obj=self.user_2)
response = self._request_multiple_user_set_password(
password=TEST_USER_PASSWORD_EDITED
)
self.assertEqual(response.status_code, 302)
self.logout()
self.login(
username=TEST_USER_2_USERNAME, password=TEST_USER_PASSWORD_EDITED
)
response = self.get('common:current_user_details')
self.assertEqual(response.status_code, 200)
def _request_user_delete(self):
return self.post(
viewname='user_management:user_delete', args=(self.user_2.pk,)
)
def test_user_delete_view_no_access(self):
self._create_test_user_2()
response = self._request_user_delete()
self.assertEqual(response.status_code, 302)
self.assertEqual(get_user_model().objects.count(), 3)
def test_user_multiple_delete_view_with_permissions(self):
user = get_user_model().objects.create(
username=TEST_USER_TO_DELETE_USERNAME
def test_user_delete_view_with_access(self):
self._create_test_user_2()
self.grant_access(permission=permission_user_delete, obj=self.user_2)
response = self._request_user_delete()
self.assertEqual(response.status_code, 302)
self.assertEqual(get_user_model().objects.count(), 2)
def _request_user_multiple_delete_view(self):
return self.post(
viewname='user_management:user_multiple_delete', data={
'id_list': self.user_2.pk
}
)
self.grant_permission(permission=permission_user_delete)
self.grant_permission(permission=permission_user_view)
def test_user_multiple_delete_view_no_access(self):
self._create_test_user_2()
response = self._request_user_multiple_delete_view()
self.assertEqual(response.status_code, 302)
self.assertEqual(get_user_model().objects.count(), 3)
response = self.post(
'user_management:user_multiple_delete', data={
'id_list': user.pk,
}, follow=True
)
self.assertContains(response, text='deleted', status_code=200)
def test_user_multiple_delete_view_with_access(self):
self._create_test_user_2()
self.grant_access(permission=permission_user_delete, obj=self.user_2)
response = self._request_user_multiple_delete_view()
self.assertEqual(response.status_code, 302)
self.assertEqual(get_user_model().objects.count(), 2)

View File

@@ -5,6 +5,7 @@ from django.contrib.auth import get_user_model
from django.contrib.auth.forms import SetPasswordForm
from django.contrib.auth.models import Group
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import PermissionDenied
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.urls import reverse, reverse_lazy
@@ -35,8 +36,8 @@ class GroupCreateView(SingleObjectCreateView):
class GroupEditView(SingleObjectEditView):
fields = ('name',)
model = Group
object_permission = permission_group_edit
post_action_redirect = reverse_lazy('user_management:group_list')
view_permission = permission_group_edit
def get_extra_context(self):
return {
@@ -51,13 +52,13 @@ class GroupListView(SingleObjectListView):
'title': _('Groups'),
}
model = Group
view_permission = permission_group_view
object_permission = permission_group_view
class GroupDeleteView(SingleObjectDeleteView):
model = Group
object_permission = permission_group_delete
post_action_redirect = reverse_lazy('user_management:group_list')
view_permission = permission_group_delete
def get_extra_context(self):
return {
@@ -70,7 +71,7 @@ class GroupMembersView(AssignRemoveView):
decode_content_type = True
left_list_title = _('Available users')
right_list_title = _('Users in group')
view_permission = permission_group_edit
object_permission = permission_group_edit
@staticmethod
def generate_choices(choices):
@@ -133,11 +134,11 @@ class UserCreateView(SingleObjectCreateView):
class UserDeleteView(MultipleObjectConfirmActionView):
model = get_user_model()
object_permission = permission_user_delete
success_message = _('User delete request performed on %(count)d user')
success_message_plural = _(
'User delete request performed on %(count)d users'
)
view_permission = permission_user_delete
def get_extra_context(self):
queryset = self.get_queryset()
@@ -187,11 +188,11 @@ class UserDeleteView(MultipleObjectConfirmActionView):
class UserEditView(SingleObjectEditView):
fields = ('username', 'first_name', 'last_name', 'email', 'is_active',)
object_permission = permission_user_edit
post_action_redirect = reverse_lazy('user_management:user_list')
queryset = get_user_model().objects.filter(
is_superuser=False, is_staff=False
)
view_permission = permission_user_edit
def get_extra_context(self):
return {
@@ -204,7 +205,7 @@ class UserGroupsView(AssignRemoveView):
decode_content_type = True
left_list_title = _('Available groups')
right_list_title = _('Groups joined')
view_permission = permission_user_edit
object_permission = permission_user_edit
def add(self, item):
item.user_set.add(self.get_object())
@@ -233,7 +234,7 @@ class UserGroupsView(AssignRemoveView):
class UserListView(SingleObjectListView):
view_permission = permission_user_view
object_permission = permission_user_view
def get_extra_context(self):
return {
@@ -250,11 +251,11 @@ class UserListView(SingleObjectListView):
class UserSetPasswordView(MultipleObjectFormActionView):
form_class = SetPasswordForm
model = get_user_model()
object_permission = permission_user_edit
success_message = _('Password change request performed on %(count)d user')
success_message_plural = _(
'Password change request performed on %(count)d users'
)
view_permission = permission_user_edit
def get_extra_context(self):
queryset = self.get_queryset()
@@ -283,8 +284,9 @@ class UserSetPasswordView(MultipleObjectFormActionView):
result = {}
if queryset:
result['user'] = queryset.first()
return result
return result
else:
raise PermissionDenied
def object_action(self, form, instance):
try: