Merge pull request #32 from KiwiTechLLC/login_code

Login code
This commit is contained in:
dilipshrivastwa-kiwi
2023-07-03 15:59:33 +05:30
committed by GitHub
6 changed files with 215 additions and 58 deletions

View File

@ -13,21 +13,15 @@ from rest_framework.decorators import action
from django.contrib.auth import authenticate, login from django.contrib.auth import authenticate, login
from rest_framework_simplejwt.tokens import RefreshToken from rest_framework_simplejwt.tokens import RefreshToken
from guardian.utils import upload_image_to_alibaba from guardian.utils import upload_image_to_alibaba
from .utils import get_token
class GoogleSignInSerializer(serializers.Serializer):
"""Google login Serializer"""
email = serializers.EmailField()
def create(self, validated_data): class GoogleLoginSerializer(serializers.Serializer):
"""Create or update user model""" access_token = serializers.CharField(max_length=5000, required=True)
with transaction.atomic():
if User.objects.filter(email__iexact=self.validated_data['email']).exists():
return User.objects.get(email__iexact=self.validated_data['email'])
if not User.objects.filter(email__iexact=self.validated_data['email']).exists(): class Meta:
instance = User.objects.create(username=self.validated_data['email'], """meta class"""
email=self.validated_data['email']) fields = ('access_token',)
return instance
class UpdateGuardianImageSerializer(serializers.ModelSerializer): class UpdateGuardianImageSerializer(serializers.ModelSerializer):
"""Reset Password after verification""" """Reset Password after verification"""
@ -132,11 +126,13 @@ class GuardianSerializer(serializers.ModelSerializer):
first_name = serializers.SerializerMethodField('get_first_name') first_name = serializers.SerializerMethodField('get_first_name')
last_name = serializers.SerializerMethodField('get_last_name') last_name = serializers.SerializerMethodField('get_last_name')
auth_token = serializers.SerializerMethodField('get_auth_token') auth_token = serializers.SerializerMethodField('get_auth_token')
refresh_token = serializers.SerializerMethodField('get_refresh_token')
def get_auth_token(self, obj): def get_auth_token(self, obj):
refresh = RefreshToken.for_user(obj.user) return get_token()['access']
access_token = str(refresh.access_token) def get_refresh_token(self, obj):
return access_token return get_token()['refresh']
def get_user_type(self, obj): def get_user_type(self, obj):
"""user type""" """user type"""
@ -157,8 +153,8 @@ class GuardianSerializer(serializers.ModelSerializer):
class Meta(object): class Meta(object):
"""Meta info""" """Meta info"""
model = Guardian model = Guardian
fields = ['auth_token', 'email', 'first_name', 'last_name', 'country_code', 'phone', 'family_name', 'gender', 'dob', fields = ['auth_token', 'refresh_token', 'email', 'first_name', 'last_name', 'country_code', 'phone', 'family_name', 'gender', 'dob',
'referral_code', 'is_active', 'is_complete_profile', 'passcode', 'referral_code', 'is_active', 'is_complete_profile', 'passcode', 'image',
'created_at', 'updated_at', 'user_type'] 'created_at', 'updated_at', 'user_type']
@ -169,11 +165,12 @@ class JuniorSerializer(serializers.ModelSerializer):
first_name = serializers.SerializerMethodField('get_first_name') first_name = serializers.SerializerMethodField('get_first_name')
last_name = serializers.SerializerMethodField('get_last_name') last_name = serializers.SerializerMethodField('get_last_name')
auth_token = serializers.SerializerMethodField('get_auth_token') auth_token = serializers.SerializerMethodField('get_auth_token')
refresh_token = serializers.SerializerMethodField('get_refresh_token')
def get_auth_token(self, obj): def get_auth_token(self, obj):
refresh = RefreshToken.for_user(obj.auth) return get_token()['access']
access_token = str(refresh.access_token) def get_refresh_token(self, obj):
return access_token return get_token()['refresh']
def get_user_type(self, obj): def get_user_type(self, obj):
return JUNIOR return JUNIOR
@ -190,8 +187,8 @@ class JuniorSerializer(serializers.ModelSerializer):
class Meta(object): class Meta(object):
"""Meta info""" """Meta info"""
model = Junior model = Junior
fields = ['auth_token', 'email', 'first_name', 'last_name', 'country_code', 'phone', 'gender', 'dob', fields = ['auth_token', 'refresh_token', 'email', 'first_name', 'last_name', 'country_code', 'phone', 'gender', 'dob',
'guardian_code', 'referral_code','is_active', 'is_complete_profile', 'created_at', 'guardian_code', 'referral_code','is_active', 'is_complete_profile', 'created_at', 'image',
'updated_at', 'user_type'] 'updated_at', 'user_type']
class EmailVerificationSerializer(serializers.ModelSerializer): class EmailVerificationSerializer(serializers.ModelSerializer):

