From 71a3e36bf3701bdf78e7ad21aeb31bfbb87df03a Mon Sep 17 00:00:00 2001 From: Ruman Siddiqui Date: Fri, 18 Aug 2023 16:57:42 +0530 Subject: [PATCH] [ZBKBCK-346] change password and forgot password api has been optimised --- account/serializers.py | 31 ++++++++++----- account/utils.py | 22 +++++++++++ account/views.py | 89 ++++++++++++++++++++++++------------------ guardian/tasks.py | 9 ++++- 4 files changed, 103 insertions(+), 48 deletions(-) diff --git a/account/serializers.py b/account/serializers.py index 0caeb8c..e946d15 100644 --- a/account/serializers.py +++ b/account/serializers.py @@ -104,10 +104,12 @@ class ResetPasswordSerializer(serializers.Serializer): return user_opt_details return '' + class ChangePasswordSerializer(serializers.Serializer): """Update Password after verification""" - current_password = serializers.CharField(max_length=100) + current_password = serializers.CharField(max_length=100, required=True) new_password = serializers.CharField(required=True) + class Meta(object): """Meta info""" model = User @@ -118,25 +120,36 @@ class ChangePasswordSerializer(serializers.Serializer): if self.context.password not in ('', None) and user.check_password(value): return value raise serializers.ValidationError(ERROR_CODE['2015']) + def create(self, validated_data): + """ + + """ new_password = validated_data.pop('new_password') current_password = validated_data.pop('current_password') - """Check new password is different from current password""" + # Check new password is different from current password if new_password == current_password: raise serializers.ValidationError({"details": ERROR_CODE['2026']}) - user_details = User.objects.filter(email=self.context).last() - if user_details: - user_details.set_password(new_password) - user_details.save() - return {'password':new_password} - return '' + user_details = self.context + user_details.set_password(new_password) + user_details.save() + return {'password':new_password} class ForgotPasswordSerializer(serializers.Serializer): """Forget password serializer""" - email = serializers.EmailField() + email = serializers.EmailField(required=True) + def validate_email(self, value): + """ + validate email exist ot not + value: string + return none + """ + if not User.objects.get(email=value): + raise serializers.ValidationError({'details': ERROR_CODE['2004']}) + return value class AdminLoginSerializer(serializers.ModelSerializer): """admin login serializer""" diff --git a/account/utils.py b/account/utils.py index e016940..3f8c687 100644 --- a/account/utils.py +++ b/account/utils.py @@ -129,6 +129,28 @@ def send_otp_email(recipient_email, otp): ) return otp + +@shared_task() +def send_all_email(template_name, email, otp): + """ + Send all type of email by passing template name + template_name: string + email: string + otp: string + """ + from_email = settings.EMAIL_FROM_ADDRESS + recipient_list = [email] + send_templated_mail( + template_name=template_name, + from_email=from_email, + recipient_list=recipient_list, + context={ + 'verification_code': otp + } + ) + + return otp + @shared_task def user_device_details(user, device_id): """ diff --git a/account/views.py b/account/views.py index c6fbb12..b36c1f7 100644 --- a/account/views.py +++ b/account/views.py @@ -39,7 +39,7 @@ from base.messages import ERROR_CODE, SUCCESS_CODE from base.constants import NUMBER, ZOD, JUN, GRD, USER_TYPE_FLAG from guardian.tasks import generate_otp from account.utils import (send_otp_email, send_support_email, custom_response, custom_error_response, - generate_code, OTP_EXPIRY, user_device_details) + generate_code, OTP_EXPIRY, user_device_details, send_all_email) from junior.serializers import JuniorProfileSerializer from guardian.serializers import GuardianProfileSerializer @@ -193,15 +193,30 @@ class UpdateProfileImage(views.APIView): return custom_error_response(ERROR_CODE['2036'],response_status=status.HTTP_400_BAD_REQUEST) class ChangePasswordAPIView(views.APIView): - """change password""" + """ + change password" + """ serializer_class = ChangePasswordSerializer permission_classes = [IsAuthenticated] + def post(self, request): - serializer = ChangePasswordSerializer(context=request.user, data=request.data) + """ + POST request to change current login user password + """ + serializer = ChangePasswordSerializer( + context=request.user, + data=request.data + ) if serializer.is_valid(): serializer.save() - return custom_response(SUCCESS_CODE['3007'], response_status=status.HTTP_200_OK) - return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) + return custom_response( + SUCCESS_CODE['3007'], + response_status=status.HTTP_200_OK + ) + return custom_error_response( + serializer.errors, + response_status=status.HTTP_400_BAD_REQUEST + ) class ResetPasswordAPIView(views.APIView): """Reset password""" @@ -213,40 +228,40 @@ class ResetPasswordAPIView(views.APIView): return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) class ForgotPasswordAPIView(views.APIView): - """Forgot password""" + """ + Forgot password + """ + serializer_class = ForgotPasswordSerializer def post(self, request): - serializer = ForgotPasswordSerializer(data=request.data) - if serializer.is_valid(): - email = serializer.validated_data['email'] - try: - User.objects.get(email=email) - except User.DoesNotExist: - return custom_error_response(ERROR_CODE['2004'], response_status=status.HTTP_404_NOT_FOUND) - verification_code = generate_otp() - # Send the verification code to the user's email - from_email = settings.EMAIL_FROM_ADDRESS - recipient_list = [email] - send_templated_mail( - template_name='email_reset_verification.email', - from_email=from_email, - recipient_list=recipient_list, - context={ - 'verification_code': verification_code - } - ) - expiry = OTP_EXPIRY - user_data, created = UserEmailOtp.objects.get_or_create(email=email) - if created: - user_data.expired_at = expiry - user_data.save() - if user_data: - user_data.otp = verification_code - user_data.expired_at = expiry - user_data.save() - return custom_response(SUCCESS_CODE['3015'], - response_status=status.HTTP_200_OK) - return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) + """ + Post method to validate serializer + """ + serializer = self.serializer_class(data=request.data) + serializer.is_valid(raise_exception=True) + email = serializer.validated_data['email'] + # generate otp + verification_code = generate_otp() + # Send the verification code to the user's email + send_all_email.delay( + 'email_reset_verification.email', email, verification_code + ) + expiry = OTP_EXPIRY + user_data, created = UserEmailOtp.objects.get_or_create( + email=email + ) + if created: + user_data.expired_at = expiry + user_data.save() + if user_data: + user_data.otp = verification_code + user_data.expired_at = expiry + user_data.save() + return custom_response( + SUCCESS_CODE['3015'], + response_status=status.HTTP_200_OK + ) + class SendPhoneOtp(viewsets.ModelViewSet): """Send otp on phone""" diff --git a/guardian/tasks.py b/guardian/tasks.py index 9cf39b3..f40d232 100644 --- a/guardian/tasks.py +++ b/guardian/tasks.py @@ -1,7 +1,12 @@ """task files""" -"""Django import""" + +# Django import import secrets + + def generate_otp(): - """generate random otp""" + """ + generate random otp + """ digits = "0123456789" return "".join(secrets.choice(digits) for _ in range(6))