mirror of
https://github.com/Tivix/django-rest-auth.git
synced 2024-11-25 10:33:45 +03:00
password reset and password change refactoring
This commit is contained in:
parent
85688940df
commit
a7be2d178b
|
@ -1,5 +1,12 @@
|
|||
from django.contrib.auth import get_user_model
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.forms import PasswordResetForm, SetPasswordForm
|
||||
try:
|
||||
from django.utils.http import urlsafe_base64_decode as uid_decoder
|
||||
except:
|
||||
# make compatible with django 1.5
|
||||
from django.utils.http import base36_to_int as uid_decoder
|
||||
from django.contrib.auth.tokens import default_token_generator
|
||||
|
||||
from rest_framework import serializers
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
@ -43,20 +50,6 @@ class UserDetailsSerializer(serializers.ModelSerializer):
|
|||
read_only_fields = ('id', 'last_login', 'is_active', 'date_joined')
|
||||
|
||||
|
||||
class SetPasswordSerializer(serializers.Serializer):
|
||||
|
||||
"""
|
||||
Serializer for changing Django User password.
|
||||
"""
|
||||
|
||||
new_password1 = serializers.CharField(max_length=128)
|
||||
new_password2 = serializers.CharField(max_length=128)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.user = kwargs.pop('user', None)
|
||||
return super(SetPasswordSerializer, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class PasswordResetSerializer(serializers.Serializer):
|
||||
|
||||
"""
|
||||
|
@ -64,3 +57,86 @@ class PasswordResetSerializer(serializers.Serializer):
|
|||
"""
|
||||
|
||||
email = serializers.EmailField()
|
||||
|
||||
password_reset_form_class = PasswordResetForm
|
||||
|
||||
def validate_email(self, attrs, source):
|
||||
# Create PasswordResetForm with the serializer
|
||||
self.reset_form = self.password_reset_form_class(data=attrs)
|
||||
if not self.reset_form.is_valid():
|
||||
raise serializers.ValidationError('Error')
|
||||
return attrs
|
||||
|
||||
def save(self):
|
||||
request = self.context.get('request')
|
||||
# Set some values to trigger the send_email method.
|
||||
opts = {
|
||||
'use_https': request.is_secure(),
|
||||
'from_email': getattr(settings, 'DEFAULT_FROM_EMAIL'),
|
||||
'request': request,
|
||||
}
|
||||
self.reset_form.save(**opts)
|
||||
|
||||
|
||||
class PasswordResetConfirmSerializer(serializers.Serializer):
|
||||
|
||||
"""
|
||||
Serializer for requesting a password reset e-mail.
|
||||
"""
|
||||
|
||||
new_password1 = serializers.CharField(max_length=128)
|
||||
new_password2 = serializers.CharField(max_length=128)
|
||||
|
||||
uid = serializers.CharField(required=True)
|
||||
token = serializers.CharField(required=True)
|
||||
|
||||
set_password_form_class = SetPasswordForm
|
||||
|
||||
def custom_validation(self, attrs):
|
||||
pass
|
||||
|
||||
def validate(self, attrs):
|
||||
self._errors = {}
|
||||
# Get the UserModel
|
||||
UserModel = get_user_model()
|
||||
# Decode the uidb64 to uid to get User object
|
||||
try:
|
||||
uid = uid_decoder(attrs['uid'])
|
||||
self.user = UserModel._default_manager.get(pk=uid)
|
||||
except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist):
|
||||
self._errors['uid'] = ['Invalid value']
|
||||
|
||||
self.custom_validation(attrs)
|
||||
|
||||
# Construct SetPasswordForm instance
|
||||
self.set_password_form = self.set_password_form_class(user=self.user,
|
||||
data=attrs)
|
||||
if not self.set_password_form.is_valid():
|
||||
self._errors['token'] = ['Invalid value']
|
||||
|
||||
if not default_token_generator.check_token(self.user, attrs['token']):
|
||||
self._errors['token'] = ['Invalid value']
|
||||
|
||||
def save(self):
|
||||
self.set_password_form.save()
|
||||
|
||||
|
||||
class PasswordChangeSerializer(serializers.Serializer):
|
||||
|
||||
new_password1 = serializers.CharField(max_length=128)
|
||||
new_password2 = serializers.CharField(max_length=128)
|
||||
|
||||
set_password_form_class = SetPasswordForm
|
||||
|
||||
def validate(self, attrs):
|
||||
request = self.context.get('request')
|
||||
self.set_password_form = self.set_password_form_class(user=request.user,
|
||||
data=attrs)
|
||||
|
||||
if not self.set_password_form.is_valid():
|
||||
self._errors = self.set_password_form.errors
|
||||
return None
|
||||
return attrs
|
||||
|
||||
def save(self):
|
||||
self.set_password_form.save()
|
||||
|
|
|
@ -253,16 +253,17 @@ class APITestCase1(TestCase, BaseAPITestCase):
|
|||
# call password reset
|
||||
mail_count = len(mail.outbox)
|
||||
payload = {'email': self.EMAIL}
|
||||
self.post(self.password_reset_url, data=payload)
|
||||
self.post(self.password_reset_url, data=payload, status_code=200)
|
||||
self.assertEqual(len(mail.outbox), mail_count + 1)
|
||||
|
||||
url_kwargs = self._generate_uid_and_token(user)
|
||||
|
||||
data = {
|
||||
'new_password1': self.NEW_PASS,
|
||||
'new_password2': self.NEW_PASS
|
||||
'new_password2': self.NEW_PASS,
|
||||
'uid': url_kwargs['uid'],
|
||||
'token': url_kwargs['token']
|
||||
}
|
||||
url = reverse('rest_password_reset_confirm', kwargs=url_kwargs)
|
||||
url = reverse('rest_password_reset_confirm')
|
||||
self.post(url, data=data, status_code=200)
|
||||
|
||||
payload = {
|
||||
|
|
|
@ -10,7 +10,7 @@ urlpatterns = patterns('rest_auth.views',
|
|||
# URLs that do not require a session or valid token
|
||||
url(r'^password/reset/$', PasswordReset.as_view(),
|
||||
name='rest_password_reset'),
|
||||
url(r'^password/reset/confirm/(?P<uid>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
|
||||
url(r'^password/reset/confirm/$',
|
||||
PasswordResetConfirm.as_view(
|
||||
), name='rest_password_reset_confirm'),
|
||||
url(r'^login/$', Login.as_view(), name='rest_login'),
|
||||
|
|
|
@ -1,11 +1,4 @@
|
|||
from django.contrib.auth.forms import PasswordResetForm, SetPasswordForm
|
||||
from django.contrib.auth import login, logout, get_user_model
|
||||
from django.contrib.auth.tokens import default_token_generator
|
||||
try:
|
||||
from django.utils.http import urlsafe_base64_decode as uid_decoder
|
||||
except:
|
||||
# make compatible with django 1.5
|
||||
from django.utils.http import base36_to_int as uid_decoder
|
||||
from django.contrib.auth import login, logout
|
||||
from django.conf import settings
|
||||
|
||||
from rest_framework import status
|
||||
|
@ -19,7 +12,8 @@ from rest_framework.authtoken.models import Token
|
|||
from rest_framework.generics import RetrieveUpdateAPIView
|
||||
|
||||
from rest_auth.serializers import (TokenSerializer, UserDetailsSerializer,
|
||||
LoginSerializer, SetPasswordSerializer, PasswordResetSerializer)
|
||||
LoginSerializer, PasswordResetSerializer, PasswordResetConfirmSerializer,
|
||||
PasswordChangeSerializer)
|
||||
|
||||
|
||||
class LoggedInRESTAPIView(APIView):
|
||||
|
@ -122,38 +116,18 @@ class PasswordReset(LoggedOutRESTAPIView, GenericAPIView):
|
|||
"""
|
||||
|
||||
serializer_class = PasswordResetSerializer
|
||||
password_reset_form_class = PasswordResetForm
|
||||
|
||||
def post(self, request):
|
||||
def post(self, request, *args, **kwargs):
|
||||
# Create a serializer with request.DATA
|
||||
serializer = self.serializer_class(data=request.DATA)
|
||||
serializer = self.get_serializer(data=request.DATA)
|
||||
|
||||
if serializer.is_valid():
|
||||
# Create PasswordResetForm with the serializer
|
||||
reset_form = self.password_reset_form_class(data=serializer.data)
|
||||
|
||||
if reset_form.is_valid():
|
||||
# Sett some values to trigger the send_email method.
|
||||
opts = {
|
||||
'use_https': request.is_secure(),
|
||||
'from_email': getattr(settings, 'DEFAULT_FROM_EMAIL'),
|
||||
'request': request,
|
||||
}
|
||||
|
||||
reset_form.save(**opts)
|
||||
|
||||
# Return the success message with OK HTTP status
|
||||
return Response(
|
||||
{"success": "Password reset e-mail has been sent."},
|
||||
status=status.HTTP_200_OK)
|
||||
|
||||
else:
|
||||
return Response(reset_form._errors,
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
else:
|
||||
if not serializer.is_valid():
|
||||
return Response(serializer.errors,
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
serializer.save()
|
||||
# Return the success message with OK HTTP status
|
||||
return Response({"success": "Password reset e-mail has been sent."},
|
||||
status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
class PasswordResetConfirm(LoggedOutRESTAPIView, GenericAPIView):
|
||||
|
@ -166,49 +140,15 @@ class PasswordResetConfirm(LoggedOutRESTAPIView, GenericAPIView):
|
|||
Returns the success/fail message.
|
||||
"""
|
||||
|
||||
serializer_class = SetPasswordSerializer
|
||||
serializer_class = PasswordResetConfirmSerializer
|
||||
|
||||
def post(self, request, uid=None, token=None):
|
||||
# Get the UserModel
|
||||
UserModel = get_user_model()
|
||||
|
||||
# Decode the uidb64 to uid to get User object
|
||||
try:
|
||||
uid = uid_decoder(uid)
|
||||
user = UserModel._default_manager.get(pk=uid)
|
||||
except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist):
|
||||
user = None
|
||||
|
||||
# If we get the User object
|
||||
if user:
|
||||
serializer = self.serializer_class(data=request.DATA, user=user)
|
||||
|
||||
if serializer.is_valid():
|
||||
# Construct SetPasswordForm instance
|
||||
form = SetPasswordForm(user=user, data=serializer.data)
|
||||
|
||||
if form.is_valid():
|
||||
if default_token_generator.check_token(user, token):
|
||||
form.save()
|
||||
|
||||
# Return the success message with OK HTTP status
|
||||
return Response(
|
||||
{"success":
|
||||
"Password has been reset with the new password."},
|
||||
status=status.HTTP_200_OK)
|
||||
else:
|
||||
return Response(
|
||||
{"error": "Invalid password reset token."},
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
else:
|
||||
return Response(form._errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
else:
|
||||
return Response(serializer.errors,
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
else:
|
||||
return Response({"errors": "Couldn\'t find the user from uid."}, status=status.HTTP_400_BAD_REQUEST)
|
||||
def post(self, request):
|
||||
serializer = self.get_serializer(data=request.DATA)
|
||||
if not serializer.is_valid():
|
||||
return Response(serializer.errors,
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
serializer.save()
|
||||
return Response({"success": "Password has been reset with the new password."})
|
||||
|
||||
|
||||
class PasswordChange(LoggedInRESTAPIView, GenericAPIView):
|
||||
|
@ -220,29 +160,12 @@ class PasswordChange(LoggedInRESTAPIView, GenericAPIView):
|
|||
Returns the success/fail message.
|
||||
"""
|
||||
|
||||
serializer_class = SetPasswordSerializer
|
||||
serializer_class = PasswordChangeSerializer
|
||||
|
||||
def post(self, request):
|
||||
# Create a serializer with request.DATA
|
||||
serializer = self.serializer_class(data=request.DATA)
|
||||
|
||||
if serializer.is_valid():
|
||||
# Construct the SetPasswordForm instance
|
||||
form = SetPasswordForm(user=request.user, data=serializer.data)
|
||||
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
|
||||
# Return the success message with OK HTTP status
|
||||
return Response({"success": "New password has been saved."},
|
||||
status=status.HTTP_200_OK)
|
||||
|
||||
else:
|
||||
return Response(form._errors,
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
else:
|
||||
serializer = self.get_serializer(data=request.DATA)
|
||||
if not serializer.is_valid():
|
||||
return Response(serializer.errors,
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
status=status.HTTP_400_BAD_REQUEST)
|
||||
serializer.save()
|
||||
return Response({"success": "New password has been saved."})
|
||||
|
|
Loading…
Reference in New Issue
Block a user