diff --git a/zod_bank/account/serializers.py b/zod_bank/account/serializers.py index 03b1012..94c774f 100644 --- a/zod_bank/account/serializers.py +++ b/zod_bank/account/serializers.py @@ -13,6 +13,64 @@ from rest_framework.decorators import action from django.contrib.auth import authenticate, login from rest_framework_simplejwt.tokens import RefreshToken +class ResetPasswordSerializer(serializers.Serializer): + """Reset Password after verification""" + verification_code = serializers.CharField(max_length=10) + password = serializers.CharField(required=True) + class Meta(object): + """Meta info""" + model = User + + def create(self, validated_data): + verification_code = validated_data.pop('verification_code') + password = validated_data.pop('password') + print("verification_code===>",verification_code) + print("password===>", password) + user_opt_details = UserEmailOtp.objects.filter(otp=verification_code, is_verified=True).last() + print("user_opt_details===>",user_opt_details) + if user_opt_details: + print("qqqqqqqqqq") + user_details = User.objects.filter(email=user_opt_details.email).last() + if user_details: + print("333333333==>",user_details.password) + user_details.set_password(password) + user_details.save() + return {'password':password} + return user_opt_details + return '' + +class ChangePasswordSerializer(serializers.Serializer): + """Update Password after verification""" + current_password = serializers.CharField(max_length=100) + new_password = serializers.CharField(required=True) + class Meta(object): + """Meta info""" + model = User + + def validate_current_password(self, value): + user = self.context + if self.context.password not in ('', None): + if user.check_password(value): + return value + raise serializers.ValidationError({"error":"Invalid Current password"}) + def create(self, validated_data): + new_password = validated_data.pop('new_password') + user_details = User.objects.filter(email=self.context).last() + print("user_details==>", user_details) + if user_details: + print("333333333==>",user_details.password) + user_details.set_password(new_password) + user_details.save() + return {'password':new_password} + return user_details + return '' + + + +class ForgotPasswordSerializer(serializers.Serializer): + """Forget password serializer""" + email = serializers.EmailField() + class SuperUserSerializer(serializers.ModelSerializer): user_type = serializers.SerializerMethodField('get_user_type') diff --git a/zod_bank/account/templates/templated_email/email_base.email b/zod_bank/account/templates/templated_email/email_base.email new file mode 100644 index 0000000..5721e28 --- /dev/null +++ b/zod_bank/account/templates/templated_email/email_base.email @@ -0,0 +1,54 @@ + +{% block subject %}DinDin{% endblock %} +{% load static %} + +{% block html %} + + + + + Zod Bank | OTP + + + + + + + + + + +
+ + + + + {% block plain %} + {% endblock %} + + + +
+
+

-

+

Cheers!

+

Zod Bank Team

+
+
+ + + +{% endblock %} diff --git a/zod_bank/account/templates/templated_email/email_otp_verification.email b/zod_bank/account/templates/templated_email/email_otp_verification.email new file mode 100644 index 0000000..8b3c693 --- /dev/null +++ b/zod_bank/account/templates/templated_email/email_otp_verification.email @@ -0,0 +1,23 @@ +{% extends "templated_email/email_base.email" %} + +{% block subject %} + OTP Verification +{% endblock %} + +{% block plain %} + + +

+ Hi User, +

+ + + + +

+ You are receiving this email for email verification. Please use {{ otp }} as the verification code for your email address & username. + +

+ + +{% endblock %} diff --git a/zod_bank/account/templates/templated_email/email_reset_verification.email b/zod_bank/account/templates/templated_email/email_reset_verification.email new file mode 100644 index 0000000..e2f8ebf --- /dev/null +++ b/zod_bank/account/templates/templated_email/email_reset_verification.email @@ -0,0 +1,23 @@ +{% extends "templated_email/email_base.email" %} + +{% block subject %} + Password Reset Verification Code +{% endblock %} + +{% block plain %} + + +

+ Hi User, +

+ + + + +

+ You are receiving this email for reset password verification. Please use {{ verification_code }} as the verification code. + +

