Skip to content

Commit

Permalink
Merge pull request #14 from andela/ft-reset-password-159054010
Browse files Browse the repository at this point in the history
#159054010 Password Reset Feature
  • Loading branch information
Jackson Onyango committed Aug 3, 2018
2 parents 4055b50 + 6e7632a commit 6dfd1e3
Show file tree
Hide file tree
Showing 13 changed files with 637 additions and 39 deletions.
87 changes: 79 additions & 8 deletions authors/apps/authentication/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,22 @@
from django.core.validators import RegexValidator
from rest_framework.validators import UniqueValidator

from django.contrib.auth.tokens import default_token_generator


from authors.apps.profiles.serializers import ProfileSerializer
from .models import User


class RegistrationSerializer(serializers.ModelSerializer):
"""Serializers registration requests and creates a new user."""

password = serializers.CharField(max_length=128, write_only=True, allow_null=True, allow_blank=True)
username = serializers.CharField(max_length=128, allow_null=True, allow_blank=True)
password = serializers.CharField(
max_length=128, write_only=True, allow_null=True, allow_blank=True)
username = serializers.CharField(
max_length=128, allow_null=True, allow_blank=True)
email = serializers.EmailField(max_length=128,
allow_null=True, allow_blank=True)
allow_null=True, allow_blank=True)
# Ensure passwords are at least 8 characters long, no longer than 128
# characters, and can not be read by the client.

Expand All @@ -25,19 +30,21 @@ def validate_password(self, data):
if password == '':
raise serializers.ValidationError('Password is required.')
elif len(password) < 8:
raise serializers.ValidationError('Password should be atleats 8 characters.')
# Validate the password has atleast one number
raise serializers.ValidationError(
'Password should be atleats 8 characters.')
# Validate the password has atleast one number
elif not re.match(r"^(?=.*[0-9]).*", password):
raise serializers.ValidationError(
'A password must contain atleast one number.'
)
# Validate password has an uppercase
elif not re.match(r"^(?=.*[A-Z])(?=.*[a-z])(?!.*\s).*", password):
raise serializers.ValidationError("Password should have an "
"uppercase")
"uppercase")
# Validate the password has a special character
elif re.match(r"^[a-zA-Z0-9_]*$", password):
raise serializers.ValidationError("Password should have a special character.")
raise serializers.ValidationError(
"Password should have a special character.")

return data

Expand Down Expand Up @@ -171,7 +178,6 @@ class Meta:
'image', 'token'
)


# The `read_only_fields` option is an alternative for explicitly
# specifying the field with `read_only=True` like we did for password
# above. The reason we want to use `read_only_fields` here is because
Expand All @@ -198,10 +204,18 @@ def update(self, instance, validated_data):
setattr(instance, key, value)

if password is not None:
print("password only")
# `.set_password()` is the method mentioned above. It handles all
# of the security stuff that we shouldn't be concerned with.
instance.set_password(password)

else:
print("others")
for (key, value) in validated_data.items():
# For the keys remaining in `validated_data`, we will set them on
# the current `User` instance one at a time.
setattr(instance, key, value)

# Finally, after everything has been updated, we must explicitly save
# the model. It's worth pointing out that `.set_password()` does not
# save the model.
Expand All @@ -214,6 +228,63 @@ def update(self, instance, validated_data):

return instance


class EmailSerializer(serializers.Serializer):
# Ensures that the email is not more than 255 characters long
email = serializers.EmailField(max_length=255)
token = serializers.CharField(max_length=225, required=False)
username = serializers.CharField(
max_length=225, required=False, read_only=True)
# Validate that the email

def validate(self, data):
user = User.objects.filter(email=data.get('email', None)).first()

# Check that the user exists
if user is None:
raise serializers.ValidationError(
"User with this email doesn't exist"
)
token = default_token_generator.make_token(user)
return {
"email": data.get("email"),
"token": token,
'username': user.username,
}


class ResetPasswordSerializer(serializers.Serializer):

# Ensures that the email is not more than 128 characters long
# Ensures that the user cannot read the password
token = serializers.CharField(max_length=225)
email = serializers.CharField(max_length=225)
new_password = serializers.CharField(
max_length=128,
min_length=8,
write_only=True
)

def create(self, validated_data):
user = User.objects.get(email=validated_data.get('email', None))
return user

def validate(self, data):
user = User.objects.filter(email=data.get('email', None)).first()
is_valid_token = default_token_generator.check_token(
user, data.get('token'))

if is_valid_token is not True:
raise serializers.ValidationError(
"Invalid token. Please generate another reset password email"
)

user.set_password(data.get('new_password', None))
user.save()

return data


class SocialSerializer(serializers.Serializer):
access_token = serializers.CharField(max_length=255, required=True)
provider = serializers.CharField(max_length=255, required=True)
Loading

0 comments on commit 6dfd1e3

Please sign in to comment.