User groups, group users views to AddRemoveView
Signed-off-by: Roberto Rosario <roberto.rosario.gonzalez@gmail.com>
This commit is contained in:
@@ -150,6 +150,14 @@
|
||||
* Add AddRemoveView to replace AssignRemoveView
|
||||
* Update the group roles view to use the new AddRemoveView.
|
||||
* Add role create and edit events.
|
||||
* Sort users by lastname, firstname.
|
||||
* Switch user groups and group users views to AddRemoveView.
|
||||
* Commit user edit event when an user is added or removed
|
||||
from a group.
|
||||
* Commit the group edit event when a group is added or remove
|
||||
from an user.
|
||||
* Require dual permissions when add or removing users to and
|
||||
from group. Same with group to users.
|
||||
|
||||
3.1.11 (2019-04-XX)
|
||||
===================
|
||||
|
||||
@@ -182,6 +182,14 @@ Other changes
|
||||
* Add AddRemoveView to replace AssignRemoveView
|
||||
* Update the group roles view to use the new AddRemoveView.
|
||||
* Add role create and edit events.
|
||||
* Sort users by lastname, firstname.
|
||||
* Switch user groups and group users views to AddRemoveView.
|
||||
* Commit user edit event when an user is added or removed
|
||||
from a group.
|
||||
* Commit the group edit event when a group is added or remove
|
||||
from an user.
|
||||
* Require dual permissions when add or removing users to and
|
||||
from group. Same with group to users.
|
||||
|
||||
Removals
|
||||
--------
|
||||
|
||||
@@ -37,7 +37,9 @@ from .links import (
|
||||
text_user_label
|
||||
)
|
||||
from .methods import (
|
||||
get_method_group_save, get_method_user_save, method_user_get_absolute_url
|
||||
get_method_group_save, get_method_user_save, method_user_get_absolute_url,
|
||||
method_group_get_users, method_group_users_add, method_group_users_remove,
|
||||
method_user_get_groups, method_user_groups_add, method_user_groups_remove
|
||||
)
|
||||
|
||||
from .permissions import (
|
||||
@@ -89,6 +91,15 @@ class UserManagementApp(MayanAppConfig):
|
||||
Group._meta.verbose_name = _('Group')
|
||||
Group._meta.verbose_name_plural = _('Groups')
|
||||
|
||||
Group.add_to_class(
|
||||
name='get_users', value=method_group_get_users
|
||||
)
|
||||
Group.add_to_class(
|
||||
name='users_add', value=method_group_users_add
|
||||
)
|
||||
Group.add_to_class(
|
||||
name='users_remove', value=method_group_users_remove
|
||||
)
|
||||
Group.add_to_class(name='save', value=get_method_group_save())
|
||||
|
||||
MetadataLookup(
|
||||
@@ -161,10 +172,20 @@ class UserManagementApp(MayanAppConfig):
|
||||
User._meta.ordering = ('pk',)
|
||||
User._meta.verbose_name = _('User')
|
||||
User._meta.verbose_name_plural = _('Users')
|
||||
User._meta.ordering = ('last_name', 'first_name')
|
||||
|
||||
User.add_to_class(
|
||||
name='get_absolute_url', value=method_user_get_absolute_url
|
||||
)
|
||||
User.add_to_class(
|
||||
name='get_groups', value=method_user_get_groups
|
||||
)
|
||||
User.add_to_class(
|
||||
name='groups_add', value=method_user_groups_add
|
||||
)
|
||||
User.add_to_class(
|
||||
name='groups_remove', value=method_user_groups_remove
|
||||
)
|
||||
User.add_to_class(name='save', value=get_method_user_save())
|
||||
|
||||
menu_list_facet.bind_links(
|
||||
|
||||
@@ -9,6 +9,8 @@ from .events import (
|
||||
event_group_created, event_group_edited, event_user_created,
|
||||
event_user_edited
|
||||
)
|
||||
from .permissions import permission_group_view, permission_user_view
|
||||
from .querysets import get_user_queryset
|
||||
|
||||
|
||||
def get_method_group_save():
|
||||
@@ -33,12 +35,82 @@ def get_method_group_save():
|
||||
return method_group_save
|
||||
|
||||
|
||||
def method_group_get_users(self, user, permission=permission_user_view):
|
||||
AccessControlList = apps.get_model(
|
||||
app_label='acls', model_name='AccessControlList'
|
||||
)
|
||||
|
||||
return AccessControlList.objects.filter_by_access(
|
||||
permission=permission, queryset=get_user_queryset().filter(
|
||||
id__in=self.user_set.all()
|
||||
), user=user
|
||||
)
|
||||
|
||||
|
||||
def method_group_users_add(self, queryset, _user):
|
||||
with transaction.atomic():
|
||||
event_group_edited.commit(
|
||||
actor=_user, target=self
|
||||
)
|
||||
for user in queryset:
|
||||
self.user_set.add(user)
|
||||
event_user_edited.commit(
|
||||
actor=_user, target=user
|
||||
)
|
||||
|
||||
|
||||
def method_group_users_remove(self, queryset, _user):
|
||||
with transaction.atomic():
|
||||
event_group_edited.commit(
|
||||
actor=_user, target=self
|
||||
)
|
||||
for user in queryset:
|
||||
self.user_set.remove(user)
|
||||
event_user_edited.commit(
|
||||
actor=_user, target=user
|
||||
)
|
||||
|
||||
|
||||
def method_user_get_absolute_url(self):
|
||||
return reverse(
|
||||
viewname='user_management:user_details', kwargs={'pk': self.pk}
|
||||
)
|
||||
|
||||
|
||||
def method_user_get_groups(self, user, permission=permission_group_view):
|
||||
AccessControlList = apps.get_model(
|
||||
app_label='acls', model_name='AccessControlList'
|
||||
)
|
||||
|
||||
return AccessControlList.objects.filter_by_access(
|
||||
permission=permission, queryset=self.groups.all(), user=user
|
||||
)
|
||||
|
||||
|
||||
def method_user_groups_add(self, queryset, _user):
|
||||
with transaction.atomic():
|
||||
event_user_edited.commit(
|
||||
actor=_user, target=self
|
||||
)
|
||||
for group in queryset:
|
||||
self.groups.add(group)
|
||||
event_group_edited.commit(
|
||||
actor=_user, target=group
|
||||
)
|
||||
|
||||
|
||||
def method_user_groups_remove(self, queryset, _user):
|
||||
with transaction.atomic():
|
||||
event_user_edited.commit(
|
||||
actor=_user, target=self
|
||||
)
|
||||
for group in queryset:
|
||||
self.groups.remove(group)
|
||||
event_group_edited.commit(
|
||||
actor=_user, target=group
|
||||
)
|
||||
|
||||
|
||||
def get_method_user_save():
|
||||
user_save_original = get_user_model().save
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ class GroupViewsTestCase(GroupTestMixin, GroupViewTestMixin, UserTestMixin, Gene
|
||||
self.test_user.groups.add(self.test_group)
|
||||
|
||||
response = self._request_test_group_members_view()
|
||||
self.assertEqual(response.status_code, 403)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_group_members_view_with_group_access(self):
|
||||
self._create_test_user()
|
||||
@@ -141,7 +141,7 @@ class GroupViewsTestCase(GroupTestMixin, GroupViewTestMixin, UserTestMixin, Gene
|
||||
|
||||
response = self._request_test_group_members_view()
|
||||
self.assertNotContains(
|
||||
response=response, text=self.test_group.name, status_code=403
|
||||
response=response, text=self.test_group.name, status_code=404
|
||||
)
|
||||
|
||||
def test_group_members_view_with_full_access(self):
|
||||
@@ -311,7 +311,7 @@ class UserGroupViewTestCase(GroupTestMixin, UserTestMixin, UserViewTestMixin, Ge
|
||||
self.test_user.groups.add(self.test_group)
|
||||
|
||||
response = self._request_test_user_groups_view()
|
||||
self.assertEqual(response.status_code, 403)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_user_groups_view_with_group_access(self):
|
||||
self._create_test_user()
|
||||
@@ -323,7 +323,7 @@ class UserGroupViewTestCase(GroupTestMixin, UserTestMixin, UserViewTestMixin, Ge
|
||||
|
||||
response = self._request_test_user_groups_view()
|
||||
self.assertNotContains(
|
||||
response=response, text=self.test_user.username, status_code=403
|
||||
response=response, text=self.test_user.username, status_code=404
|
||||
)
|
||||
|
||||
def test_user_groups_view_with_user_access(self):
|
||||
|
||||
@@ -4,7 +4,6 @@ from django.contrib import messages
|
||||
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
|
||||
@@ -12,12 +11,11 @@ from django.template import RequestContext
|
||||
from django.urls import reverse, reverse_lazy
|
||||
from django.utils.translation import ungettext, ugettext_lazy as _
|
||||
|
||||
from mayan.apps.acls.models import AccessControlList
|
||||
from mayan.apps.common.generics import AddRemoveView
|
||||
from mayan.apps.common.views import (
|
||||
AssignRemoveView, MultipleObjectConfirmActionView,
|
||||
MultipleObjectFormActionView, SingleObjectCreateView,
|
||||
SingleObjectDeleteView, SingleObjectDetailView, SingleObjectEditView,
|
||||
SingleObjectListView
|
||||
MultipleObjectConfirmActionView, MultipleObjectFormActionView,
|
||||
SingleObjectCreateView, SingleObjectDeleteView, SingleObjectDetailView,
|
||||
SingleObjectEditView, SingleObjectListView
|
||||
)
|
||||
|
||||
from .forms import UserForm
|
||||
@@ -28,6 +26,7 @@ from .permissions import (
|
||||
permission_group_view, permission_user_create, permission_user_delete,
|
||||
permission_user_edit, permission_user_view
|
||||
)
|
||||
from .querysets import get_user_queryset
|
||||
|
||||
|
||||
class CurrentUserDetailsView(SingleObjectDetailView):
|
||||
@@ -126,62 +125,31 @@ class GroupDeleteView(SingleObjectDeleteView):
|
||||
}
|
||||
|
||||
|
||||
class GroupUsersView(AssignRemoveView):
|
||||
decode_content_type = True
|
||||
left_list_title = _('Available users')
|
||||
right_list_title = _('Users in group')
|
||||
object_permission = permission_group_edit
|
||||
class GroupUsersView(AddRemoveView):
|
||||
action_add_method = 'users_add'
|
||||
action_remove_method = 'users_remove'
|
||||
main_object_model = Group
|
||||
main_object_permission = permission_group_edit
|
||||
main_object_pk_url_kwarg = 'pk'
|
||||
secondary_object_permission = permission_user_edit
|
||||
secondary_object_source_queryset = get_user_queryset()
|
||||
list_available_title = _('Available users')
|
||||
list_added_title = _('Group users')
|
||||
|
||||
@staticmethod
|
||||
def generate_choices(choices):
|
||||
results = []
|
||||
for choice in choices:
|
||||
ct = ContentType.objects.get_for_model(choice)
|
||||
label = choice.get_full_name() if choice.get_full_name() else choice
|
||||
|
||||
results.append(('%s,%s' % (ct.model, choice.pk), '%s' % (label)))
|
||||
|
||||
# Sort results by the label not the key value
|
||||
return sorted(results, key=lambda x: x[1])
|
||||
|
||||
def add(self, item):
|
||||
self.get_object().user_set.add(item)
|
||||
def get_actions_extra_kwargs(self):
|
||||
return {'_user': self.request.user}
|
||||
|
||||
def get_extra_context(self):
|
||||
return {
|
||||
'object': self.get_object(),
|
||||
'title': _('Users of group: %s') % self.get_object()
|
||||
'object': self.main_object,
|
||||
'title': _('Users of group: %s') % self.main_object,
|
||||
}
|
||||
|
||||
def get_object(self):
|
||||
return get_object_or_404(klass=Group, pk=self.kwargs['pk'])
|
||||
|
||||
def get_choices_queryset(self):
|
||||
return AccessControlList.objects.filter_by_access(
|
||||
permission=permission_user_edit,
|
||||
queryset=get_user_model().objects.exclude(
|
||||
is_staff=True
|
||||
).exclude(is_superuser=True),
|
||||
user=self.request.user
|
||||
def get_list_added_queryset(self):
|
||||
return self.main_object.get_users(
|
||||
permission=permission_user_edit, user=self.request.user
|
||||
)
|
||||
|
||||
def left_list(self):
|
||||
return GroupUsersView.generate_choices(
|
||||
self.get_choices_queryset().exclude(
|
||||
groups=self.get_object()
|
||||
)
|
||||
)
|
||||
|
||||
def right_list(self):
|
||||
return GroupUsersView.generate_choices(
|
||||
self.get_choices_queryset().filter(
|
||||
pk__in=self.get_object().user_set.all()
|
||||
)
|
||||
)
|
||||
|
||||
def remove(self, item):
|
||||
self.get_object().user_set.remove(item)
|
||||
|
||||
|
||||
class UserCreateView(SingleObjectCreateView):
|
||||
extra_context = {
|
||||
@@ -199,16 +167,13 @@ class UserCreateView(SingleObjectCreateView):
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def get_save_extra_data(self):
|
||||
return {'_user': self.request.user}
|
||||
|
||||
|
||||
class UserDeleteView(MultipleObjectConfirmActionView):
|
||||
object_permission = permission_user_delete
|
||||
queryset = get_user_model().objects.filter(
|
||||
is_superuser=False, is_staff=False
|
||||
)
|
||||
queryset = get_user_queryset()
|
||||
success_message = _('User delete request performed on %(count)d user')
|
||||
success_message_plural = _(
|
||||
'User delete request performed on %(count)d users'
|
||||
@@ -267,9 +232,7 @@ class UserDetailsView(SingleObjectDetailView):
|
||||
)
|
||||
object_permission = permission_user_view
|
||||
pk_url_kwarg = 'pk'
|
||||
queryset = get_user_model().objects.filter(
|
||||
is_superuser=False, is_staff=False
|
||||
)
|
||||
queryset = get_user_queryset()
|
||||
|
||||
def get_extra_context(self, **kwargs):
|
||||
return {
|
||||
@@ -284,9 +247,7 @@ class UserEditView(SingleObjectEditView):
|
||||
post_action_redirect = reverse_lazy(
|
||||
viewname='user_management:user_list'
|
||||
)
|
||||
queryset = get_user_model().objects.filter(
|
||||
is_superuser=False, is_staff=False
|
||||
)
|
||||
queryset = get_user_queryset()
|
||||
|
||||
def get_extra_context(self):
|
||||
return {
|
||||
@@ -298,47 +259,31 @@ class UserEditView(SingleObjectEditView):
|
||||
return {'_user': self.request.user}
|
||||
|
||||
|
||||
class UserGroupsView(AssignRemoveView):
|
||||
decode_content_type = True
|
||||
left_list_title = _('Available groups')
|
||||
right_list_title = _('Groups joined')
|
||||
object_permission = permission_user_edit
|
||||
class UserGroupsView(AddRemoveView):
|
||||
action_add_method = 'groups_add'
|
||||
action_remove_method = 'groups_remove'
|
||||
main_object_permission = permission_user_edit
|
||||
main_object_source_queryset = get_user_queryset()
|
||||
main_object_pk_url_kwarg = 'pk'
|
||||
secondary_object_model = Group
|
||||
secondary_object_permission = permission_group_edit
|
||||
list_available_title = _('Available groups')
|
||||
list_added_title = _('User groups')
|
||||
|
||||
def add(self, item):
|
||||
item.user_set.add(self.get_object())
|
||||
def get_actions_extra_kwargs(self):
|
||||
return {'_user': self.request.user}
|
||||
|
||||
def get_extra_context(self):
|
||||
return {
|
||||
'object': self.get_object(),
|
||||
'title': _('Groups of user: %s') % self.get_object()
|
||||
'object': self.main_object,
|
||||
'title': _('Groups of user: %s') % self.main_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']
|
||||
)
|
||||
|
||||
def get_choices_queryset(self):
|
||||
return AccessControlList.objects.filter_by_access(
|
||||
queryset=Group.objects.filter(user=self.get_object()),
|
||||
def get_list_added_queryset(self):
|
||||
return self.main_object.get_groups(
|
||||
permission=permission_group_edit, user=self.request.user
|
||||
)
|
||||
|
||||
def left_list(self):
|
||||
return AssignRemoveView.generate_choices(
|
||||
self.get_choices_queryset().exclude(user=self.get_object())
|
||||
)
|
||||
|
||||
def right_list(self):
|
||||
return AssignRemoveView.generate_choices(
|
||||
self.get_choices_queryset().filter(user=self.get_object())
|
||||
)
|
||||
|
||||
def remove(self, item):
|
||||
item.user_set.remove(self.get_object())
|
||||
|
||||
|
||||
class UserListView(SingleObjectListView):
|
||||
object_permission = permission_user_view
|
||||
@@ -360,9 +305,7 @@ class UserListView(SingleObjectListView):
|
||||
}
|
||||
|
||||
def get_object_list(self):
|
||||
return get_user_model().objects.exclude(
|
||||
is_superuser=True
|
||||
).exclude(is_staff=True).order_by('last_name', 'first_name')
|
||||
return get_user_queryset()
|
||||
|
||||
|
||||
class UserOptionsEditView(SingleObjectEditView):
|
||||
@@ -385,9 +328,7 @@ class UserOptionsEditView(SingleObjectEditView):
|
||||
|
||||
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']
|
||||
klass=get_user_queryset(), pk=self.kwargs['pk']
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user