From 4f02cef0f9408b53d4b93717feaa9f8934e46ae6 Mon Sep 17 00:00:00 2001 From: Ruman Siddiqui Date: Thu, 10 Aug 2023 18:43:03 +0530 Subject: [PATCH 1/6] Optimised login api --- account/serializers.py | 15 ++++++++--- account/utils.py | 19 ++++++++++++- account/views.py | 61 ++++++++++++++++++++++++++++-------------- base/constants.py | 7 +++++ base/messages.py | 3 ++- 5 files changed, 79 insertions(+), 26 deletions(-) diff --git a/account/serializers.py b/account/serializers.py index 4065b5c..7ae9c43 100644 --- a/account/serializers.py +++ b/account/serializers.py @@ -215,10 +215,17 @@ class GuardianSerializer(serializers.ModelSerializer): def get_user_type(self, obj): """user type""" - email_verified = UserEmailOtp.objects.filter(email=obj.user.username).last() - if email_verified and email_verified.user_type is not None: - return email_verified.user_type - return str(NUMBER['two']) + if self.context.get('user_type', ''): + return self.context.get('user_type') + # remove the below code once user_type can be passed + # from everywhere from where this serializer is being called + else: + email_verified = UserEmailOtp.objects.filter( + email=obj.user.username + ).last() + if email_verified and email_verified.user_type is not None: + return email_verified.user_type + return str(NUMBER['two']) def get_auth(self, obj): """user email address""" diff --git a/account/utils.py b/account/utils.py index 357f2d1..d495163 100644 --- a/account/utils.py +++ b/account/utils.py @@ -1,4 +1,6 @@ """Account utils""" +from celery import shared_task + """Import django""" from django.conf import settings from rest_framework import viewsets, status @@ -20,7 +22,7 @@ from rest_framework import serializers # Import messages from base package""" from junior.models import Junior from guardian.models import Guardian -from account.models import UserDelete +from account.models import UserDelete, UserDeviceDetails from base.messages import ERROR_CODE from django.utils import timezone from base.constants import NUMBER @@ -107,6 +109,7 @@ def guardian_account_update(user_tb): for data in jun_data: data.guardian_code.remove(guardian_data.guardian_code) data.save() +@shared_task() def send_otp_email(recipient_email, otp): """Send otp on email with template""" from_email = settings.EMAIL_FROM_ADDRESS @@ -122,6 +125,20 @@ def send_otp_email(recipient_email, otp): ) return otp +@shared_task +def user_device_details(user, device_id): + """ + Used to store the device id of the user + user: user object + device_id: string + return + """ + device_details, created = UserDeviceDetails.objects.get_or_create(user=user) + if device_details: + device_details.device_id = device_id + device_details.save() + + def send_support_email(name, sender, subject, message): """Send otp on email with template""" to_email = [settings.EMAIL_FROM_ADDRESS] diff --git a/account/views.py b/account/views.py index 7979215..df273d6 100644 --- a/account/views.py +++ b/account/views.py @@ -1,4 +1,6 @@ """Account view """ +import threading + from notifications.utils import remove_fcm_token # django imports @@ -35,10 +37,10 @@ from .serializers import (SuperUserSerializer, GuardianSerializer, JuniorSeriali AdminLoginSerializer) from rest_framework_simplejwt.tokens import RefreshToken from base.messages import ERROR_CODE, SUCCESS_CODE -from base.constants import NUMBER, ZOD, JUN, GRD +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) + generate_code, OTP_EXPIRY, user_device_details) from junior.serializers import JuniorProfileSerializer from guardian.serializers import GuardianProfileSerializer @@ -276,29 +278,38 @@ class UserPhoneVerification(viewsets.ModelViewSet): return custom_error_response(ERROR_CODE["2008"], response_status=status.HTTP_400_BAD_REQUEST) - class UserLogin(viewsets.ViewSet): """User login""" @action(methods=['post'], detail=False) def login(self, request): username = request.data.get('username') password = request.data.get('password') + user_type = request.data.get('user_type') device_id = request.META.get('HTTP_DEVICE_ID') user = authenticate(request, username=username, password=password) try: if user is not None: login(request, user) - guardian_data = Guardian.objects.filter(user__username=username, is_verified=True).last() - if guardian_data: - serializer = GuardianSerializer(guardian_data).data - junior_data = Junior.objects.filter(auth__username=username, is_verified=True).last() - if junior_data: - serializer = JuniorSerializer(junior_data).data - device_details, created = UserDeviceDetails.objects.get_or_create(user=user) - if device_details: - device_details.device_id = device_id - device_details.save() + if user_type == USER_TYPE_FLAG["FIRST"]: + guardian_data = Guardian.objects.filter(user__username=username, is_verified=True).last() + if guardian_data: + serializer = GuardianSerializer( + guardian_data, context={'user_type': user_type} + ).data + elif user_type == USER_TYPE_FLAG["TWO"]: + junior_data = Junior.objects.filter(auth__username=username, is_verified=True).last() + if junior_data: + serializer = JuniorSerializer( + junior_data, context={'user_type': user_type} + ).data + else: + return custom_error_response( + ERROR_CODE["2069"], + response_status=status.HTTP_401_UNAUTHORIZED + ) + # storing device id in using thread so the time would be reduced + threading.Thread(target=user_device_details, args=(user, device_id)) return custom_response(SUCCESS_CODE['3003'], serializer, response_status=status.HTTP_200_OK) else: return custom_error_response(ERROR_CODE["2002"], response_status=status.HTTP_401_UNAUTHORIZED) @@ -308,9 +319,12 @@ class UserLogin(viewsets.ViewSet): refresh = RefreshToken.for_user(user) access_token = str(refresh.access_token) refresh_token = str(refresh) - data = {"auth_token":access_token, "refresh_token":refresh_token, "is_profile_complete": False, - "user_type": email_verified.user_type, - } + data = { + "auth_token":access_token, + "refresh_token":refresh_token, + "is_profile_complete": False, + "user_type": user_type, + } is_verified = False if email_verified: is_verified = email_verified.is_verified @@ -319,11 +333,18 @@ class UserLogin(viewsets.ViewSet): email_verified.otp = otp email_verified.save() data.update({"email_otp":otp}) - send_otp_email(username, otp) - return custom_response(ERROR_CODE['2024'], {"email_otp": otp, "is_email_verified": is_verified}, - response_status=status.HTTP_200_OK) + send_otp_email.delay(username, otp) + return custom_response( + ERROR_CODE['2024'], + {"email_otp": otp, "is_email_verified": is_verified}, + response_status=status.HTTP_200_OK + ) data.update({"is_email_verified": is_verified}) - return custom_response(SUCCESS_CODE['3003'], data, response_status=status.HTTP_200_OK) + return custom_response( + SUCCESS_CODE['3003'], + data, + response_status=status.HTTP_200_OK + ) @action(methods=['post'], detail=False) def admin_login(self, request): diff --git a/base/constants.py b/base/constants.py index 36079b9..b3b16d9 100644 --- a/base/constants.py +++ b/base/constants.py @@ -50,6 +50,13 @@ USER_TYPE = ( ('2', 'guardian'), ('3', 'superuser') ) + +USER_TYPE_FLAG = { + "FIRST" : "1", + "TWO" : "2", + "THREE": "3" +} + """gender""" GENDERS = ( ('1', 'Male'), diff --git a/base/messages.py b/base/messages.py index 87f5e9a..c7863c8 100644 --- a/base/messages.py +++ b/base/messages.py @@ -94,7 +94,8 @@ ERROR_CODE = { "2065": "Passwords do not match. Please try again.", "2066": "Task does not exist or not in expired state", "2067": "Action not allowed. User type missing.", - "2068": "No guardian associated with this junior" + "2068": "No guardian associated with this junior", + "2069": "Invalid user type" } """Success message code""" From d3b0be953e4aafe2ae9a489d6c4c0a2d7b0f6118 Mon Sep 17 00:00:00 2001 From: jain Date: Mon, 14 Aug 2023 15:16:16 +0530 Subject: [PATCH 2/6] login api with user type --- account/views.py | 14 ++++++++++++-- base/messages.py | 4 +++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/account/views.py b/account/views.py index cb2ee56..5b71b86 100644 --- a/account/views.py +++ b/account/views.py @@ -295,18 +295,28 @@ class UserLogin(viewsets.ViewSet): try: if user is not None: login(request, user) - if user_type == USER_TYPE_FLAG["FIRST"]: + if user_type == USER_TYPE_FLAG["TWO"]: guardian_data = Guardian.objects.filter(user__username=username, is_verified=True).last() if guardian_data: serializer = GuardianSerializer( guardian_data, context={'user_type': user_type} ).data - elif user_type == USER_TYPE_FLAG["TWO"]: + else: + return custom_error_response( + ERROR_CODE["2070"], + response_status=status.HTTP_401_UNAUTHORIZED + ) + elif user_type == USER_TYPE_FLAG["FIRST"]: junior_data = Junior.objects.filter(auth__username=username, is_verified=True).last() if junior_data: serializer = JuniorSerializer( junior_data, context={'user_type': user_type} ).data + else: + return custom_error_response( + ERROR_CODE["2071"], + response_status=status.HTTP_401_UNAUTHORIZED + ) else: return custom_error_response( ERROR_CODE["2069"], diff --git a/base/messages.py b/base/messages.py index c7863c8..10fbfaa 100644 --- a/base/messages.py +++ b/base/messages.py @@ -95,7 +95,9 @@ ERROR_CODE = { "2066": "Task does not exist or not in expired state", "2067": "Action not allowed. User type missing.", "2068": "No guardian associated with this junior", - "2069": "Invalid user type" + "2069": "Invalid user type", + "2070": "You did not find as a guardian", + "2071": "You did not find as a junior" } """Success message code""" From a02dfd4e31a09edd3720f8a1a20a48d83cefdd02 Mon Sep 17 00:00:00 2001 From: jain Date: Mon, 14 Aug 2023 15:23:41 +0530 Subject: [PATCH 3/6] login api with user type --- account/views.py | 1 - 1 file changed, 1 deletion(-) diff --git a/account/views.py b/account/views.py index 5b71b86..7a26d9e 100644 --- a/account/views.py +++ b/account/views.py @@ -7,7 +7,6 @@ from notifications.utils import remove_fcm_token from datetime import datetime, timedelta from rest_framework import viewsets, status, views from rest_framework.decorators import action -import random import logging from django.utils import timezone import jwt From 7c809776b60ab6939b3f8d93ad4b4051453c1f4c Mon Sep 17 00:00:00 2001 From: jain Date: Mon, 14 Aug 2023 18:22:50 +0530 Subject: [PATCH 4/6] guardian code status --- junior/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/junior/serializers.py b/junior/serializers.py index dc8202f..c3e2d72 100644 --- a/junior/serializers.py +++ b/junior/serializers.py @@ -320,7 +320,7 @@ class RemoveJuniorSerializer(serializers.ModelSerializer): if instance: instance.is_invited = False instance.guardian_code = '{}' - instance.guardian_code_status = str(NUMBER['1']) + instance.guardian_code_status = str(NUMBER['one']) instance.save() return instance From 451c3bdae7b6b09aabfc6227aae77a615ea41120 Mon Sep 17 00:00:00 2001 From: jain Date: Wed, 16 Aug 2023 11:37:21 +0530 Subject: [PATCH 5/6] user type --- account/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/account/views.py b/account/views.py index 7a26d9e..d95f87a 100644 --- a/account/views.py +++ b/account/views.py @@ -294,7 +294,7 @@ class UserLogin(viewsets.ViewSet): try: if user is not None: login(request, user) - if user_type == USER_TYPE_FLAG["TWO"]: + if str(user_type) == USER_TYPE_FLAG["TWO"]: guardian_data = Guardian.objects.filter(user__username=username, is_verified=True).last() if guardian_data: serializer = GuardianSerializer( @@ -305,7 +305,7 @@ class UserLogin(viewsets.ViewSet): ERROR_CODE["2070"], response_status=status.HTTP_401_UNAUTHORIZED ) - elif user_type == USER_TYPE_FLAG["FIRST"]: + elif str(user_type) == USER_TYPE_FLAG["FIRST"]: junior_data = Junior.objects.filter(auth__username=username, is_verified=True).last() if junior_data: serializer = JuniorSerializer( From 60af098e1e0f4b129bbacdb7464c36b53434a081 Mon Sep 17 00:00:00 2001 From: jain Date: Wed, 16 Aug 2023 16:16:05 +0530 Subject: [PATCH 6/6] email verfication and user notification bug --- account/views.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/account/views.py b/account/views.py index d95f87a..c17f853 100644 --- a/account/views.py +++ b/account/views.py @@ -401,12 +401,13 @@ class AdminLoginViewSet(viewsets.GenericViewSet): class UserEmailVerification(viewsets.ModelViewSet): """User Email verification""" serializer_class = EmailVerificationSerializer + http_method_names = ('post',) - def list(self, request, *args, **kwargs): + def create(self, request, *args, **kwargs): try: - user_obj = User.objects.filter(username=self.request.GET.get('email')).last() - email_data = UserEmailOtp.objects.filter(email=self.request.GET.get('email'), - otp=self.request.GET.get('otp')).last() + user_obj = User.objects.filter(username=self.request.data.get('email')).last() + email_data = UserEmailOtp.objects.filter(email=self.request.data.get('email'), + otp=self.request.data.get('otp')).last() if email_data: input_datetime_str = str(email_data.expired_at) input_format = "%Y-%m-%d %H:%M:%S.%f%z" @@ -420,12 +421,12 @@ class UserEmailVerification(viewsets.ModelViewSet): email_data.is_verified = True email_data.save() if email_data.user_type == '1': - junior_data = Junior.objects.filter(auth__email=self.request.GET.get('email')).last() + junior_data = Junior.objects.filter(auth__email=self.request.data.get('email')).last() if junior_data: junior_data.is_verified = True junior_data.save() else: - guardian_data = Guardian.objects.filter(user__email=self.request.GET.get('email')).last() + guardian_data = Guardian.objects.filter(user__email=self.request.data.get('email')).last() if guardian_data: guardian_data.is_verified = True guardian_data.save() @@ -535,7 +536,7 @@ class UserNotificationAPIViewSet(viewsets.ModelViewSet): permission_classes = [IsAuthenticated] def list(self, request, *args, **kwargs): """profile view""" - queryset = self.queryset.filter(user=request.user) + queryset = UserNotification.objects.filter(user=request.user) serializer = UserNotificationSerializer(queryset, many=True) return custom_response(None, serializer.data, response_status=status.HTTP_200_OK)