Skip to content

Commit

Permalink
feat: init otp login api
Browse files Browse the repository at this point in the history
  • Loading branch information
AmooHashem committed Oct 28, 2024
1 parent 78bd75e commit b88fcd6
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 2 deletions.
5 changes: 3 additions & 2 deletions apps/accounts/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from apps.accounts.views.change_password import ChangePasswordView
from apps.accounts.views.change_phone_number import change_phone_number_view
from apps.accounts.views.google_login import GoogleLogin
from apps.accounts.views.otp_login import OTPLoginView
from apps.accounts.views.simple_login import SimpleLogin
from apps.accounts.views.studentship_view import StudentshipViewSet
from apps.accounts.views.institute_view import InstituteViewSet, SchoolViewSet
Expand All @@ -22,13 +23,13 @@

urlpatterns = [
path('accounts/simple-login/', SimpleLogin.as_view(), name='create_token'),
path('accounts/otp-login/', OTPLoginView.as_view(), name='otp-login'),
path("accounts/google-login/", GoogleLogin.as_view(), name="google-login"),

path('accounts/verification_code/', VerificationCodeView.as_view(),
name="send_verification_code"),
path('accounts/refresh/', TokenRefreshView.as_view(), name='refresh_token'),
path('accounts/change_pass/', ChangePasswordView.as_view(), name="change_pass"),
path("accounts/login-with-google/",
GoogleLogin.as_view(), name="login-with-google"),
path("accounts/change-phone-number/",
change_phone_number_view, name="change-phone-number"),
path('accounts/user-list/', UserListAPIView.as_view(), name='user-list'),
Expand Down
85 changes: 85 additions & 0 deletions apps/accounts/views/otp_login.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
from django.db import transaction
from drf_yasg.utils import swagger_auto_schema
from rest_framework import permissions, status
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.exceptions import ParseError

from apps.accounts.serializers.user_serializer import PhoneNumberVerificationCodeSerializer, UserSerializer

from apps.accounts.utils import find_user_in_website, generate_tokens_for_user
from errors.error_codes import serialize_error


class OTPLoginView(APIView):
permission_classes = (permissions.AllowAny,)

@swagger_auto_schema(
tags=['accounts'],
request_body=PhoneNumberVerificationCodeSerializer,
responses={
200: UserSerializer,
201: UserSerializer, # For new user creation
400: "error code 4002 for len(code) < 5, 4003 for invalid & 4005 for expired code",
}
)
@transaction.atomic
def post(self, request):
# First validate the verification code using your existing serializer
verification_serializer = PhoneNumberVerificationCodeSerializer(
data=request.data)
verification_serializer.is_valid(raise_exception=True)

phone_number = verification_serializer.validated_data['phone_number']
website = request.headers.get("Website")

# Try to find existing user
try:
user = find_user_in_website(
user_data={"phone_number": phone_number},
website=website,
raise_exception=False
)
response_status = status.HTTP_200_OK
except:
# If user doesn't exist, create one with provided details
if not all([
request.data.get('first_name'),
request.data.get('last_name')
]):
raise ParseError(serialize_error('4007',
"First name and last name are required for new user registration"))

user_data = {
'phone_number': phone_number,
'username': phone_number,
'password': phone_number, # You might want to generate a random password
'first_name': request.data.get('first_name'),
'last_name': request.data.get('last_name'),
'email': request.data.get('email', '')
}

# Use your UserSerializer to create new user
user_serializer = UserSerializer(data=user_data)
user_serializer.is_valid(raise_exception=True)
user = user_serializer.create(user_serializer.validated_data)
response_status = status.HTTP_201_CREATED

# Generate tokens
access_token, refresh_token = generate_tokens_for_user(user)

# Invalidate the verification code
verification_code = VerificationCode.objects.get(
phone_number=phone_number,
code=verification_serializer.validated_data['code'],
is_valid=True
)
verification_code.is_valid = False
verification_code.save()

return Response({
'user': UserSerializer(user).data,
'access': str(access_token),
'refresh': str(refresh_token),
'is_new_user': response_status == status.HTTP_201_CREATED
}, status=response_status)

0 comments on commit b88fcd6

Please sign in to comment.