Skip to content

Commit

Permalink
added USER_CREATE_PASSWORD_RETYPE option to validate re_password on u…
Browse files Browse the repository at this point in the history
…ser creation
  • Loading branch information
Chadys committed May 21, 2019
1 parent 8af0c41 commit d07bd1c
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 2 deletions.
3 changes: 3 additions & 0 deletions djoser/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def __getattribute__(self, item):
default_settings = {
'SEND_ACTIVATION_EMAIL': False,
'SEND_CONFIRMATION_EMAIL': False,
'USER_CREATE_PASSWORD_RETYPE': False,
'SET_PASSWORD_RETYPE': False,
'SET_USERNAME_RETYPE': False,
'PASSWORD_RESET_CONFIRM_RETYPE': False,
Expand All @@ -53,6 +54,8 @@ def __getattribute__(self, item):
'djoser.serializers.SetUsernameRetypeSerializer',
'user_create':
'djoser.serializers.UserCreateSerializer',
'user_create_password_retype':
'djoser.serializers.UserCreatePasswordRetypeSerializer',
'user_delete':
'djoser.serializers.UserDeleteSerializer',
'user':
Expand Down
18 changes: 18 additions & 0 deletions djoser/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,24 @@ def perform_create(self, validated_data):
return user


class UserCreatePasswordRetypeSerializer(UserCreateSerializer):
default_error_messages = {
'password_mismatch': settings.CONSTANTS.messages.PASSWORD_MISMATCH_ERROR,
}

def __init__(self, *args, **kwargs):
super(UserCreatePasswordRetypeSerializer, self).__init__(*args, **kwargs)
self.fields['re_password'] = serializers.CharField(style={'input_type': 'password'})

def validate(self, attrs):
re_password = attrs.pop('re_password')
attrs = super(UserCreatePasswordRetypeSerializer, self).validate(attrs)
if attrs['password'] == re_password:
return attrs
else:
self.fail('password_mismatch')


class TokenCreateSerializer(serializers.Serializer):
password = serializers.CharField(
required=False, style={'input_type': 'password'}
Expand Down
8 changes: 7 additions & 1 deletion djoser/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,13 @@ class UserCreateView(UserCreateMixin, generics.CreateAPIView):
"""
Use this endpoint to register new user.
"""
serializer_class = settings.SERIALIZERS.user_create
permission_classes = settings.PERMISSIONS.user_create

def get_serializer_class(self):
if settings.USER_CREATE_PASSWORD_RETYPE:
return settings.SERIALIZERS.user_create_password_retype
return settings.SERIALIZERS.user_create


class ResendActivationView(ActionViewMixin, generics.GenericAPIView):
"""
Expand Down Expand Up @@ -343,6 +347,8 @@ def get_permissions(self):

def get_serializer_class(self):
if self.action == 'create':
if settings.USER_CREATE_PASSWORD_RETYPE:
return settings.SERIALIZERS.user_create_password_retype
return settings.SERIALIZERS.user_create

elif self.action == 'remove' or (
Expand Down
7 changes: 6 additions & 1 deletion docs/source/base_endpoints.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,25 @@ fields.
**Default URL**: ``/users/``
**Backward-compatible URL**: ``/users/create/``

.. note::

``re_password`` is only required if ``USER_CREATE_PASSWORD_RETYPE`` is ``True``

+----------+-----------------------------------+----------------------------------+
| Method | Request | Response |
+==========+===================================+==================================+
| ``POST`` | * ``{{ User.USERNAME_FIELD }}`` | ``HTTP_201_CREATED`` |
| | * ``{{ User.REQUIRED_FIELDS }}`` | |
| | * ``password`` | * ``{{ User.USERNAME_FIELD }}`` |
| | | * ``{{ User._meta.pk.name }}`` |
| | * ``re_password`` | * ``{{ User._meta.pk.name }}`` |
| | | * ``{{ User.REQUIRED_FIELDS }}`` |
| | | |
| | | ``HTTP_400_BAD_REQUEST`` |
| | | |
| | | * ``{{ User.USERNAME_FIELD }}`` |
| | | * ``{{ User.REQUIRED_FIELDS }}`` |
| | | * ``password`` |
| | | * ``re_password`` |
+----------+-----------------------------------+----------------------------------+

User Delete
Expand Down
8 changes: 8 additions & 0 deletions docs/source/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ placeholders, e.g. ``#/activate/{uid}/{token}``. You should pass ``uid`` and

**Required**: ``True``

USER_CREATE_PASSWORD_RETYPE
---------------------------

If ``True``, you need to pass ``re_password`` to
``/users/`` endpoint, to validate password equality.

**Default**: ``False``

SET_USERNAME_RETYPE
-------------------

Expand Down
40 changes: 40 additions & 0 deletions testproject/testapp/tests/test_user_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,27 @@ def test_post_not_register_if_fails_password_validation(self):
'no666',
)

@override_settings(
DJOSER=dict(settings.DJOSER, **{'USER_CREATE_PASSWORD_RETYPE': True})
)
def test_post_not_register_if_password_mismatch(self):
data = {
'username': 'john',
'password': 'secret',
're_password': 'wrong',
'csrftoken': 'asdf',
}

request = self.factory.post(data=data)
response = self.view(request)

self.assert_status_equal(response, status.HTTP_400_BAD_REQUEST)
response.render()
self.assertEqual(
str(response.data['non_field_errors'][0]),
default_settings.CONSTANTS.messages.PASSWORD_MISMATCH_ERROR,
)

@mock.patch(
'djoser.serializers.UserCreateSerializer.perform_create',
side_effect=perform_create_mock
Expand Down Expand Up @@ -226,6 +247,25 @@ def test_post_not_register_if_fails_password_validation(self):
'no666',
)

@override_settings(
DJOSER=dict(settings.DJOSER, **{'USER_CREATE_PASSWORD_RETYPE': True})
)
def test_post_not_register_if_password_mismatch(self):
data = {
'username': 'john',
'password': 'secret',
're_password': 'wrong',
'csrftoken': 'asdf',
}

response = self.client.post(reverse('user-list'), data=data)

self.assert_status_equal(response, status.HTTP_400_BAD_REQUEST)
self.assertEqual(
str(response.data['non_field_errors'][0]),
default_settings.CONSTANTS.messages.PASSWORD_MISMATCH_ERROR,
)

@mock.patch(
'djoser.serializers.UserCreateSerializer.perform_create',
side_effect=perform_create_mock
Expand Down

0 comments on commit d07bd1c

Please sign in to comment.