View File

@ -5,14 +5,15 @@ from rest_framework.decorators import api_view
"""Third party import""" """Third party import"""
from rest_framework import routers from rest_framework import routers
from .views import (UserLogin, SendPhoneOtp, UserPhoneVerification, UserEmailVerification, ReSendEmailOtp, from .views import (UserLogin, SendPhoneOtp, UserPhoneVerification, UserEmailVerification, ReSendEmailOtp,
ForgotPasswordAPIView, ResetPasswordAPIView, ChangePasswordAPIView, UpdateProfileImage) ForgotPasswordAPIView, ResetPasswordAPIView, ChangePasswordAPIView, UpdateProfileImage,
GoogleLoginViewSet, SigninWithApple)
"""Router""" """Router"""
router = routers.SimpleRouter() router = routers.SimpleRouter()
"""API End points with router""" """API End points with router"""
router.register('user', UserLogin, basename='user') router.register('user', UserLogin, basename='user')
router.register('admin', UserLogin, basename='admin') router.register('admin', UserLogin, basename='admin')
# router.register('google-login', GoogleLoginAPIViewset, basename='admin') router.register('google-login', GoogleLoginViewSet, basename='admin')
router.register('send-phone-otp', SendPhoneOtp, basename='send-phone-otp') router.register('send-phone-otp', SendPhoneOtp, basename='send-phone-otp')
router.register('user-phone-verification', UserPhoneVerification, basename='user-phone-verification') router.register('user-phone-verification', UserPhoneVerification, basename='user-phone-verification')
router.register('user-email-verification', UserEmailVerification, basename='user-email-verification') router.register('user-email-verification', UserEmailVerification, basename='user-email-verification')
@ -22,5 +23,6 @@ urlpatterns = [
path('api/v1/forgot-password/', ForgotPasswordAPIView.as_view()), path('api/v1/forgot-password/', ForgotPasswordAPIView.as_view()),
path('api/v1/reset-password/', ResetPasswordAPIView.as_view()), path('api/v1/reset-password/', ResetPasswordAPIView.as_view()),
path('api/v1/change-password/', ChangePasswordAPIView.as_view()), path('api/v1/change-password/', ChangePasswordAPIView.as_view()),
path('api/v1/update-profile-image/', UpdateProfileImage.as_view()) path('api/v1/update-profile-image/', UpdateProfileImage.as_view()),
path('api/v1/apple-login/', SigninWithApple.as_view(), name='signup_with_apple'),
] ]

View File

@ -3,8 +3,13 @@
from django.conf import settings from django.conf import settings
from rest_framework import viewsets, status from rest_framework import viewsets, status
from rest_framework.response import Response from rest_framework.response import Response
from templated_email import send_templated_mail from templated_email import send_templated_mail
import jwt
from datetime import datetime
from calendar import timegm
from uuid import uuid4
import secrets
def send_otp_email(recipient_email, otp): def send_otp_email(recipient_email, otp):
from_email = settings.EMAIL_FROM_ADDRESS from_email = settings.EMAIL_FROM_ADDRESS
recipient_list = [recipient_email] recipient_list = [recipient_email]
@ -36,3 +41,53 @@ def custom_error_response(detail, response_status):
if not detail: if not detail:
detail = {} detail = {}
return Response({"error": detail, "status": "failed", "code": response_status}) return Response({"error": detail, "status": "failed", "code": response_status})
def get_user_data(attrs):
"""
used to decode token
"""
user_data = jwt.decode(jwt=attrs['token'], options={'verify_signature': False},
algorithms=['RS256'])
return user_data
def generate_jwt_token(token_type: str, now_time: int, data: dict = dict):
"""
used to generate jwt token
"""
if type(data) == type:
data = {}
data.update({
'token_type': token_type,
'iss': 'your_site_url',
'iat': timegm(datetime.utcnow().utctimetuple()),
'jti': uuid4().hex
})
TOKEN_TYPE = ["access", "refresh"]
if token_type == TOKEN_TYPE[1]:
exp = now_time + settings.SIMPLE_JWT['REFRESH_TOKEN_LIFETIME']
else:
exp = now_time + settings.SIMPLE_JWT['ACCESS_TOKEN_LIFETIME']
data.update({
"exp": timegm(exp.utctimetuple())
})
signing_key = secrets.token_hex(32)
return jwt.encode(payload=data, key=signing_key,
algorithm='HS256')
def get_token(data: dict = dict):
""" create access and refresh token """
now_time = datetime.utcnow()
access = generate_jwt_token('access', now_time, data)
refresh = generate_jwt_token('refresh', now_time, data)
return {
'access': access,
'refresh': refresh
}

