diff --git a/mayan/apps/user_management/serializers.py b/mayan/apps/user_management/serializers.py index 2430629d35..83b4ca54c3 100644 --- a/mayan/apps/user_management/serializers.py +++ b/mayan/apps/user_management/serializers.py @@ -2,8 +2,10 @@ from __future__ import unicode_literals from django.contrib.auth import get_user_model from django.contrib.auth.models import Group +from django.utils.translation import ugettext_lazy as _ from rest_framework import serializers +from rest_framework.exceptions import ValidationError class GroupSerializer(serializers.HyperlinkedModelSerializer): @@ -21,10 +23,16 @@ class GroupSerializer(serializers.HyperlinkedModelSerializer): class UserSerializer(serializers.HyperlinkedModelSerializer): - groups = GroupSerializer(many=True) + groups = GroupSerializer(read_only=True, many=True) + + groups_pk_list = serializers.CharField( + help_text=_( + 'List of group primary keys to which to the user.' + ), required=False + ) password = serializers.CharField( - required=False, style={'input_type': 'password'} + required=False, style={'input_type': 'password'}, write_only=True ) class Meta: @@ -32,30 +40,47 @@ class UserSerializer(serializers.HyperlinkedModelSerializer): 'url': {'view_name': 'rest_api:user-detail'} } fields = ( - 'first_name', 'date_joined', 'email', 'groups', 'id', 'is_active', - 'last_login', 'last_name', 'url', 'username', 'password' + 'first_name', 'date_joined', 'email', 'groups', 'groups_pk_list', + 'id', 'is_active', 'last_login', 'last_name', 'password', 'url', + 'username' ) model = get_user_model() - read_only_fields = ('last_login', 'date_joined') - write_only_fields = ('password',) + read_only_fields = ('groups', 'is_active', 'last_login', 'date_joined') + write_only_fields = ('password', 'group_pk_list') def create(self, validated_data): - validated_data.pop('groups') - validated_data.pop('is_active') - user = get_user_model().objects.create_user(**validated_data) + groups_pk_list = validated_data.pop('groups_pk_list', '') + password = validated_data.pop('password', None) + instance = super(UserSerializer, self).create(validated_data) - return user + if password: + instance.set_password(password) + instance.save() + + if groups_pk_list: + try: + for group in Group.objects.filter(pk__in=groups_pk_list.split(',')): + instance.groups.add(group) + except Exception as exception: + raise ValidationError(exception) + + return instance def update(self, instance, validated_data): - validated_data.pop('groups') - if 'password' in validated_data: instance.set_password(validated_data['password']) validated_data.pop('password') - for attr, value in validated_data.items(): - setattr(instance, attr, value) + result = super(UserSerializer, self).update(instance, validated_data) - instance.save() + groups_pk_list = validated_data.pop('groups_pk_list', '') - return instance + if groups_pk_list: + instance.groups.clear() + try: + for group in Group.objects.filter(pk__in=groups_pk_list.split(',')): + instance.groups.add(group) + except Exception as exception: + raise ValidationError(exception) + + return result diff --git a/mayan/apps/user_management/tests/test_api.py b/mayan/apps/user_management/tests/test_api.py index e5eb2b561c..8a952da42c 100644 --- a/mayan/apps/user_management/tests/test_api.py +++ b/mayan/apps/user_management/tests/test_api.py @@ -1,7 +1,7 @@ from __future__ import unicode_literals from django.contrib.auth import get_user_model - +from django.contrib.auth.models import Group from django.core.urlresolvers import reverse from rest_framework.test import APITestCase @@ -47,6 +47,43 @@ class UserManagementAPITestCase(APITestCase): user = get_user_model().objects.get(pk=response.data['id']) self.assertEqual(user.username, TEST_USER_USERNAME) + def test_user_create_with_group(self): + group_1 = Group.objects.create(name='test group 1') + + response = self.client.post( + reverse('rest_api:user-list'), data={ + 'email': TEST_USER_EMAIL, 'password': TEST_USER_PASSWORD, + 'username': TEST_USER_USERNAME, + 'groups_pk_list': '{}'.format(group_1.pk) + } + ) + + self.assertEqual(response.status_code, 201) + + user = get_user_model().objects.get(pk=response.data['id']) + self.assertEqual(user.username, TEST_USER_USERNAME) + self.assertQuerysetEqual(user.groups.all(), (repr(group_1),)) + + def test_user_create_with_groups(self): + group_1 = Group.objects.create(name='test group 1') + group_2 = Group.objects.create(name='test group 2') + + response = self.client.post( + reverse('rest_api:user-list'), data={ + 'email': TEST_USER_EMAIL, 'password': TEST_USER_PASSWORD, + 'username': TEST_USER_USERNAME, + 'groups_pk_list': '{},{}'.format(group_1.pk, group_2.pk) + } + ) + + self.assertEqual(response.status_code, 201) + + user = get_user_model().objects.get(pk=response.data['id']) + self.assertEqual(user.username, TEST_USER_USERNAME) + self.assertQuerysetEqual( + user.groups.all().order_by('name'), (repr(group_1), repr(group_2)) + ) + def test_user_create_login(self): response = self.client.post( reverse('rest_api:user-list'), data={ @@ -57,7 +94,35 @@ class UserManagementAPITestCase(APITestCase): self.assertEqual(response.status_code, 201) - get_user_model().objects.get(pk=response.data['id']) + self.assertTrue( + self.client.login( + username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD + ) + ) + + def test_user_create_login_password_change(self): + response = self.client.post( + reverse('rest_api:user-list'), data={ + 'email': TEST_USER_EMAIL, 'password': 'bad_password', + 'username': TEST_USER_USERNAME, + } + ) + + self.assertEqual(response.status_code, 201) + + self.assertFalse( + self.client.login( + username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD + ) + ) + + user = get_user_model().objects.get(pk=response.data['id']) + + response = self.client.patch( + reverse('rest_api:user-detail', args=(user.pk,)), data={ + 'password': TEST_USER_PASSWORD, + } + ) self.assertTrue( self.client.login( @@ -81,7 +146,7 @@ class UserManagementAPITestCase(APITestCase): user.refresh_from_db() self.assertEqual(user.username, TEST_USER_USERNAME_EDITED) - def test_document_type_edit_via_patch(self): + def test_user_edit_via_patch(self): user = get_user_model().objects.create_user( email=TEST_USER_EMAIL, password=TEST_USER_PASSWORD, username=TEST_USER_USERNAME @@ -97,7 +162,45 @@ class UserManagementAPITestCase(APITestCase): user.refresh_from_db() self.assertEqual(user.username, TEST_USER_USERNAME_EDITED) - def test_document_type_delete(self): + def test_user_edit_remove_groups_via_patch(self): + user = get_user_model().objects.create_user( + email=TEST_USER_EMAIL, password=TEST_USER_PASSWORD, + username=TEST_USER_USERNAME + ) + group_1 = Group.objects.create(name='test group 1') + user.groups.add(group_1) + + response = self.client.patch( + reverse('rest_api:user-detail', args=(user.pk,)), + ) + + self.assertEqual(response.status_code, 200) + + user.refresh_from_db() + self.assertQuerysetEqual( + user.groups.all().order_by('name'), (repr(group_1),) + ) + + def test_user_edit_add_groups_via_patch(self): + user = get_user_model().objects.create_user( + email=TEST_USER_EMAIL, password=TEST_USER_PASSWORD, + username=TEST_USER_USERNAME + ) + group_1 = Group.objects.create(name='test group 1') + + response = self.client.patch( + reverse('rest_api:user-detail', args=(user.pk,)), + data={'groups_pk_list': '{}'.format(group_1.pk)} + ) + + self.assertEqual(response.status_code, 200) + + user.refresh_from_db() + self.assertQuerysetEqual( + user.groups.all().order_by('name'), (repr(group_1),) + ) + + def test_user_delete(self): user = get_user_model().objects.create_user( email=TEST_USER_EMAIL, password=TEST_USER_PASSWORD, username=TEST_USER_USERNAME