+ + +{% endblock %} diff --git a/zod_bank/account/urls.py b/zod_bank/account/urls.py index 1350cea..3c1fc2c 100644 --- a/zod_bank/account/urls.py +++ b/zod_bank/account/urls.py @@ -4,7 +4,8 @@ from django.urls import path, include from rest_framework.decorators import api_view """Third party import""" from rest_framework import routers -from .views import UserLogin, SendPhoneOtp, UserPhoneVerification, UserEmailVerification, ReSendEmailOtp +from .views import (UserLogin, SendPhoneOtp, UserPhoneVerification, UserEmailVerification, ReSendEmailOtp, + ForgotPasswordAPIView, ResetPasswordAPIView, ChangePasswordAPIView) """Router""" router = routers.SimpleRouter() @@ -15,6 +16,10 @@ router.register('send-phone-otp', SendPhoneOtp, basename='send-phone-otp') router.register('user-phone-verification', UserPhoneVerification, basename='user-phone-verification') router.register('user-email-verification', UserEmailVerification, basename='user-email-verification') router.register('resend-email-otp', ReSendEmailOtp, basename='resend-email-otp') + urlpatterns = [ path('api/v1/', include(router.urls)), + path('api/v1/forgot-password/', ForgotPasswordAPIView.as_view()), + path('api/v1/reset-password/', ResetPasswordAPIView.as_view()), + path('api/v1/change-password/', ChangePasswordAPIView.as_view()) ] diff --git a/zod_bank/account/utils.py b/zod_bank/account/utils.py index c6ffe7f..2d86106 100644 --- a/zod_bank/account/utils.py +++ b/zod_bank/account/utils.py @@ -3,12 +3,19 @@ from django.conf import settings import random from rest_framework import viewsets, status from rest_framework.response import Response + +from templated_email import send_templated_mail def send_otp_email(recipient_email, otp): - subject = 'One-Time Password' - message = f'Your OTP is: {otp}' - from_email = settings.DEFAULT_FROM_EMAIL + from_email = settings.EMAIL_HOST_USER recipient_list = [recipient_email] - send_mail(subject, message, from_email, recipient_list) + send_templated_mail( + template_name='email_otp_verification.email', + from_email=from_email, + recipient_list=recipient_list, + context={ + 'otp': otp + } + ) return otp def custom_response(detail, data=None, response_status=status.HTTP_200_OK): diff --git a/zod_bank/account/views.py b/zod_bank/account/views.py index 352b834..82039b9 100644 --- a/zod_bank/account/views.py +++ b/zod_bank/account/views.py @@ -1,20 +1,75 @@ -from rest_framework import viewsets, status +from rest_framework import viewsets, status, views from rest_framework.decorators import action -from rest_framework.response import Response +import random from django.contrib.auth import authenticate, login from guardian.models import Guardian from junior.models import Junior from account.models import UserProfile, UserPhoneOtp, UserEmailOtp from django.contrib.auth.models import User -from .serializers import SuperUserSerializer, GuardianSerializer, JuniorSerializer, EmailVerificationSerializer +from .serializers import (SuperUserSerializer, GuardianSerializer, JuniorSerializer, EmailVerificationSerializer, + ForgotPasswordSerializer, ResetPasswordSerializer, ChangePasswordSerializer) from django.views.decorators.csrf import csrf_exempt from rest_framework_simplejwt.serializers import TokenObtainPairSerializer from rest_framework_simplejwt.views import TokenObtainPairView from rest_framework_simplejwt.tokens import RefreshToken from base.messages import ERROR_CODE, SUCCESS_CODE from guardian.tasks import generate_otp - +from django.conf import settings from account.utils import custom_response, custom_error_response +from django.core.mail import EmailMessage +from django.core.mail import send_mail +from rest_framework.response import Response +from rest_framework.permissions import IsAuthenticated +from templated_email import send_templated_mail +import secrets + + +class ChangePasswordAPIView(views.APIView): + permission_classes = [IsAuthenticated] + def post(self, request): + print("request.data====>",request.data) + print("request.user====>", request.user) + serializer = ChangePasswordSerializer(context=request.user, data=request.data) + if serializer.is_valid(): + serializer.save() + return custom_response(SUCCESS_CODE['3006'], response_status=status.HTTP_200_OK) + return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) + +class ResetPasswordAPIView(views.APIView): + def post(self, request): + print("request.data====>",request.data) + serializer = ResetPasswordSerializer(data=request.data) + if serializer.is_valid(): + serializer.save() + return custom_response(SUCCESS_CODE['3006'], response_status=status.HTTP_200_OK) + return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) + +class ForgotPasswordAPIView(views.APIView): + 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 = ''.join([str(random.randrange(9)) for _ in range(6)]) + # Send the verification code to the user's email + from_email = settings.EMAIL_HOST_USER + 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 + } + ) + UserEmailOtp.objects.create(email=email, otp=verification_code) + return custom_response(SUCCESS_CODE['3015'], {'verification_code': verification_code}, + response_status=status.HTTP_200_OK) + return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) + class SendPhoneOtp(viewsets.ModelViewSet): """Send otp on phone""" def create(self, request, *args, **kwargs): @@ -58,7 +113,7 @@ class UserLogin(viewsets.ViewSet): serializer = JuniorSerializer(junior_data) if user.is_superuser: serializer = SuperUserSerializer(user) - return custom_response(None, serializer.data, response_status=status.HTTP_200_OK) + return custom_response(SUCCESS_CODE['3003'], serializer.data, response_status=status.HTTP_200_OK) else: return custom_error_response(ERROR_CODE["2002"], response_status=status.HTTP_401_UNAUTHORIZED) except Exception as e: diff --git a/zod_bank/base/messages.py b/zod_bank/base/messages.py index 718d6be..39f0282 100644 --- a/zod_bank/base/messages.py +++ b/zod_bank/base/messages.py @@ -27,7 +27,7 @@ ERROR_CODE = { "2001": "Your account has not been verified. Please check your email and verify it.", "2002": "Invalid login credentials.", "2003": "An account already exists with this email address.", - "2004": "User doesn't exist.", + "2004": "User not found.", "2005": "Your account has been activated.", "2006": "Your account is not activated.", "2007": "Your account already activated.", @@ -55,7 +55,7 @@ SUCCESS_CODE = { # Success code for Thank you "3002": "Thank you for contacting us! Our Consumer Experience Team will reach out to you shortly.", # Success code for account activation - "3003": "Your account has been activated.", + "3003": "Log in successfully", # Success code for password reset "3004": "Password reset link has been sent to your email address", # Success code for link verified @@ -73,7 +73,8 @@ SUCCESS_CODE = { "3011": "Email OTP Verified successfully", "3012": "Phone OTP Verified successfully", "3013": "Valid Guardian code", - "3014": "Password has been updated successfully." + "3014": "Password has been updated successfully.", + "3015": "Verification code sent on your email." } STATUS_CODE_ERROR = { diff --git a/zod_bank/guardian/urls.py b/zod_bank/guardian/urls.py index 64aa80f..0e3f898 100644 --- a/zod_bank/guardian/urls.py +++ b/zod_bank/guardian/urls.py @@ -11,7 +11,7 @@ router = routers.SimpleRouter() """API End points with router""" router.register('sign-up', SignupViewset, basename='sign-up') -router.register('update-guardian-profile', UpdateGuardianProfile, basename='update-guardian-profile') +router.register('complete-guardian-profile', UpdateGuardianProfile, basename='update-guardian-profile') urlpatterns = [ path('api/v1/', include(router.urls)), ] diff --git a/zod_bank/guardian/views.py b/zod_bank/guardian/views.py index f43e4c8..2b40702 100644 --- a/zod_bank/guardian/views.py +++ b/zod_bank/guardian/views.py @@ -17,6 +17,7 @@ from .tasks import generate_otp from account.utils import send_otp_email from account.utils import custom_response, custom_error_response from base.messages import ERROR_CODE, SUCCESS_CODE + class SignupViewset(viewsets.ModelViewSet): serializer_class = UserSerializer @@ -26,7 +27,7 @@ class SignupViewset(viewsets.ModelViewSet): serializer.save() otp = generate_otp() UserEmailOtp.objects.create(email=request.data['email'], otp=otp) - # send_otp_email(request.data['email'], otp) + send_otp_email(request.data['email'], otp) return custom_response(SUCCESS_CODE['3001'], {"email_otp": otp}, response_status=status.HTTP_200_OK) return custom_error_response(serializer.errors, response_status=status.HTTP_400_BAD_REQUEST) diff --git a/zod_bank/junior/urls.py b/zod_bank/junior/urls.py index cce385d..27a312e 100644 --- a/zod_bank/junior/urls.py +++ b/zod_bank/junior/urls.py @@ -10,7 +10,7 @@ from rest_framework import routers router = routers.SimpleRouter() """API End points with router""" -router.register('profile-update', UpdateJuniorProfile, basename='profile-update') +router.register('complete-junior-profile', UpdateJuniorProfile, basename='profile-update') router.register('validate-guardian-code', ValidateGuardianCode, basename='validate-guardian-code') urlpatterns = [ path('api/v1/', include(router.urls)), diff --git a/zod_bank/zod_bank/settings.py b/zod_bank/zod_bank/settings.py index 0c8da76..9e47b30 100644 --- a/zod_bank/zod_bank/settings.py +++ b/zod_bank/zod_bank/settings.py @@ -171,6 +171,32 @@ CORS_ALLOW_HEADERS = ( # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.0/howto/static-files/ +# +# MAIL_MAILER='smtp' +# MAIL_HOST='smtp.gmail.com' +# MAIL_PORT=587 +# mail_username='infozodbank@gmail.com' +# MAIL_PASSWORD='ghwdmznwwslvchga' +# MAIL_ENCRYPTION='tls' +# mail_from_address='infozodbank@gmail.com' +# MAIL_FROM_NAME="${APP_NAME}" + +# MAIL_MAILER='smtp' +# MAIL_HOST='smtp.gmail.com' +# MAIL_PORT=587 +# mail_username='ankita.jain@kiwitech.com' +# MAIL_PASSWORD='jaijain0912@' +# MAIL_ENCRYPTION='tls' +# mail_from_address='infozodbank@gmail.com' +# MAIL_FROM_NAME="${APP_NAME}" + +# Email settings +EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' +EMAIL_HOST = 'smtp.gmail.com' +EMAIL_PORT = 587 +EMAIL_USE_TLS = True +EMAIL_HOST_USER = 'infozodbank@gmail.com' +EMAIL_HOST_PASSWORD = 'ghwdmznwwslvchga' # Replace with your Gmail email password or App password STATIC_URL = '/static/'