View File

@ -2,6 +2,7 @@ from rest_framework import viewsets, status, views
from rest_framework.decorators import action from rest_framework.decorators import action
import random import random
import logging import logging
import jwt
from django.contrib.auth import authenticate, login from django.contrib.auth import authenticate, login
from guardian.models import Guardian from guardian.models import Guardian
from junior.models import Junior from junior.models import Junior
@ -9,40 +10,125 @@ from account.models import UserProfile, UserPhoneOtp, UserEmailOtp
from django.contrib.auth.models import User from django.contrib.auth.models import User
from .serializers import (SuperUserSerializer, GuardianSerializer, JuniorSerializer, EmailVerificationSerializer, from .serializers import (SuperUserSerializer, GuardianSerializer, JuniorSerializer, EmailVerificationSerializer,
ForgotPasswordSerializer, ResetPasswordSerializer, ChangePasswordSerializer, ForgotPasswordSerializer, ResetPasswordSerializer, ChangePasswordSerializer,
GoogleSignInSerializer, UpdateGuardianImageSerializer, UpdateJuniorProfileImageSerializer) GoogleLoginSerializer, UpdateGuardianImageSerializer, UpdateJuniorProfileImageSerializer)
from rest_framework_simplejwt.tokens import RefreshToken from rest_framework_simplejwt.tokens import RefreshToken
from base.messages import ERROR_CODE, SUCCESS_CODE from base.messages import ERROR_CODE, SUCCESS_CODE
from guardian.tasks import generate_otp from guardian.tasks import generate_otp
from django.conf import settings
from account.utils import send_otp_email from account.utils import send_otp_email
from account.utils import custom_response, custom_error_response 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 rest_framework.permissions import IsAuthenticated
from templated_email import send_templated_mail from templated_email import send_templated_mail
import google.oauth2.credentials
import google.auth.transport.requests
from rest_framework import status
from rest_framework.response import Response
import requests
from django.conf import settings
from .utils import get_token
class GoogleLoginMixin:
def google_login(self, request):
access_token = request.data.get('access_token')
user_type = request.data.get('user_type')
if not access_token:
return Response({'error': 'Access token is required.'}, status=status.HTTP_400_BAD_REQUEST)
try:
# Validate the access token and obtain the user's email and name
credentials = google.oauth2.credentials.Credentials.from_authorized_user_info(
info={
'access_token': access_token,
'token_uri': 'https://oauth2.googleapis.com/token',
'client_id': settings.GOOGLE_CLIENT_ID,
'client_secret': settings.GOOGLE_CLIENT_SECRET,
'refresh_token': None,
}
)
user_info_endpoint = f'https://www.googleapis.com/oauth2/v3/userinfo?access_token={access_token}'
headers = {'Authorization': f'Bearer {credentials.token}'}
response = requests.get(user_info_endpoint, headers=headers)
response.raise_for_status()
user_info = response.json()
email = user_info['email']
first_name = user_info['given_name']
last_name = user_info['family_name']
profile_picture = user_info['picture']
except Exception as e:
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
# Check if the user exists in your database or create a new user
# ...
user_data = User.objects.filter(email__iexact=email)
if user_data.exists():
if str(user_type) == '1':
junior_query = Junior.objects.filter(auth=user_data.last()).last()
serializer = JuniorSerializer(junior_query)
if str(user_type) == '2':
guardian_query = Guardian.objects.filter(user=user_data.last()).last()
serializer = GuardianSerializer(guardian_query)
return custom_response(SUCCESS_CODE['3003'], serializer.data,
response_status=status.HTTP_200_OK)
if not User.objects.filter(email__iexact=email).exists():
user_obj = User.objects.create(username=email, email=email, first_name=first_name, last_name=last_name)
if str(user_type) == '1':
junior_query = Junior.objects.create(auth=user_obj, is_verified=True, is_active=True,
image=profile_picture)
serializer = JuniorSerializer(junior_query)
if str(user_type) == '2':
guardian_query = Guardian.objects.create(user=user_obj, is_verified=True, is_active=True,
image=profile_picture)
serializer = GuardianSerializer(guardian_query)
# Return a JSON response with the user's email and name
return custom_response(SUCCESS_CODE['3003'], serializer.data,
response_status=status.HTTP_200_OK)
class GoogleLoginViewSet(GoogleLoginMixin, viewsets.GenericViewSet):
serializer_class = GoogleLoginSerializer
def create(self, request):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
return self.google_login(request)
class SigninWithApple(views.APIView):
"""This API is for sign in with Apple for app."""
def post(self, request):
token = request.data.get("access_token")
user_type = request.data.get("user_type")
if not token:
return custom_error_response(ERROR_CODE['2027'], response_status=status.HTTP_400_BAD_REQUEST)
try:
decoded_data = jwt.decode(token, options={"verify_signature": False})
user_data = {"email": decoded_data.get('email'), "username": decoded_data.get('email'), "is_active": True}
if decoded_data.get("email"):
try:
user = User.objects.get(email=decoded_data.get("email"))
if str(user_type) == '1':
junior_query = Junior.objects.filter(auth=user).last()
serializer = JuniorSerializer(junior_query)
if str(user_type) == '2':
guardian_query = Guardian.objects.filter(user=user).last()
serializer = GuardianSerializer(guardian_query)
return custom_response(SUCCESS_CODE['3003'], serializer.data,
response_status=status.HTTP_200_OK)
except User.DoesNotExist:
user = User.objects.create(**user_data)
if str(user_type) == '1':
junior_query = Junior.objects.create(auth=user, is_verified=True, is_active=True)
serializer = JuniorSerializer(junior_query)
if str(user_type) == '2':
guardian_query = Guardian.objects.create(user=user, is_verified=True, is_active=True)
serializer = GuardianSerializer(guardian_query)
return custom_response(SUCCESS_CODE['3003'], serializer.data,
response_status=status.HTTP_200_OK)
except Exception as e:
logging.error(e)
return custom_error_response(str(e), response_status=status.HTTP_400_BAD_REQUEST)
# class GoogleLoginAPIViewset(viewsets.ModelViewSet):
# """Google Login"""
# serializer_class = GoogleSignInSerializer
#
# def create(self, request, *args, **kwargs):
# """
# Override default behaviour of create method
# """
# provider_type = []
# serializer = self.get_serializer(data=request.data)
# if serializer.is_valid(raise_exception=True):
# # provider = self.get_provider_view(request.data.get('provider'))
# # if User is not authenticated then send error message
# # if not provider.is_authenticated(request):
# # return custom_error_response({}, status.HTTP_400_BAD_REQUEST)
#
# user = serializer.save()
# if User.objects.filter(email__iexact=user.email).exists():
# print("ppppppppppppp")
# return custom_response(SUCCESS_CODE["3003"], response_status=status.HTTP_200_OK)
# return custom_response(ERROR_CODE["2002"], response_status=status.HTTP_400_BAD_REQUEST)
class UpdateProfileImage(views.APIView): class UpdateProfileImage(views.APIView):
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]

