Refactor user management app

Add keyword arguments.

Update view resolutions and URL parameters to the '_id' form.

Remove code from create and edit subclasses and user
the super class error checking.

Cache the view object instead of using .get_object()
every time.

Movernize tests.

Update views to comply with MERCs 5 and 6.

Split UserTestMixin into mixins for Groups and Users tests.

Add super delete and detail tests.

Remove redundant superuser filtering from views.

Add transactions to views that also commit events.

Signed-off-by: Roberto Rosario <Roberto.Rosario@mayan-edms.com>
This commit is contained in:
Roberto Rosario
2019-01-29 13:35:10 -04:00
parent 3bd33db023
commit f65f363361
20 changed files with 886 additions and 551 deletions

View File

@@ -7,6 +7,7 @@ from django.shortcuts import get_object_or_404
from rest_framework import generics
from mayan.apps.acls.models import AccessControlList
from mayan.apps.common.mixins import ExternalObjectMixin
from mayan.apps.rest_api.filters import MayanObjectPermissionsFilter
from mayan.apps.rest_api.permissions import MayanPermission
@@ -16,7 +17,7 @@ from .permissions import (
permission_user_edit, permission_user_view
)
from .serializers import (
GroupSerializer, UserSerializer, UserGroupListSerializer
GroupSerializer, UserSerializer#, UserGroupListSerializer
)
@@ -53,6 +54,7 @@ class APIGroupView(generics.RetrieveUpdateDestroyAPIView):
patch: Partially edit the selected group.
put: Edit the selected group.
"""
lookup_url_kwarg = 'group_pk'
mayan_object_permissions = {
'GET': (permission_group_view,),
'PUT': (permission_group_edit,),
@@ -84,6 +86,7 @@ class APIUserView(generics.RetrieveUpdateDestroyAPIView):
patch: Partially edit the selected user.
put: Edit the selected user.
"""
lookup_url_kwarg = 'user_pk'
mayan_object_permissions = {
'GET': (permission_user_view,),
'PUT': (permission_user_edit,),
@@ -95,16 +98,28 @@ class APIUserView(generics.RetrieveUpdateDestroyAPIView):
serializer_class = UserSerializer
class APIUserGroupList(generics.ListCreateAPIView):
class APIUserGroupList(ExternalObjectMixin, generics.ListCreateAPIView):
"""
get: Returns a list of all the groups to which an user belongs.
post: Add a user to a list of groups.
"""
external_object_pk_url_kwarg = 'user_pk'
filter_backends = (MayanObjectPermissionsFilter,)
mayan_object_permissions = {
'GET': (permission_user_view,),
'POST': (permission_user_edit,)
'GET': (permission_group_view,),
'POST': (permission_group_edit,)
}
permission_classes = (MayanPermission,)
def get_external_object_permission(self):
if self.request.method == 'POST':
return permission_user_edit
else:
return permission_user_view
def get_external_object_queryset(self):
return get_user_model().objects.exclude(is_staff=True).exclude(
is_superuser=True
)
def get_serializer(self, *args, **kwargs):
if not self.request:
@@ -113,10 +128,10 @@ class APIUserGroupList(generics.ListCreateAPIView):
return super(APIUserGroupList, self).get_serializer(*args, **kwargs)
def get_serializer_class(self):
if self.request.method == 'GET':
if self.request.method == 'POST':
return UserSerializer
else:
return GroupSerializer
elif self.request.method == 'POST':
return UserGroupListSerializer
def get_serializer_context(self):
"""
@@ -133,26 +148,10 @@ class APIUserGroupList(generics.ListCreateAPIView):
return context
def get_queryset(self):
user = self.get_user()
return AccessControlList.objects.filter_by_access(
permission_group_view, self.request.user,
queryset=user.groups.order_by('id')
)
return self.get_user().groups.order_by('id')
def get_user(self):
if self.request.method == 'GET':
permission = permission_user_view
else:
permission = permission_user_edit
user = get_object_or_404(klass=get_user_model(), pk=self.kwargs['pk'])
AccessControlList.objects.check_access(
permissions=(permission,), user=self.request.user,
obj=user
)
return user
return self.get_external_object()
def perform_create(self, serializer):
serializer.save(user=self.get_user(), _user=self.request.user)
return serializer.save(user=self.get_object(), _user=self.request.user)

View File

@@ -40,7 +40,7 @@ from .permissions import (
permission_user_view
)
from .search import * # NOQA
from .utils import get_groups, get_users
from .utils import lookup_get_groups, lookup_get_users
class UserManagementApp(MayanAppConfig):
@@ -65,15 +65,15 @@ class UserManagementApp(MayanAppConfig):
MetadataLookup(
description=_('All the groups.'), name='groups',
value=get_groups
value=lookup_get_groups
)
MetadataLookup(
description=_('All the users.'), name='users',
value=get_users
value=lookup_get_users
)
ModelEventType.register(
model=User, event_types=(event_user_edited,)
event_types=(event_user_edited,), model=User
)
ModelPermission.register(
@@ -129,7 +129,9 @@ class UserManagementApp(MayanAppConfig):
menu_list_facet.bind_links(
links=(
link_acl_list, link_group_members,
link_acl_list, link_events_for_object,
link_object_event_types_user_subcriptions_list,
link_group_members,
), sources=(Group,)
)
@@ -138,8 +140,7 @@ class UserManagementApp(MayanAppConfig):
link_acl_list, link_events_for_object,
link_object_event_types_user_subcriptions_list,
link_user_groups,
),
sources=(User,)
), sources=(User,)
)
menu_multi_item.bind_links(
@@ -147,12 +148,10 @@ class UserManagementApp(MayanAppConfig):
sources=('user_management:user_list',)
)
menu_object.bind_links(
links=(link_group_edit,),
sources=(Group,)
links=(link_group_edit,), sources=(Group,)
)
menu_object.bind_links(
links=(link_group_delete,), position=99,
sources=(Group,)
links=(link_group_delete,), position=99, sources=(Group,)
)
menu_object.bind_links(
links=(

View File

@@ -5,7 +5,7 @@ from django.utils.translation import ugettext_lazy as _
from mayan.apps.events import EventTypeNamespace
namespace = EventTypeNamespace(
name='user_management', label=_('User management')
label=_('User management'), name='user_management'
)
event_group_created = namespace.add_event_type(

View File

@@ -16,7 +16,7 @@ icon_user_delete = Icon(driver_name='fontawesome', symbol='times')
icon_user_edit = Icon(driver_name='fontawesome', symbol='pencil-alt')
icon_user_list = Icon(driver_name='fontawesome', symbol='user')
icon_user_multiple_delete = icon_user_delete
icon_user_multiple_set_password = Icon(driver_name='fontawesome', symbol='key')
icon_user_set_options = Icon(driver_name='fontawesome', symbol='cog')
icon_user_set_password = Icon(driver_name='fontawesome', symbol='key')
icon_user_setup = Icon(driver_name='fontawesome', symbol='user')
icon_user_multiple_set_password = icon_user_set_password

View File

@@ -38,24 +38,23 @@ link_group_create = Link(
text=_('Create new group'), view='user_management:group_create'
)
link_group_delete = Link(
args='object.id', icon_class=icon_group_delete,
icon_class=icon_group_delete, kwargs={'group_id': 'object.pk'},
permission=permission_group_delete, tags='dangerous',
text=_('Delete'), view='user_management:group_delete',
text=_('Delete'), view='user_management:group_delete'
)
link_group_edit = Link(
args='object.id', icon_class=icon_group_edit,
icon_class=icon_group_edit, kwargs={'group_id': 'object.pk'},
permission=permission_group_edit, text=_('Edit'),
view='user_management:group_edit',
view='user_management:group_edit'
)
link_group_list = Link(
icon_class=icon_group_list, permission=permission_group_view,
text=_('Groups'),
view='user_management:group_list'
text=_('Groups'), view='user_management:group_list'
)
link_group_members = Link(
args='object.id', icon_class=icon_group_members,
icon_class=icon_group_members, kwargs={'group_id': 'object.pk'},
permission=permission_group_edit, text=_('Users'),
view='user_management:group_members',
view='user_management:group_members'
)
link_group_setup = Link(
icon_class=icon_group_setup, permission=permission_group_view,
@@ -66,19 +65,19 @@ link_user_create = Link(
text=_('Create new user'), view='user_management:user_create'
)
link_user_delete = Link(
args='object.id', icon_class=icon_user_delete,
icon_class=icon_user_delete, kwargs={'user_id': 'object.pk'},
permission=permission_user_delete, tags='dangerous', text=_('Delete'),
view='user_management:user_delete',
view='user_management:user_delete'
)
link_user_edit = Link(
args='object.id', icon_class=icon_user_edit,
icon_class=icon_user_edit, kwargs={'user_id': 'object.pk'},
permission=permission_user_edit, text=_('Edit'),
view='user_management:user_edit',
view='user_management:user_edit'
)
link_user_groups = Link(
args='object.id', condition=condition_is_not_superuser,
icon_class=icon_group, permission=permission_user_edit,
text=_('Groups'), view='user_management:user_groups',
condition=condition_is_not_superuser, icon_class=icon_group,
kwargs={'user_id': 'object.pk'}, permission=permission_user_edit,
text=_('Groups'), view='user_management:user_groups'
)
link_user_list = Link(
icon_class=icon_user_list, permission=permission_user_view,
@@ -95,14 +94,14 @@ link_user_multiple_set_password = Link(
view='user_management:user_multiple_set_password'
)
link_user_set_options = Link(
args='object.id', icon_class=icon_user_set_options,
icon_class=icon_user_set_options, kwargs={'user_id': 'object.pk'},
permission=permission_user_edit, text=_('User options'),
view='user_management:user_options',
view='user_management:user_options'
)
link_user_set_password = Link(
args='object.id', icon_class=icon_user_set_password,
icon_class=icon_user_set_password, kwargs={'user_id': 'object.pk'},
permission=permission_user_edit, text=_('Set password'),
view='user_management:user_set_password',
view='user_management:user_set_password'
)
link_user_setup = Link(
icon_class=icon_user_setup, permission=permission_user_view,

View File

@@ -4,4 +4,6 @@ from django.shortcuts import reverse
def method_get_absolute_url(self):
return reverse(viewname='user_management:user_details', args=(self.pk,))
return reverse(
viewname='user_management:user_details', kwargs={'user_id': self.pk}
)

View File

@@ -18,8 +18,9 @@ class UserOptions(models.Model):
to=settings.AUTH_USER_MODEL, unique=True, verbose_name=_('User')
)
block_password_change = models.BooleanField(
default=False,
verbose_name=_('Forbid this user from changing their password.')
default=False, verbose_name=_(
'Forbid this user from changing their password.'
)
)
objects = UserOptionsManager()

View File

@@ -4,29 +4,31 @@ from django.utils.translation import ugettext_lazy as _
from mayan.apps.permissions import PermissionNamespace
namespace = PermissionNamespace(label=_('User management'), name='user_management')
namespace = PermissionNamespace(
label=_('User management'), name='user_management'
)
permission_group_create = namespace.add_permission(
name='group_create', label=_('Create new groups')
label=_('Create new groups'), name='group_create'
)
permission_group_delete = namespace.add_permission(
name='group_delete', label=_('Delete existing groups')
label=_('Delete existing groups'), name='group_delete'
)
permission_group_edit = namespace.add_permission(
name='group_edit', label=_('Edit existing groups')
label=_('Edit existing groups'), name='group_edit'
)
permission_group_view = namespace.add_permission(
name='group_view', label=_('View existing groups')
label=_('View existing groups'), name='group_view'
)
permission_user_create = namespace.add_permission(
name='user_create', label=_('Create new users')
label=_('Create new users'), name='user_create'
)
permission_user_delete = namespace.add_permission(
name='user_delete', label=_('Delete existing users')
label=_('Delete existing users'), name='user_delete'
)
permission_user_edit = namespace.add_permission(
name='user_edit', label=_('Edit existing users')
label=_('Edit existing users'), name='user_edit'
)
permission_user_view = namespace.add_permission(
name='user_view', label=_('View existing users')
label=_('View existing users'), name='user_view'
)

View File

@@ -32,8 +32,7 @@ user_search.add_model_field(
)
group_search = SearchModel(
app_label='auth', model_name='Group',
permission=permission_group_view,
app_label='auth', model_name='Group', permission=permission_group_view,
serializer_path='user_management.serializers.GroupSerializer'
)

View File

@@ -11,7 +11,7 @@ from rest_framework.exceptions import ValidationError
from mayan.apps.acls.models import AccessControlList
from .permissions import permission_group_view
from .permissions import permission_group_edit, permission_group_view
class GroupSerializer(serializers.HyperlinkedModelSerializer):
@@ -19,7 +19,10 @@ class GroupSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
extra_kwargs = {
'url': {'view_name': 'rest_api:group-detail'}
'url': {
'lookup_field': 'pk', 'lookup_url_kwarg': 'group_pk',
'view_name': 'rest_api:group-detail'
}
}
fields = ('id', 'name', 'url', 'users_count')
model = Group
@@ -28,41 +31,13 @@ class GroupSerializer(serializers.HyperlinkedModelSerializer):
return instance.user_set.count()
class UserGroupListSerializer(serializers.Serializer):
group_pk_list = serializers.CharField(
class UserSerializer(serializers.HyperlinkedModelSerializer):
groups = GroupSerializer(many=True, read_only=True, required=False)
groups_pk_list = serializers.CharField(
help_text=_(
'Comma separated list of group primary keys to assign this '
'user to.'
)
)
def create(self, validated_data):
validated_data['user'].groups.clear()
try:
pk_list = validated_data['group_pk_list'].split(',')
for group in Group.objects.filter(pk__in=pk_list):
try:
AccessControlList.objects.check_access(
permissions=(permission_group_view,),
user=self.context['request'].user, obj=group
)
except PermissionDenied:
pass
else:
validated_data['user'].groups.add(group)
except Exception as exception:
raise ValidationError(exception)
return {'group_pk_list': validated_data['group_pk_list']}
class UserSerializer(serializers.HyperlinkedModelSerializer):
groups = GroupSerializer(many=True, read_only=True)
groups_pk_list = serializers.CharField(
help_text=_(
'List of group primary keys to which to add the user.'
), required=False
), required=False, write_only=True
)
password = serializers.CharField(
required=False, style={'input_type': 'password'}, write_only=True
@@ -70,7 +45,10 @@ class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
extra_kwargs = {
'url': {'view_name': 'rest_api:user-detail'}
'url': {
'lookup_field': 'pk', 'lookup_url_kwarg': 'user_pk',
'view_name': 'rest_api:user-detail'
}
}
fields = (
'first_name', 'date_joined', 'email', 'groups', 'groups_pk_list',
@@ -81,13 +59,19 @@ class UserSerializer(serializers.HyperlinkedModelSerializer):
read_only_fields = ('groups', 'is_active', 'last_login', 'date_joined')
write_only_fields = ('password', 'group_pk_list')
def _add_groups(self, instance):
instance.groups.add(
*Group.objects.filter(pk__in=self.groups_pk_list.split(','))
def _add_groups(self, instance, groups_pk_list):
instance.groups.clear()
queryset = AccessControlList.objects.restrict_queryset(
permission=permission_group_edit,
queryset=Group.objects.filter(pk__in=groups_pk_list.split(',')),
user=self.context['request'].user
)
instance.groups.add(*queryset)
def create(self, validated_data):
self.groups_pk_list = validated_data.pop('groups_pk_list', '')
groups_pk_list = validated_data.pop('groups_pk_list', '')
password = validated_data.pop('password', None)
instance = super(UserSerializer, self).create(validated_data)
@@ -95,13 +79,13 @@ class UserSerializer(serializers.HyperlinkedModelSerializer):
instance.set_password(password)
instance.save()
if self.groups_pk_list:
self._add_groups(instance=instance)
if groups_pk_list:
self._add_groups(instance=instance, groups_pk_list=groups_pk_list)
return instance
def update(self, instance, validated_data):
self.groups_pk_list = validated_data.pop('groups_pk_list', '')
groups_pk_list = validated_data.pop('groups_pk_list', '')
if 'password' in validated_data:
instance.set_password(validated_data['password'])
@@ -109,9 +93,8 @@ class UserSerializer(serializers.HyperlinkedModelSerializer):
instance = super(UserSerializer, self).update(instance, validated_data)
if self.groups_pk_list:
instance.groups.clear()
self._add_groups(instance=instance)
if groups_pk_list:
self._add_groups(instance=instance, groups_pk_list=groups_pk_list)
return instance

View File

@@ -1 +1,2 @@
from .literals import * # NOQA
from .mixins import * # NOQA

View File

@@ -5,26 +5,28 @@ __all__ = (
'TEST_USER_PASSWORD', 'TEST_USER_PASSWORD_EDITED', 'TEST_USER_USERNAME'
)
TEST_CASE_ADMIN_EMAIL = 'admin@example.com'
TEST_CASE_ADMIN_PASSWORD = 'test admin password'
TEST_CASE_ADMIN_USERNAME = 'test_admin'
TEST_CASE_ADMIN_EMAIL = 'case_admin@example.com'
TEST_CASE_ADMIN_PASSWORD = 'test case admin password'
TEST_CASE_ADMIN_USERNAME = 'test_case_admin'
TEST_CASE_GROUP_NAME = 'test group'
TEST_CASE_USER_EMAIL = 'user@example.com'
TEST_CASE_USER_PASSWORD = 'test user password'
TEST_CASE_USER_USERNAME = 'test_user'
TEST_CASE_GROUP_NAME = 'test case group'
TEST_CASE_USER_EMAIL = 'test_case_user@example.com'
TEST_CASE_USER_PASSWORD = 'test case user password'
TEST_CASE_USER_USERNAME = 'test_case_user'
TEST_GROUP_NAME = 'test group'
TEST_GROUP_NAME_EDITED = 'test group edited'
TEST_GROUP_2_NAME = 'test group 2'
TEST_GROUP_2_NAME_EDITED = 'test group 2 edited'
TEST_USER_EMAIL = 'user@example.com'
TEST_USER_EMAIL = 'testuser@example.com'
TEST_USER_PASSWORD = 'test user password'
TEST_USER_PASSWORD_EDITED = 'test user password edited'
TEST_USER_USERNAME = 'test_user'
TEST_USER_USERNAME_EDITED = 'test_user_edited'
TEST_USER_2_EMAIL = 'user2@example.com'
TEST_USER_2_EMAIL = 'testuser2@example.com'
TEST_USER_2_PASSWORD = 'test user 2 password'
TEST_USER_2_PASSWORD_EDITED = 'test user 2 password edited'
TEST_USER_2_USERNAME = 'test_user_2'

View File

@@ -5,97 +5,117 @@ from django.contrib.auth.models import Group
from .literals import (
TEST_CASE_ADMIN_EMAIL, TEST_CASE_ADMIN_PASSWORD, TEST_CASE_ADMIN_USERNAME,
TEST_CASE_GROUP_NAME, TEST_CASE_USER_EMAIL, TEST_CASE_USER_PASSWORD,
TEST_CASE_USER_USERNAME, TEST_GROUP_NAME, TEST_GROUP_2_NAME,
TEST_GROUP_2_NAME_EDITED, TEST_USER_2_EMAIL, TEST_USER_2_PASSWORD,
TEST_USER_EMAIL, TEST_USER_USERNAME, TEST_USER_PASSWORD,
TEST_USER_2_USERNAME, TEST_USER_2_USERNAME_EDITED
TEST_CASE_GROUP_NAME, TEST_GROUP_NAME_EDITED, TEST_CASE_USER_EMAIL,
TEST_CASE_USER_PASSWORD, TEST_CASE_USER_USERNAME, TEST_GROUP_NAME,
TEST_USER_EMAIL, TEST_USER_USERNAME, TEST_USER_USERNAME_EDITED,
TEST_USER_PASSWORD
)
__all__ = ('GroupTestMixin', 'UserTestCaseMixin', 'UserTestMixin')
class UserTestCaseMixin(object):
auto_login_admin = False
"""
This TestCaseMixin is used to create an user and group to execute the
test case, these are used to just create an identity which is required by
most of the code in the project, these are not meant to be acted upon
(edited, deleted, etc). To create a test users or groups to modify, use
the UserTestMixin instead and the respective test_user and test_group.
The user and group created by this mixin will be prepended with
_test_case_{...}. The _test_case_user and _test_case_group are meant
to be used by other test case mixins like the ACLs test case mixin which
adds shorthand methods to create ACL entries to test access control.
"""
auto_login_superuser = False
auto_login_user = True
create_test_case_superuser = False
create_test_case_user = True
def setUp(self):
super(UserTestCaseMixin, self).setUp()
if self.auto_login_user:
self._test_case_user = get_user_model().objects.create_user(
username=TEST_CASE_USER_USERNAME, email=TEST_CASE_USER_EMAIL,
password=TEST_CASE_USER_PASSWORD
)
self.login_user()
self._test_case_group = Group.objects.create(name=TEST_GROUP_NAME)
if self.create_test_case_user:
self._create_test_case_user()
self._create_test_case_group()
self._test_case_group.user_set.add(self._test_case_user)
elif self.auto_login_admin:
self._test_case_admin_user = get_user_model().objects.create_superuser(
username=TEST_CASE_ADMIN_USERNAME, email=TEST_CASE_ADMIN_EMAIL,
password=TEST_CASE_ADMIN_PASSWORD
)
self.login_admin_user()
if self.auto_login_user:
self.login_user()
elif self.create_test_case_superuser:
self._create_test_case_superuser()
if self.auto_login_superuser:
self.login_superuser()
def tearDown(self):
self.client.logout()
super(UserTestCaseMixin, self).tearDown()
def _create_test_case_group(self):
self._test_case_group = Group.objects.create(name=TEST_CASE_GROUP_NAME)
def _create_test_case_superuser(self):
self._test_case_superuser = get_user_model().objects.create_superuser(
username=TEST_CASE_ADMIN_USERNAME, email=TEST_CASE_ADMIN_EMAIL,
password=TEST_CASE_ADMIN_PASSWORD
)
def _create_test_case_user(self):
self._test_case_user = get_user_model().objects.create_user(
username=TEST_CASE_USER_USERNAME, email=TEST_CASE_USER_EMAIL,
password=TEST_CASE_USER_PASSWORD
)
def login(self, *args, **kwargs):
logged_in = self.client.login(*args, **kwargs)
return logged_in
def login_user(self):
self.login(
username=TEST_CASE_USER_USERNAME, password=TEST_CASE_USER_PASSWORD
)
def login_admin_user(self):
def login_superuser(self):
self.login(
username=TEST_CASE_ADMIN_USERNAME,
password=TEST_CASE_ADMIN_PASSWORD
)
def login_user(self):
self.login(
username=TEST_CASE_USER_USERNAME, password=TEST_CASE_USER_PASSWORD
)
def logout(self):
self.client.logout()
class UserTestMixin(object):
class GroupTestMixin(object):
def _create_test_group(self):
self.test_group = Group.objects.create(name=TEST_GROUP_2_NAME)
self.test_group = Group.objects.create(name=TEST_GROUP_NAME)
def _edit_test_group(self):
self.test_group.name = TEST_GROUP_2_NAME_EDITED
self.test_group.name = TEST_GROUP_NAME_EDITED
self.test_group.save()
def _create_test_user(self):
self.test_user = get_user_model().objects.create(
username=TEST_USER_2_USERNAME, email=TEST_USER_2_EMAIL,
password=TEST_USER_2_PASSWORD
)
# Group views
def _request_test_group_create_view(self):
reponse = self.post(
viewname='user_management:group_create', data={
'name': TEST_GROUP_2_NAME
'name': TEST_GROUP_NAME
}
)
self.test_group = Group.objects.filter(name=TEST_GROUP_2_NAME).first()
self.test_group = Group.objects.filter(name=TEST_GROUP_NAME).first()
return reponse
def _request_test_group_delete_view(self):
return self.post(
viewname='user_management:group_delete', kwargs={
'group_pk': self.test_group.pk
'group_id': self.test_group.pk
}
)
def _request_test_group_edit_view(self):
return self.post(
viewname='user_management:group_edit', kwargs={
'group_pk': self.test_group.pk
'group_id': self.test_group.pk
}, data={
'name': TEST_GROUP_2_NAME_EDITED
'name': TEST_GROUP_NAME_EDITED
}
)
@@ -105,41 +125,65 @@ class UserTestMixin(object):
def _request_test_group_members_view(self):
return self.get(
viewname='user_management:group_members',
kwargs={'group_pk': self.test_group.pk}
kwargs={'group_id': self.test_group.pk}
)
# User views
class UserTestMixin(object):
def _create_test_superuser(self):
self.test_superuser = get_user_model().objects.create_superuser(
username=TEST_CASE_ADMIN_USERNAME, email=TEST_CASE_ADMIN_EMAIL,
password=TEST_CASE_ADMIN_PASSWORD
)
def _create_test_user(self):
self.test_user = get_user_model().objects.create(
username=TEST_USER_USERNAME, email=TEST_USER_EMAIL,
password=TEST_USER_PASSWORD
)
def _request_test_superuser_delete_view(self):
return self.post(
viewname='user_management:user_delete',
kwargs={'user_id': self.test_superuser.pk}
)
def _request_test_superuser_detail_view(self):
return self.get(
viewname='user_management:user_details',
kwargs={'user_id': self.test_superuser.pk}
)
def _request_test_user_create_view(self):
reponse = self.post(
viewname='user_management:user_create', data={
'username': TEST_USER_2_USERNAME,
'password': TEST_USER_2_PASSWORD
'username': TEST_USER_USERNAME,
'password': TEST_USER_PASSWORD
}
)
self.test_user = get_user_model().objects.filter(
username=TEST_USER_2_USERNAME
username=TEST_USER_USERNAME
).first()
return reponse
def _request_test_user_delete_view(self):
return self.post(
viewname='user_management:user_delete',
kwargs={'user_pk': self.test_user.pk}
kwargs={'user_id': self.test_user.pk}
)
def _request_test_user_edit_view(self):
return self.post(
viewname='user_management:user_edit', kwargs={
'user_pk': self.test_user.pk
'user_id': self.test_user.pk
}, data={
'username': TEST_USER_2_USERNAME_EDITED
'username': TEST_USER_USERNAME_EDITED
}
)
def _request_test_user_groups_view(self):
return self.get(
viewname='user_management:user_groups',
kwargs={'user_pk': self.test_user.pk}
kwargs={'user_id': self.test_user.pk}
)

File diff suppressed because it is too large Load Diff

View File

@@ -4,47 +4,60 @@ from actstream.models import Action
from mayan.apps.common.tests import GenericViewTestCase
from ..permissions import (
permission_group_create, permission_group_edit, permission_user_create,
permission_user_edit
)
from ..events import (
event_group_created, event_group_edited, event_user_created,
event_user_edited
)
from .mixins import UserTestMixin
from .mixins import GroupTestMixin, UserTestMixin
class GroupEventsTestCase(UserTestMixin, GenericViewTestCase):
auto_create_group = False
class GroupEventsTestCase(GroupTestMixin, UserTestMixin, GenericViewTestCase):
def test_group_create_event(self):
self.login_admin_user()
Action.objects.all().delete()
self.grant_permission(
permission=permission_group_create
)
self._request_test_group_create_view()
self.assertEqual(Action.objects.last().target, self.test_group)
self.assertEqual(Action.objects.last().verb, event_group_created.id)
def test_group_edit_event(self):
self.login_admin_user()
self._create_test_group()
Action.objects.all().delete()
self.grant_access(
obj=self.test_group, permission=permission_group_edit
)
self._request_test_group_edit_view()
self.assertEqual(Action.objects.last().target, self.test_group)
self.assertEqual(Action.objects.last().verb, event_group_edited.id)
class UserEventsTestCase(UserTestMixin, GenericViewTestCase):
auto_create_group = False
def test_user_create_event(self):
self.login_admin_user()
Action.objects.all().delete()
self.grant_permission(
permission=permission_user_create
)
self._request_test_user_create_view()
self.assertEqual(Action.objects.last().target, self.test_user)
self.assertEqual(Action.objects.last().verb, event_user_created.id)
def test_user_edit_event(self):
self.login_admin_user()
self._create_test_user()
Action.objects.all().delete()
self.grant_access(
obj=self.test_user, permission=permission_user_edit
)
self._request_test_user_edit_view()
self.assertEqual(Action.objects.last().target, self.test_user)
self.assertEqual(Action.objects.last().verb, event_user_edited.id)

View File

@@ -7,5 +7,5 @@ from .mixins import UserTestMixin
class UserTestCase(UserTestMixin, BaseTestCase):
def test_natural_keys(self):
self._create_user()
self._create_test_user()
self._test_database_conversion('auth', 'user_management')

View File

@@ -6,70 +6,253 @@ from django.contrib.auth.models import Group
from mayan.apps.common.tests import GenericViewTestCase
from mayan.apps.documents.tests import GenericDocumentViewTestCase
from mayan.apps.metadata.models import MetadataType
from mayan.apps.metadata.permissions import permission_metadata_document_edit
from mayan.apps.metadata.permissions import permission_document_metadata_edit
from mayan.apps.metadata.tests.literals import (
TEST_METADATA_TYPE_LABEL, TEST_METADATA_TYPE_NAME,
)
from ..permissions import (
permission_user_create, permission_user_delete, permission_user_edit
permission_group_create, permission_group_delete, permission_group_edit,
permission_group_view, permission_user_create, permission_user_delete,
permission_user_edit, permission_user_view
)
from .literals import (
TEST_USER_PASSWORD_EDITED, TEST_USER_USERNAME, TEST_USER_2_USERNAME
TEST_GROUP_NAME, TEST_GROUP_NAME_EDITED, TEST_USER_PASSWORD_EDITED,
TEST_USER_USERNAME
)
from .mixins import UserTestMixin
from .mixins import GroupTestMixin, UserTestMixin
TEST_USER_TO_DELETE_USERNAME = 'user_to_delete'
class UserManagementViewTestCase(UserTestMixin, GenericViewTestCase):
def setUp(self):
super(UserManagementViewTestCase, self).setUp()
self.login_user()
class GroupViewsTestCase(GroupTestMixin, UserTestMixin, GenericViewTestCase):
def test_group_create_view_no_permission(self):
response = self._request_test_group_create_view()
self.assertEqual(response.status_code, 403)
self.assertEqual(Group.objects.count(), 1)
#def _request_test_user_create_view(self):
# return self.post(
# viewname='user_management:user_create', data={
# 'username': TEST_USER_2_USERNAME
# }
# )
def test_group_create_view_with_permission(self):
self.grant_permission(permission=permission_group_create)
response = self._request_test_group_create_view()
self.assertEqual(response.status_code, 302)
self.assertEqual(Group.objects.count(), 2)
def test_group_delete_view_no_permission(self):
self._create_test_group()
response = self._request_test_group_delete_view()
self.assertEqual(response.status_code, 404)
self.assertEqual(Group.objects.count(), 2)
def test_group_delete_view_with_access(self):
self._create_test_group()
self.grant_access(
obj=self.test_group, permission=permission_group_delete
)
response = self._request_test_group_delete_view()
self.assertEqual(response.status_code, 302)
self.assertEqual(Group.objects.count(), 1)
def test_group_edit_view_no_permission(self):
self._create_test_group()
response = self._request_test_group_edit_view()
self.assertEqual(response.status_code, 404)
self.test_group.refresh_from_db()
self.assertEqual(self.test_group.name, TEST_GROUP_NAME)
def test_group_edit_view_with_access(self):
self._create_test_group()
self.grant_access(
obj=self.test_group, permission=permission_group_edit
)
response = self._request_test_group_edit_view()
self.assertEqual(response.status_code, 302)
self.test_group.refresh_from_db()
self.assertEqual(self.test_group.name, TEST_GROUP_NAME_EDITED)
def test_group_list_view_no_permission(self):
self._create_test_group()
response = self._request_test_group_list_view()
self.assertNotContains(
response=response, text=self.test_group.name, status_code=200
)
def test_group_list_view_with_permission(self):
self._create_test_group()
self.grant_access(
obj=self.test_group, permission=permission_group_view
)
response = self._request_test_group_list_view()
self.assertContains(
response=response, text=self.test_group.name, status_code=200
)
def test_group_members_view_no_permission(self):
self._create_test_user()
self._create_test_group()
self.test_user.groups.add(self.test_group)
response = self._request_test_group_members_view()
self.assertEqual(response.status_code, 404)
def test_group_members_view_with_group_access(self):
self._create_test_user()
self._create_test_group()
self.test_user.groups.add(self.test_group)
self.grant_access(
obj=self.test_group, permission=permission_group_edit
)
response = self._request_test_group_members_view()
self.assertContains(
response=response, text=self.test_group.name, status_code=200
)
self.assertNotContains(
response=response, text=self.test_user.username, status_code=200
)
def test_group_members_view_with_user_access(self):
self._create_test_user()
self._create_test_group()
self.test_user.groups.add(self.test_group)
self.grant_access(obj=self.test_user, permission=permission_user_edit)
response = self._request_test_group_members_view()
self.assertNotContains(
response=response, text=self.test_group.name, status_code=404
)
def test_group_members_view_with_full_access(self):
self._create_test_user()
self._create_test_group()
self.test_user.groups.add(self.test_group)
self.grant_access(
obj=self.test_group, permission=permission_group_edit
)
self.grant_access(obj=self.test_user, permission=permission_user_edit)
response = self._request_test_group_members_view()
self.assertContains(
response=response, text=self.test_user.username, status_code=200
)
self.assertContains(
response=response, text=self.test_group.name, status_code=200
)
class UserViewsTestCase(GroupTestMixin, UserTestMixin, GenericViewTestCase):
def test_user_create_view_no_permission(self):
user_count = get_user_model().objects.count()
response = self._request_test_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))
self.assertEqual(get_user_model().objects.count(), user_count)
self.assertFalse(TEST_USER_USERNAME in get_user_model().objects.values_list('username', flat=True))
def test_user_create_view_with_permission(self):
user_count = get_user_model().objects.count()
self.grant_permission(permission=permission_user_create)
response = self._request_test_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_user_groups_view(self):
return self.post(
viewname='user_management:user_groups', args=(self.test_user.pk,)
self.assertEqual(get_user_model().objects.count(), user_count + 1)
self.assertTrue(TEST_USER_USERNAME in get_user_model().objects.values_list('username', flat=True))
def test_user_delete_view_no_access(self):
self._create_test_user()
user_count = get_user_model().objects.count()
response = self._request_test_user_delete_view()
self.assertEqual(response.status_code, 404)
self.assertEqual(get_user_model().objects.count(), user_count)
def test_user_delete_view_with_access(self):
self._create_test_user()
user_count = get_user_model().objects.count()
self.grant_access(
obj=self.test_user, permission=permission_user_delete
)
response = self._request_test_user_delete_view()
self.assertEqual(response.status_code, 302)
self.assertEqual(get_user_model().objects.count(), user_count - 1)
def test_superuser_delete_view_with_access(self):
self._create_test_superuser()
superuser_count = get_user_model().objects.filter(is_superuser=True).count()
self.grant_access(
obj=self.test_superuser, permission=permission_user_delete
)
response = self._request_test_superuser_delete_view()
self.assertEqual(response.status_code, 404)
self.assertEqual(
get_user_model().objects.filter(is_superuser=True).count(),
superuser_count
)
def test_superuser_detail_view_with_access(self):
self._create_test_superuser()
self.grant_access(
obj=self.test_superuser, permission=permission_user_view
)
response = self._request_test_superuser_detail_view()
self.assertEqual(response.status_code, 404)
def test_user_groups_view_no_permission(self):
self._create_test_user()
response = self._request_user_groups_view()
self.assertEqual(response.status_code, 403)
self._create_test_group()
self.test_user.groups.add(self.test_group)
response = self._request_test_user_groups_view()
self.assertEqual(response.status_code, 404)
def test_user_groups_view_with_access(self):
def test_user_groups_view_with_group_access(self):
self._create_test_user()
self.grant_access(permission=permission_user_edit, obj=self.test_user)
self._create_test_group()
self.test_user.groups.add(self.test_group)
self.grant_access(
obj=self.test_group, permission=permission_group_edit
)
response = self._request_test_user_groups_view()
self.assertNotContains(
response=response, text=self.test_user.username, status_code=404
)
response = self._request_user_groups_view()
def test_user_groups_view_with_user_access(self):
self._create_test_user()
self._create_test_group()
self.test_user.groups.add(self.test_group)
self.grant_access(obj=self.test_user, permission=permission_user_edit)
response = self._request_test_user_groups_view()
self.assertContains(
response=response, text=self.test_user.username, status_code=200
)
self.assertNotContains(
response=response, text=self.test_group.name, status_code=200
)
def test_user_groups_view_with_full_access(self):
self._create_test_user()
self._create_test_group()
self.test_user.groups.add(self.test_group)
self.grant_access(
obj=self.test_group, permission=permission_group_edit
)
self.grant_access(obj=self.test_user, permission=permission_user_edit)
response = self._request_test_user_groups_view()
self.assertContains(
response=response, text=self.test_user.username, status_code=200
)
self.assertContains(
response=response, text=self.test_group.name, status_code=200
)
def _request_set_password_view(self, password):
return self.post(
viewname='user_management:user_set_password', args=(self.test_user.pk,),
viewname='user_management:user_set_password',
kwargs={'user_id': self.test_user.pk},
data={
'new_password1': password, 'new_password2': password
}
@@ -81,13 +264,14 @@ class UserManagementViewTestCase(UserTestMixin, GenericViewTestCase):
password=TEST_USER_PASSWORD_EDITED
)
self.assertEqual(response.status_code, 403)
self.assertEqual(response.status_code, 404)
self.logout()
with self.assertRaises(AssertionError):
self.login(
username=TEST_USER_2_USERNAME, password=TEST_USER_PASSWORD_EDITED
username=self.test_user.username,
password=TEST_USER_PASSWORD_EDITED
)
response = self.get(viewname='user_management:current_user_details')
@@ -96,7 +280,7 @@ class UserManagementViewTestCase(UserTestMixin, GenericViewTestCase):
def test_user_set_password_view_with_access(self):
self._create_test_user()
self.grant_access(permission=permission_user_edit, obj=self.test_user)
self.grant_access(obj=self.test_user, permission=permission_user_edit)
response = self._request_set_password_view(
password=TEST_USER_PASSWORD_EDITED
@@ -106,7 +290,7 @@ class UserManagementViewTestCase(UserTestMixin, GenericViewTestCase):
self.logout()
self.login(
username=TEST_USER_2_USERNAME, password=TEST_USER_PASSWORD_EDITED
username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD_EDITED
)
response = self.get(viewname='user_management:current_user_details')
@@ -128,13 +312,14 @@ class UserManagementViewTestCase(UserTestMixin, GenericViewTestCase):
password=TEST_USER_PASSWORD_EDITED
)
self.assertEqual(response.status_code, 403)
self.assertEqual(response.status_code, 404)
self.logout()
with self.assertRaises(AssertionError):
self.login(
username=TEST_USER_2_USERNAME, password=TEST_USER_PASSWORD_EDITED
username=self.test_user.username,
password=TEST_USER_PASSWORD_EDITED
)
response = self.get(viewname='user_management:current_user_details')
@@ -142,7 +327,7 @@ class UserManagementViewTestCase(UserTestMixin, GenericViewTestCase):
def test_user_multiple_set_password_view_with_access(self):
self._create_test_user()
self.grant_access(permission=permission_user_edit, obj=self.test_user)
self.grant_access(obj=self.test_user, permission=permission_user_edit)
response = self._request_multiple_user_set_password_view(
password=TEST_USER_PASSWORD_EDITED
@@ -152,30 +337,12 @@ class UserManagementViewTestCase(UserTestMixin, GenericViewTestCase):
self.logout()
self.login(
username=TEST_USER_2_USERNAME, password=TEST_USER_PASSWORD_EDITED
username=self.test_user.username, password=TEST_USER_PASSWORD_EDITED
)
response = self.get(viewname='user_management:current_user_details')
self.assertEqual(response.status_code, 200)
def _request_user_delete_view(self):
return self.post(
viewname='user_management:user_delete', args=(self.test_user.pk,)
)
def test_user_delete_view_no_access(self):
self._create_test_user()
response = self._request_user_delete_view()
self.assertEqual(response.status_code, 302)
self.assertEqual(get_user_model().objects.count(), 3)
def test_user_delete_view_with_access(self):
self._create_test_user()
self.grant_access(permission=permission_user_delete, obj=self.test_user)
response = self._request_user_delete_view()
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={
@@ -185,16 +352,24 @@ class UserManagementViewTestCase(UserTestMixin, GenericViewTestCase):
def test_user_multiple_delete_view_no_access(self):
self._create_test_user()
user_count = get_user_model().objects.count()
response = self._request_user_multiple_delete_view()
self.assertEqual(response.status_code, 302)
self.assertEqual(get_user_model().objects.count(), 3)
self.assertEqual(response.status_code, 404)
self.assertEqual(get_user_model().objects.count(), user_count)
def test_user_multiple_delete_view_with_access(self):
self._create_test_user()
self.grant_access(permission=permission_user_delete, obj=self.test_user)
user_count = get_user_model().objects.count()
self.grant_access(
obj=self.test_user, permission=permission_user_delete
)
response = self._request_user_multiple_delete_view()
self.assertEqual(response.status_code, 302)
self.assertEqual(get_user_model().objects.count(), 2)
self.assertEqual(get_user_model().objects.count(), user_count - 1)
class MetadataLookupIntegrationTestCase(GenericDocumentViewTestCase):
@@ -212,13 +387,13 @@ class MetadataLookupIntegrationTestCase(GenericDocumentViewTestCase):
self.metadata_type.lookup = '{{ users }}'
self.metadata_type.save()
self.document.metadata.create(metadata_type=self.metadata_type)
self.role.permissions.add(
permission_metadata_document_edit.stored_permission
self.grant_access(
obj=self.document, permission=permission_document_metadata_edit
)
response = self.get(
viewname='metadata:document_metadata_edit',
kwargs={'pk': self.document.pk}
kwargs={'document_id': self.document.pk}
)
self.assertContains(
response=response, text='<option value="{}">{}</option>'.format(
@@ -230,13 +405,13 @@ class MetadataLookupIntegrationTestCase(GenericDocumentViewTestCase):
self.metadata_type.lookup = '{{ groups }}'
self.metadata_type.save()
self.document.metadata.create(metadata_type=self.metadata_type)
self.role.permissions.add(
permission_metadata_document_edit.stored_permission
self.grant_access(
obj=self.document, permission=permission_document_metadata_edit
)
response = self.get(
viewname='metadata:document_metadata_edit',
kwargs={'pk': self.document.pk}
kwargs={'document_id': self.document.pk}
)
self.assertContains(

View File

@@ -14,76 +14,93 @@ from .views import (
)
urlpatterns = [
url(r'^groups/list/$', GroupListView.as_view(), name='group_list'),
url(r'^groups/create/$', GroupCreateView.as_view(), name='group_create'),
url(
r'^groups/(?P<pk>\d+)/edit/$', GroupEditView.as_view(),
name='group_edit'
regex=r'^groups/$', name='group_list', view=GroupListView.as_view()
),
url(
r'^groups/(?P<pk>\d+)/delete/$', GroupDeleteView.as_view(),
name='group_delete'
regex=r'^groups/create/$', name='group_create',
view=GroupCreateView.as_view()
),
url(
r'^groups/(?P<pk>\d+)/members/$', GroupMembersView.as_view(),
name='group_members'
),
url(
r'^users/current/$', CurrentUserDetailsView.as_view(),
name='current_user_details'
regex=r'^groups/(?P<group_id>\d+)/delete/$', name='group_delete',
view=GroupDeleteView.as_view()
),
url(
r'^users/current/edit/$', CurrentUserEditView.as_view(),
name='current_user_edit'
),
url(r'^users/list/$', UserListView.as_view(), name='user_list'),
url(r'^users/create/$', UserCreateView.as_view(), name='user_create'),
url(
r'^users/(?P<pk>\d+)/delete/$', UserDeleteView.as_view(),
name='user_delete'
),
url(r'^users/(?P<pk>\d+)/edit/$', UserEditView.as_view(), name='user_edit'),
url(
r'^users/(?P<pk>\d+)/$', UserDetailsView.as_view(),
name='user_details'
regex=r'^groups/(?P<group_id>\d+)/edit/$', name='group_edit',
view=GroupEditView.as_view()
),
url(
r'^users/multiple/delete/$', UserDeleteView.as_view(),
name='user_multiple_delete'
regex=r'^groups/(?P<group_id>\d+)/members/$', name='group_members',
view=GroupMembersView.as_view()
),
url(
r'^users/(?P<pk>\d+)/set_password/$', UserSetPasswordView.as_view(),
name='user_set_password'
regex=r'^user/$', name='current_user_details',
view=CurrentUserDetailsView.as_view()
),
url(
r'^users/multiple/set_password/$', UserSetPasswordView.as_view(),
name='user_multiple_set_password'
regex=r'^user/edit/$', name='current_user_edit',
view=CurrentUserEditView.as_view()
),
url(
r'^users/(?P<pk>\d+)/groups/$', UserGroupsView.as_view(),
name='user_groups'
regex=r'^users/$', name='user_list', view=UserListView.as_view()
),
url(
r'^users/(?P<pk>\d+)/options/$',
UserOptionsEditView.as_view(),
name='user_options'
regex=r'^users/create/$', name='user_create',
view=UserCreateView.as_view()
),
url(
regex=r'^users/(?P<user_id>\d+)/$', name='user_details',
view=UserDetailsView.as_view()
),
url(
regex=r'^users/(?P<user_id>\d+)/delete/$', name='user_delete',
view=UserDeleteView.as_view(),
),
url(
regex=r'^users/(?P<user_id>\d+)/edit/$', name='user_edit',
view=UserEditView.as_view()
),
url(
regex=r'^users/(?P<user_id>\d+)/groups/$', name='user_groups',
view=UserGroupsView.as_view()
),
url(
regex=r'^users/(?P<user_id>\d+)/options/$', name='user_options',
view=UserOptionsEditView.as_view()
),
url(
regex=r'^users/(?P<user_id>\d+)/set_password/$',
name='user_set_password', view=UserSetPasswordView.as_view()
),
url(
regex=r'^users/multiple/delete/$', name='user_multiple_delete',
view=UserDeleteView.as_view()
),
url(
regex=r'^users/multiple/set_password/$',
name='user_multiple_set_password', view=UserSetPasswordView.as_view()
)
]
api_urls = [
url(r'^groups/$', APIGroupListView.as_view(), name='group-list'),
url(
r'^groups/(?P<pk>[0-9]+)/$', APIGroupView.as_view(),
name='group-detail'
),
url(r'^users/$', APIUserListView.as_view(), name='user-list'),
url(r'^users/(?P<pk>[0-9]+)/$', APIUserView.as_view(), name='user-detail'),
url(
r'^users/current/$', APICurrentUserView.as_view(), name='user-current'
regex=r'^groups/$', name='group-list', view=APIGroupListView.as_view()
),
url(
r'^users/(?P<pk>[0-9]+)/groups/$', APIUserGroupList.as_view(),
name='users-group-list'
regex=r'^groups/(?P<group_id>\d+)/$', name='group-detail',
view=APIGroupView.as_view(),
),
url(
regex=r'^user/$', name='user-current',
view=APICurrentUserView.as_view()
),
url(regex=r'^users/$', name='user-list', view=APIUserListView.as_view()),
url(
regex=r'^users/(?P<user_id>\d+)/$', name='user-detail',
view=APIUserView.as_view()
),
url(
regex=r'^users/(?P<user_id>\d+)/groups/$', name='users-group-list',
view=APIUserGroupList.as_view()
),
]

View File

@@ -5,22 +5,22 @@ from django.contrib.auth import get_user_model
from django.utils.translation import ugettext_lazy as _
def get_groups():
def get_user_label_text(context):
if not context['request'].user.is_authenticated:
return _('Anonymous')
else:
return context['request'].user.get_full_name() or context['request'].user
def lookup_get_groups():
Group = apps.get_model(app_label='auth', model_name='Group')
return ','.join([group.name for group in Group.objects.all()])
def get_users():
def lookup_get_users():
return ','.join(
[
user.get_full_name() or user.username
for user in get_user_model().objects.all()
]
)
def get_user_label_text(context):
if not context['request'].user.is_authenticated:
return _('Anonymous')
else:
return context['request'].user.get_full_name() or context['request'].user

View File

@@ -5,19 +5,21 @@ 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.db import transaction
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.template import RequestContext
from django.urls import reverse, reverse_lazy
from django.utils.translation import ungettext, ugettext_lazy as _
from mayan.apps.common.views import (
from mayan.apps.acls.models import AccessControlList
from mayan.apps.common.generics import (
AssignRemoveView, MultipleObjectConfirmActionView,
MultipleObjectFormActionView, SingleObjectCreateView,
SingleObjectDeleteView, SingleObjectDetailView, SingleObjectEditView,
SingleObjectListView
)
from mayan.apps.common.mixins import ExternalObjectMixin
from .events import (
event_group_created, event_group_edited, event_user_created,
@@ -52,7 +54,9 @@ class CurrentUserDetailsView(SingleObjectDetailView):
class CurrentUserEditView(SingleObjectEditView):
extra_context = {'object': None, 'title': _('Edit current user details')}
form_class = UserForm
post_action_redirect = reverse_lazy('user_management:current_user_details')
post_action_redirect = reverse_lazy(
viewname='user_management:current_user_details'
)
def get_object(self):
return self.request.user
@@ -62,38 +66,50 @@ class GroupCreateView(SingleObjectCreateView):
extra_context = {'title': _('Create new group')}
fields = ('name',)
model = Group
post_action_redirect = reverse_lazy('user_management:group_list')
post_action_redirect = reverse_lazy(viewname='user_management:group_list')
view_permission = permission_group_create
def form_valid(self, form):
group = form.save()
with transaction.atomic():
result = super(GroupCreateView, self).form_valid(form=form)
event_group_created.commit(
actor=self.request.user, target=group
actor=self.request.user, target=self.object
)
return result
messages.success(
self.request, _('Group "%s" created successfully.') % group
)
return super(GroupCreateView, self).form_valid(form=form)
class GroupDeleteView(SingleObjectDeleteView):
model = Group
object_permission = permission_group_delete
pk_url_kwarg = 'group_id'
post_action_redirect = reverse_lazy(viewname='user_management:group_list')
def get_extra_context(self):
return {
'object': self.object,
'title': _('Delete the group: %s?') % self.object,
}
class GroupEditView(SingleObjectEditView):
fields = ('name',)
model = Group
object_permission = permission_group_edit
post_action_redirect = reverse_lazy('user_management:group_list')
pk_url_kwarg = 'group_id'
post_action_redirect = reverse_lazy(viewname='user_management:group_list')
def form_valid(self, form):
with transaction.atomic():
result = super(GroupEditView, self).form_valid(form=form)
event_group_edited.commit(
actor=self.request.user, target=self.get_object()
actor=self.request.user, target=self.object
)
return super(GroupEditView, self).form_valid(form=form)
return result
def get_extra_context(self):
return {
'object': self.get_object(),
'title': _('Edit group: %s') % self.get_object(),
'object': self.object,
'title': _('Edit group: %s') % self.object,
}
@@ -120,29 +136,20 @@ class GroupListView(SingleObjectListView):
}
class GroupDeleteView(SingleObjectDeleteView):
model = Group
object_permission = permission_group_delete
post_action_redirect = reverse_lazy('user_management:group_list')
def get_extra_context(self):
return {
'object': self.get_object(),
'title': _('Delete the group: %s?') % self.get_object(),
}
class GroupMembersView(AssignRemoveView):
class GroupMembersView(ExternalObjectMixin, AssignRemoveView):
decode_content_type = True
external_object_class = Group
external_object_permission = permission_group_edit
external_object_pk_url_kwarg = 'group_id'
left_list_title = _('Available users')
right_list_title = _('Users in group')
object_permission = permission_group_edit
right_list_title = _('Users in group')
@staticmethod
def generate_choices(choices):
results = []
for choice in choices:
ct = ContentType.objects.get_for_model(choice)
ct = ContentType.objects.get_for_model(model=choice)
label = choice.get_full_name() if choice.get_full_name() else choice
results.append(('%s,%s' % (ct.model, choice.pk), '%s' % (label)))
@@ -151,31 +158,43 @@ class GroupMembersView(AssignRemoveView):
return sorted(results, key=lambda x: x[1])
def add(self, item):
self.get_object().user_set.add(item)
self.object.user_set.add(item)
def dispatch(self, *args, **kwargs):
self.object = self.get_object()
return super(GroupMembersView, self).dispatch(*args, **kwargs)
def get_extra_context(self):
return {
'object': self.get_object(),
'title': _('Users of group: %s') % self.get_object()
'object': self.object,
'title': _('Users of group: %s') % self.object
}
def get_object(self):
return get_object_or_404(klass=Group, pk=self.kwargs['pk'])
return self.get_external_object()
def left_list(self):
return GroupMembersView.generate_choices(
get_user_model().objects.exclude(
groups=self.get_object()
).exclude(is_staff=True).exclude(is_superuser=True)
queryset = AccessControlList.objects.restrict_queryset(
permission=permission_user_edit,
queryset=get_user_model().objects.exclude(
groups=self.object
).exclude(is_staff=True).exclude(is_superuser=True),
user=self.request.user
)
return GroupMembersView.generate_choices(choices=queryset)
def right_list(self):
return GroupMembersView.generate_choices(
self.get_object().user_set.all()
queryset = AccessControlList.objects.restrict_queryset(
permission=permission_user_edit,
queryset=self.object.user_set.all(),
user=self.request.user
)
return GroupMembersView.generate_choices(choices=queryset)
def remove(self, item):
self.get_object().user_set.remove(item)
self.object.user_set.remove(item)
class UserCreateView(SingleObjectCreateView):
@@ -186,25 +205,24 @@ class UserCreateView(SingleObjectCreateView):
view_permission = permission_user_create
def form_valid(self, form):
user = form.save(commit=False)
user.set_unusable_password()
user.save()
with transaction.atomic():
super(UserCreateView, self).form_valid(form=form)
event_user_created.commit(
actor=self.request.user, target=user
actor=self.request.user, target=self.object
)
messages.success(
self.request, _('User "%s" created successfully.') % user
)
return HttpResponseRedirect(
reverse('user_management:user_set_password', args=(user.pk,))
reverse(
viewname='user_management:user_set_password',
kwargs={'user_id': self.object.pk}
)
)
class UserDeleteView(MultipleObjectConfirmActionView):
object_permission = permission_user_delete
queryset = get_user_model().objects.filter(
pk_url_kwarg = 'user_id'
source_queryset = get_user_model().objects.filter(
is_superuser=False, is_staff=False
)
success_message = _('User delete request performed on %(count)d user')
@@ -213,13 +231,13 @@ class UserDeleteView(MultipleObjectConfirmActionView):
)
def get_extra_context(self):
queryset = self.get_queryset()
queryset = self.get_object_list()
result = {
'title': ungettext(
'Delete user',
'Delete users',
queryset.count()
singular='Delete user',
plural='Delete users',
number=queryset.count()
)
}
@@ -235,26 +253,18 @@ class UserDeleteView(MultipleObjectConfirmActionView):
def object_action(self, form, instance):
try:
if instance.is_superuser or instance.is_staff:
messages.error(
self.request,
_(
'Super user and staff user deleting is not '
'allowed, use the admin interface for these cases.'
)
)
else:
instance.delete()
messages.success(
self.request, _(
message=_(
'User "%s" deleted successfully.'
) % instance
) % instance, request=self.request
)
except Exception as exception:
messages.error(
self.request, _(
message=_(
'Error deleting user "%(user)s": %(error)s'
) % {'user': instance, 'error': exception}
) % {'user': instance, 'error': exception},
request=self.request
)
@@ -264,7 +274,8 @@ class UserDetailsView(SingleObjectDetailView):
'date_joined', 'groups',
)
object_permission = permission_user_view
queryset = get_user_model().objects.filter(
pk_url_kwarg = 'user_id'
source_queryset = get_user_model().objects.filter(
is_superuser=False, is_staff=False
)
@@ -278,58 +289,72 @@ class UserDetailsView(SingleObjectDetailView):
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(
pk_url_kwarg = 'user_id'
post_action_redirect = reverse_lazy(viewname='user_management:user_list')
source_queryset = get_user_model().objects.filter(
is_superuser=False, is_staff=False
)
def form_valid(self, form):
with transaction.atomic():
result = super(UserEditView, self).form_valid(form=form)
event_user_edited.commit(
actor=self.request.user, target=self.get_object()
actor=self.request.user, target=self.object
)
return super(UserEditView, self).form_valid(form=form)
return result
def get_extra_context(self):
return {
'object': self.get_object(),
'title': _('Edit user: %s') % self.get_object(),
'object': self.object,
'title': _('Edit user: %s') % self.object,
}
class UserGroupsView(AssignRemoveView):
class UserGroupsView(ExternalObjectMixin, AssignRemoveView):
decode_content_type = True
external_object_queryset = get_user_model().objects.filter(
is_staff=False, is_superuser=False
)
external_object_permission = permission_user_edit
external_object_pk_url_kwarg = 'user_id'
left_list_title = _('Available groups')
right_list_title = _('Groups joined')
object_permission = permission_user_edit
def add(self, item):
item.user_set.add(self.get_object())
item.user_set.add(self.object)
def dispatch(self, *args, **kwargs):
self.object = self.get_object()
return super(UserGroupsView, self).dispatch(*args, **kwargs)
def get_extra_context(self):
return {
'object': self.get_object(),
'title': _('Groups of user: %s') % self.get_object()
'object': self.object,
'title': _('Groups of user: %s') % self.object
}
def get_object(self):
return get_object_or_404(
klass=get_user_model().objects.filter(
is_superuser=False, is_staff=False
), pk=self.kwargs['pk']
)
return self.get_external_object()
def left_list(self):
return AssignRemoveView.generate_choices(
Group.objects.exclude(user=self.get_object())
queryset = AccessControlList.objects.restrict_queryset(
permission=permission_group_edit,
queryset=Group.objects.exclude(user=self.object),
user=self.request.user
)
return AssignRemoveView.generate_choices(choices=queryset)
def right_list(self):
return AssignRemoveView.generate_choices(
Group.objects.filter(user=self.get_object())
queryset = AccessControlList.objects.restrict_queryset(
permission=permission_group_edit,
queryset=Group.objects.filter(user=self.object),
user=self.request.user
)
return AssignRemoveView.generate_choices(choices=queryset)
def remove(self, item):
item.user_set.remove(self.get_object())
item.user_set.remove(self.object)
class UserListView(SingleObjectListView):
@@ -350,7 +375,7 @@ class UserListView(SingleObjectListView):
'title': _('Users'),
}
def get_object_list(self):
def get_source_queryset(self):
return get_user_model().objects.exclude(
is_superuser=True
).exclude(is_staff=True).order_by('last_name', 'first_name')
@@ -372,13 +397,13 @@ class UserOptionsEditView(SingleObjectEditView):
return self.get_user().user_options
def get_post_action_redirect(self):
return reverse('user_management:user_list')
return reverse(viewname='user_management:user_list')
def get_user(self):
return get_object_or_404(
klass=get_user_model().objects.filter(
is_superuser=False, is_staff=False
), pk=self.kwargs['pk']
), pk=self.kwargs['user_id']
)
@@ -386,66 +411,57 @@ class UserSetPasswordView(MultipleObjectFormActionView):
form_class = SetPasswordForm
model = get_user_model()
object_permission = permission_user_edit
pk_url_kwarg = 'user_id'
source_queryset = get_user_model().objects.filter(
is_superuser=False, is_staff=False
)
success_message = _('Password change request performed on %(count)d user')
success_message_plural = _(
'Password change request performed on %(count)d users'
)
def get_extra_context(self):
queryset = self.get_queryset()
queryset = self.get_object_list()
result = {
'submit_label': _('Submit'),
'title': ungettext(
'Change user password',
'Change users passwords',
queryset.count()
)
singular='Change the password of the %(count)d selected user',
plural='Change the password of the %(count)d selected users',
number=queryset.count()
) % {'count': queryset.count()}
}
if queryset.count() == 1:
result.update(
{
'object': queryset.first(),
'title': _('Change password for user: %s') % queryset.first()
'title': _(
'Change the password of user: %s'
) % queryset.first()
}
)
return result
def get_form_extra_kwargs(self):
queryset = self.get_queryset()
result = {}
if queryset:
result['user'] = queryset.first()
return result
else:
raise PermissionDenied
queryset = self.get_object_list()
return {'user': queryset.first()}
def object_action(self, form, instance):
try:
if instance.is_superuser or instance.is_staff:
messages.error(
self.request,
_(
'Super user and staff user password '
'reseting is not allowed, use the admin '
'interface for these cases.'
)
)
else:
instance.set_password(form.cleaned_data['new_password1'])
instance.save()
messages.success(
self.request, _(
message=_(
'Successful password reset for user: %s.'
) % instance
) % instance, request=self.request
)
except Exception as exception:
messages.error(
self.request, _(
message=_(
'Error reseting password for user "%(user)s": %(error)s'
) % {
'user': instance, 'error': exception
}
}, request=self.request
)