Skip to content

Commit

Permalink
Issue #50: customizable send reset password link serializer
Browse files Browse the repository at this point in the history
  • Loading branch information
apragacz committed May 10, 2019
1 parent 260806d commit 3b9b981
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 35 deletions.
20 changes: 20 additions & 0 deletions rest_registration/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
from rest_framework import serializers
from rest_framework.exceptions import ValidationError

from rest_registration.exceptions import UserNotFound
from rest_registration.settings import registration_settings
from rest_registration.utils.users import (
authenticate_by_login_and_password_or_none,
get_user_by_lookup_dict,
get_user_login_fields,
get_user_setting
)

Expand Down Expand Up @@ -46,6 +49,23 @@ def get_email(self):
return self.validated_data['email']


class DefaultSendResetPasswordLinkSerializer(serializers.Serializer):
login = serializers.CharField(required=True)

def get_user(self):
login = self.validated_data['login']
user = None
for login_field in get_user_login_fields():
user = get_user_by_lookup_dict(
{login_field: login}, default=None, require_verified=False)
if user:
break

if not user:
raise UserNotFound()
return user


class DefaultUserProfileSerializer(serializers.ModelSerializer):
"""
Default serializer used for user profile. It will use these:
Expand Down
41 changes: 10 additions & 31 deletions rest_registration/api/views/reset_password.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
from django.contrib.auth import get_user_model
from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError
from django.http import Http404
from rest_framework import serializers
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny

from rest_registration.decorators import api_view_serializer_class
from rest_registration.exceptions import UserNotFound
from rest_registration.decorators import (
api_view_serializer_class,
api_view_serializer_class_getter
)
from rest_registration.notifications import send_verification_notification
from rest_registration.settings import registration_settings
from rest_registration.utils.responses import get_ok_response
from rest_registration.utils.users import (
get_user_by_id,
get_user_by_lookup_dict,
get_user_setting
)
from rest_registration.utils.users import get_user_by_id
from rest_registration.utils.verification import verify_signer_or_bad_request
from rest_registration.verification import URLParamsSigner

Expand Down Expand Up @@ -46,16 +43,8 @@ def _calculate_salt(self, data):
return salt


class SendResetPasswordLinkSerializer(serializers.Serializer):
login = serializers.CharField(required=True)


def get_login_fields():
user_class = get_user_model()
return get_user_setting('LOGIN_FIELDS') or [user_class.USERNAME_FIELD]


@api_view_serializer_class(SendResetPasswordLinkSerializer)
@api_view_serializer_class_getter(
lambda: registration_settings.SEND_RESET_PASSWORD_LINK_SERIALIZER_CLASS)
@api_view(['POST'])
@permission_classes([AllowAny])
def send_reset_password_link(request):
Expand All @@ -64,20 +53,10 @@ def send_reset_password_link(request):
'''
if not registration_settings.RESET_PASSWORD_VERIFICATION_ENABLED:
raise Http404()
serializer = SendResetPasswordLinkSerializer(data=request.data)
serializer_class = registration_settings.SEND_RESET_PASSWORD_LINK_SERIALIZER_CLASS # noqa: E501
serializer = serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
login = serializer.validated_data['login']

user = None
for login_field in get_login_fields():
user = get_user_by_lookup_dict(
{login_field: login}, default=None, require_verified=False)
if user:
break

if not user:
raise UserNotFound()

user = serializer.get_user()
signer = ResetPasswordSigner({
'user_id': user.pk,
}, request=request)
Expand Down
7 changes: 7 additions & 0 deletions rest_registration/settings_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ def __new__(cls, name, *, default=None, help=None, import_string=False):
Field('LOGIN_RETRIEVE_TOKEN'),
]
RESET_PASSWORD_SETTINGS_FIELDS = [
Field(
'SEND_RESET_PASSWORD_LINK_SERIALIZER_CLASS',
default='rest_registration.api.serializers.DefaultSendResetPasswordLinkSerializer', # noqa: E501,
import_string=True,
help=dedent("""\
""")
),
Field('RESET_PASSWORD_VERIFICATION_ENABLED', default=True),
Field(
'RESET_PASSWORD_VERIFICATION_PERIOD',
Expand Down
10 changes: 6 additions & 4 deletions rest_registration/utils/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ def get_object_or_404(queryset, *filter_args, **filter_kwargs):
raise Http404


def get_user_login_fields():
user_class = get_user_model()
return get_user_setting('LOGIN_FIELDS') or [user_class.USERNAME_FIELD]


def get_user_setting(name):
setting_name = 'USER_{name}'.format(name=name)
user_class = get_user_model()
Expand All @@ -37,10 +42,7 @@ def get_user_setting(name):

def authenticate_by_login_and_password_or_none(login, password):
user = None
user_class = get_user_model()
login_fields = (registration_settings.USER_LOGIN_FIELDS or
getattr(user_class, 'LOGIN_FIELDS', None) or
[user_class.USERNAME_FIELD])
login_fields = get_user_login_fields()

for field_name in login_fields:
kwargs = {
Expand Down

0 comments on commit 3b9b981

Please sign in to comment.