View File

@ -49,7 +49,8 @@ ERROR_CODE = {
"2023": "Invalid user", "2023": "Invalid user",
"2024": "Email not verified", "2024": "Email not verified",
"2025": "Invalid input. Expected a list of strings.", "2025": "Invalid input. Expected a list of strings.",
"2026" : "New password should not same as old password" "2026": "New password should not same as old password",
"2027": "data should contain `identityToken`"
} }
SUCCESS_CODE = { SUCCESS_CODE = {
# Success code for password # Success code for password

View File

@ -56,6 +56,7 @@ INSTALLED_APPS = [
'account', 'account',
'junior', 'junior',
'guardian', 'guardian',
# 'social_django'
] ]
MIDDLEWARE = [ MIDDLEWARE = [
@ -95,7 +96,7 @@ REST_FRAMEWORK = {
] ]
} }
SIMPLE_JWT = { SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=15), 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=50),
'REFRESH_TOKEN_LIFETIME': timedelta(days=7), 'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
} }
# Database # Database
@ -171,6 +172,21 @@ CORS_ALLOW_HEADERS = (
"""Static files (CSS, JavaScript, Images) """Static files (CSS, JavaScript, Images)
https://docs.djangoproject.com/en/3.0/howto/static-files/""" https://docs.djangoproject.com/en/3.0/howto/static-files/"""
# AUTHENTICATION_BACKENDS = [
# 'social_core.backends.google.GoogleOAuth2',
# 'django.contrib.auth.backends.ModelBackend',
# ]
#
# LOGIN_URL = 'login'
# LOGIN_REDIRECT_URL = 'home'
# LOGOUT_URL = 'logout'
# LOGOUT_REDIRECT_URL = 'login'
# SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = ''
# SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = ''
GOOGLE_CLIENT_ID = "182276566528-hlbjncs19fo502jposod6kft2p9k4grk.apps.googleusercontent.com"
GOOGLE_CLIENT_SECRET = "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"
# EMAIL_BACKEND = os.getenv('EMAIL_BACKEND') # EMAIL_BACKEND = os.getenv('EMAIL_BACKEND')
# EMAIL_HOST = os.getenv('EMAIL_HOST') # EMAIL_HOST = os.getenv('EMAIL_HOST')