mirror of
https://github.com/i701/sarlink-portal-api.git
synced 2025-04-19 23:46:53 +00:00
Add TemporaryUser model and related functionality for user registration and OTP verification
Some checks failed
Build and Push Docker Images / Build and Push Docker Images (push) Failing after 1m19s
Some checks failed
Build and Push Docker Images / Build and Push Docker Images (push) Failing after 1m19s
This commit is contained in:
parent
e0a80d4a00
commit
dd21b848b9
50
api/admin.py
50
api/admin.py
@ -1,6 +1,6 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
||||||
from api.models import User, Atoll, Island
|
from api.models import User, Atoll, Island, TemporaryUser
|
||||||
from django.contrib.auth.models import Permission
|
from django.contrib.auth.models import Permission
|
||||||
|
|
||||||
|
|
||||||
@ -65,11 +65,59 @@ class UserAdmin(BaseUserAdmin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TemporaryUserAdmin(admin.ModelAdmin):
|
||||||
|
list_display = (
|
||||||
|
"t_username",
|
||||||
|
"t_email",
|
||||||
|
"t_first_name",
|
||||||
|
"t_last_name",
|
||||||
|
"t_verified",
|
||||||
|
"t_mobile",
|
||||||
|
"t_address",
|
||||||
|
"t_wallet_balance",
|
||||||
|
"otp_verified",
|
||||||
|
"t_acc_no",
|
||||||
|
"t_id_card",
|
||||||
|
"t_dob",
|
||||||
|
"t_atoll",
|
||||||
|
"t_island",
|
||||||
|
"t_terms_accepted",
|
||||||
|
"t_policy_accepted",
|
||||||
|
)
|
||||||
|
fieldsets = (
|
||||||
|
(None, {"fields": ("t_username",)}),
|
||||||
|
(
|
||||||
|
"Personal info",
|
||||||
|
{
|
||||||
|
"fields": (
|
||||||
|
"t_first_name",
|
||||||
|
"t_last_name",
|
||||||
|
"t_email",
|
||||||
|
"t_mobile",
|
||||||
|
"t_address",
|
||||||
|
"t_verified",
|
||||||
|
"otp_verified",
|
||||||
|
"otp_expiry",
|
||||||
|
"t_wallet_balance",
|
||||||
|
"t_acc_no",
|
||||||
|
"t_id_card",
|
||||||
|
"t_dob",
|
||||||
|
"t_atoll",
|
||||||
|
"t_island",
|
||||||
|
"t_terms_accepted",
|
||||||
|
"t_policy_accepted",
|
||||||
|
)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# Re-register UserAdmin
|
# Re-register UserAdmin
|
||||||
admin.site.register(User, UserAdmin)
|
admin.site.register(User, UserAdmin)
|
||||||
admin.site.register(Permission)
|
admin.site.register(Permission)
|
||||||
admin.site.register(Atoll)
|
admin.site.register(Atoll)
|
||||||
admin.site.register(Island)
|
admin.site.register(Island)
|
||||||
|
admin.site.register(TemporaryUser, TemporaryUserAdmin)
|
||||||
|
|
||||||
|
|
||||||
# TokenAdmin.raw_id_fields = ["user"]
|
# TokenAdmin.raw_id_fields = ["user"]
|
||||||
|
@ -0,0 +1,97 @@
|
|||||||
|
# Generated by Django 5.2 on 2025-04-16 05:13
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
import pyotp
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("api", "0014_alter_user_email"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="user",
|
||||||
|
name="created_at",
|
||||||
|
field=models.DateTimeField(default=django.utils.timezone.now),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="user",
|
||||||
|
name="updated_at",
|
||||||
|
field=models.DateTimeField(auto_now=True),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="TemporaryUser",
|
||||||
|
fields=[
|
||||||
|
("t_id", models.AutoField(primary_key=True, serialize=False)),
|
||||||
|
(
|
||||||
|
"t_username",
|
||||||
|
models.CharField(
|
||||||
|
blank=True, max_length=255, null=True, unique=True
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("t_first_name", models.CharField(blank=True, max_length=255)),
|
||||||
|
("t_last_name", models.CharField(blank=True, max_length=255)),
|
||||||
|
("t_address", models.CharField(blank=True, max_length=255)),
|
||||||
|
(
|
||||||
|
"t_email",
|
||||||
|
models.EmailField(
|
||||||
|
blank=True, max_length=254, null=True, unique=True
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"t_mobile",
|
||||||
|
models.CharField(
|
||||||
|
blank=True, max_length=255, null=True, unique=True
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("t_designation", models.CharField(blank=True, max_length=255)),
|
||||||
|
("t_acc_no", models.CharField(blank=True, max_length=255)),
|
||||||
|
(
|
||||||
|
"t_id_card",
|
||||||
|
models.CharField(
|
||||||
|
blank=True, max_length=255, null=True, unique=True
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("t_verified", models.BooleanField(default=False)),
|
||||||
|
("t_dob", models.DateField(blank=True, null=True)),
|
||||||
|
("t_terms_accepted", models.BooleanField(default=False)),
|
||||||
|
("t_policy_accepted", models.BooleanField(default=False)),
|
||||||
|
("t_wallet_balance", models.FloatField(default=0.0)),
|
||||||
|
("t_ninja_user_id", models.CharField(blank=True, max_length=255)),
|
||||||
|
("created_at", models.DateTimeField(default=django.utils.timezone.now)),
|
||||||
|
("updated_at", models.DateTimeField(auto_now=True)),
|
||||||
|
(
|
||||||
|
"otp_secret",
|
||||||
|
models.CharField(default=pyotp.random_base32, max_length=50),
|
||||||
|
),
|
||||||
|
("otp_verified", models.BooleanField(default=False)),
|
||||||
|
(
|
||||||
|
"t_atoll",
|
||||||
|
models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name="temp_users",
|
||||||
|
to="api.atoll",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"t_island",
|
||||||
|
models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name="temp_users",
|
||||||
|
to="api.island",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "Temporary User",
|
||||||
|
"verbose_name_plural": "Temporary Users",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
@ -29,6 +29,8 @@ class User(AbstractUser):
|
|||||||
island = models.ForeignKey(
|
island = models.ForeignKey(
|
||||||
"Island", on_delete=models.SET_NULL, null=True, blank=True, related_name="users"
|
"Island", on_delete=models.SET_NULL, null=True, blank=True, related_name="users"
|
||||||
)
|
)
|
||||||
|
created_at = models.DateTimeField(default=timezone.now)
|
||||||
|
updated_at = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
def get_all_fields(self, instance):
|
def get_all_fields(self, instance):
|
||||||
return [field.name for field in instance.get_fields()]
|
return [field.name for field in instance.get_fields()]
|
||||||
@ -36,7 +38,43 @@ class User(AbstractUser):
|
|||||||
objects = CustomUserManager()
|
objects = CustomUserManager()
|
||||||
|
|
||||||
|
|
||||||
class TemporaryUser(User):
|
class TemporaryUser(models.Model):
|
||||||
|
t_id = models.AutoField(primary_key=True)
|
||||||
|
t_username = models.CharField(max_length=255, unique=True, blank=True, null=True)
|
||||||
|
t_first_name = models.CharField(max_length=255, blank=True)
|
||||||
|
t_last_name = models.CharField(max_length=255, blank=True)
|
||||||
|
t_address = models.CharField(max_length=255, blank=True)
|
||||||
|
t_email = models.EmailField(blank=True, null=True, unique=True)
|
||||||
|
t_mobile = models.CharField(max_length=255, blank=True, unique=True, null=True)
|
||||||
|
t_designation = models.CharField(max_length=255, blank=True)
|
||||||
|
t_acc_no = models.CharField(max_length=255, blank=True)
|
||||||
|
t_id_card = models.CharField(max_length=255, blank=True, unique=True, null=True)
|
||||||
|
t_verified = models.BooleanField(default=False)
|
||||||
|
t_dob = models.DateField(blank=True, null=True)
|
||||||
|
t_terms_accepted = models.BooleanField(default=False)
|
||||||
|
t_policy_accepted = models.BooleanField(default=False)
|
||||||
|
t_wallet_balance = models.FloatField(default=0.0)
|
||||||
|
t_ninja_user_id = models.CharField(max_length=255, blank=True)
|
||||||
|
t_atoll = models.ForeignKey(
|
||||||
|
"Atoll",
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
related_name="temp_users",
|
||||||
|
)
|
||||||
|
t_island = models.ForeignKey(
|
||||||
|
"Island",
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
related_name="temp_users",
|
||||||
|
)
|
||||||
|
created_at = models.DateTimeField(default=timezone.now)
|
||||||
|
updated_at = models.DateTimeField(auto_now=True)
|
||||||
|
|
||||||
|
def get_all_fields(self, instance):
|
||||||
|
return [field.name for field in instance.get_fields()]
|
||||||
|
|
||||||
otp_secret = models.CharField(max_length=50, default=pyotp.random_base32)
|
otp_secret = models.CharField(max_length=50, default=pyotp.random_base32)
|
||||||
otp_verified = models.BooleanField(default=False)
|
otp_verified = models.BooleanField(default=False)
|
||||||
|
|
||||||
@ -51,6 +89,13 @@ class TemporaryUser(User):
|
|||||||
def is_expired(self):
|
def is_expired(self):
|
||||||
return self.created_at < timezone.now() - timedelta(minutes=5)
|
return self.created_at < timezone.now() - timedelta(minutes=5)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = "Temporary User"
|
||||||
|
verbose_name_plural = "Temporary Users"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.t_username
|
||||||
|
|
||||||
|
|
||||||
class Atoll(models.Model):
|
class Atoll(models.Model):
|
||||||
name = models.CharField(max_length=255, unique=True)
|
name = models.CharField(max_length=255, unique=True)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from knox.models import AuthToken
|
from knox.models import AuthToken
|
||||||
from django.contrib.auth import authenticate
|
from django.contrib.auth import authenticate
|
||||||
from api.models import User, Atoll, Island
|
from api.models import User, Atoll, Island, TemporaryUser
|
||||||
from django.contrib.auth.models import Permission
|
from django.contrib.auth.models import Permission
|
||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
@ -82,6 +82,14 @@ class CustomUserByWalletBalanceSerializer(serializers.ModelSerializer):
|
|||||||
fields = ("wallet_balance",)
|
fields = ("wallet_balance",)
|
||||||
|
|
||||||
|
|
||||||
|
class TemporaryUserSerializer(serializers.ModelSerializer):
|
||||||
|
"""serializer for the user object"""
|
||||||
|
|
||||||
|
class Meta: # type: ignore
|
||||||
|
model = TemporaryUser
|
||||||
|
fields = ["t_username"]
|
||||||
|
|
||||||
|
|
||||||
class UserSerializer(serializers.ModelSerializer):
|
class UserSerializer(serializers.ModelSerializer):
|
||||||
"""serializer for the user object"""
|
"""serializer for the user object"""
|
||||||
|
|
||||||
@ -142,5 +150,5 @@ class AtollSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
|
|
||||||
class OTPVerificationSerializer(serializers.Serializer):
|
class OTPVerificationSerializer(serializers.Serializer):
|
||||||
mobile = serializers.CharField()
|
mobile = serializers.CharField(required=True, allow_blank=False)
|
||||||
otp = serializers.CharField()
|
otp = serializers.CharField(required=True, allow_blank=False)
|
||||||
|
30
api/sms.py
Normal file
30
api/sms.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
from decouple import config
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
api_url = config("SMS_API_URL")
|
||||||
|
api_key = config("SMS_API_KEY")
|
||||||
|
|
||||||
|
|
||||||
|
def send_otp(mobile: str, otp: int, message: str):
|
||||||
|
if not api_url or not api_key:
|
||||||
|
logger.debug("Failed to send SMS. Missing SMS_API_URL or SMS_API_KEY.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": f"Bearer {api_key}",
|
||||||
|
}
|
||||||
|
data = {
|
||||||
|
"number": mobile,
|
||||||
|
"message": message,
|
||||||
|
"check_delivery": False,
|
||||||
|
}
|
||||||
|
response = requests.post(api_url, headers=headers, data=json.dumps(data))
|
||||||
|
if response.status_code == 200:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
logger.debug(f"Failed to send SMS. Status code: {response.status_code}")
|
||||||
|
return False
|
@ -4,7 +4,7 @@ from django.urls import path
|
|||||||
from knox import views as knox_views
|
from knox import views as knox_views
|
||||||
from .views import (
|
from .views import (
|
||||||
LoginView,
|
LoginView,
|
||||||
CreateUserView,
|
CreateTemporaryUserView,
|
||||||
ManageUserView,
|
ManageUserView,
|
||||||
KnoxTokenListApiView,
|
KnoxTokenListApiView,
|
||||||
ListUserView,
|
ListUserView,
|
||||||
@ -18,11 +18,13 @@ from .views import (
|
|||||||
RetrieveUpdateDestroyIslandView,
|
RetrieveUpdateDestroyIslandView,
|
||||||
filter_user,
|
filter_user,
|
||||||
UpdateUserWalletView,
|
UpdateUserWalletView,
|
||||||
|
VerifyOTPView,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("create/", CreateUserView.as_view(), name="create"),
|
path("register/", CreateTemporaryUserView.as_view(), name="register"),
|
||||||
|
path("register/verify/", VerifyOTPView.as_view(), name="verify-otp"),
|
||||||
path("profile/", ManageUserView.as_view(), name="profile"),
|
path("profile/", ManageUserView.as_view(), name="profile"),
|
||||||
path("login/", LoginView.as_view(), name="knox_login"),
|
path("login/", LoginView.as_view(), name="knox_login"),
|
||||||
path("logout/", knox_views.LogoutView.as_view(), name="knox_logout"),
|
path("logout/", knox_views.LogoutView.as_view(), name="knox_logout"),
|
||||||
|
106
api/views.py
106
api/views.py
@ -6,7 +6,7 @@ from rest_framework import generics, permissions
|
|||||||
from rest_framework.authtoken.serializers import AuthTokenSerializer
|
from rest_framework.authtoken.serializers import AuthTokenSerializer
|
||||||
from api.filters import UserFilter
|
from api.filters import UserFilter
|
||||||
from api.mixins import StaffEditorPermissionMixin
|
from api.mixins import StaffEditorPermissionMixin
|
||||||
from api.models import User, Atoll, Island
|
from api.models import User, Atoll, Island, TemporaryUser
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.exceptions import ValidationError
|
from rest_framework.exceptions import ValidationError
|
||||||
@ -15,6 +15,8 @@ from api.serializers import (
|
|||||||
AtollSerializer,
|
AtollSerializer,
|
||||||
IslandSerializer,
|
IslandSerializer,
|
||||||
CustomUserByWalletBalanceSerializer,
|
CustomUserByWalletBalanceSerializer,
|
||||||
|
OTPVerificationSerializer,
|
||||||
|
TemporaryUserSerializer,
|
||||||
)
|
)
|
||||||
|
|
||||||
# knox imports
|
# knox imports
|
||||||
@ -25,11 +27,12 @@ import re
|
|||||||
from typing import cast, Dict, Any
|
from typing import cast, Dict, Any
|
||||||
from django.core.mail import send_mail
|
from django.core.mail import send_mail
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
from api.sms import send_otp
|
||||||
|
|
||||||
|
|
||||||
# local apps import
|
# local apps import
|
||||||
from .serializers import (
|
from .serializers import (
|
||||||
KnoxTokenSerializer,
|
KnoxTokenSerializer,
|
||||||
UserSerializer,
|
|
||||||
AuthSerializer,
|
AuthSerializer,
|
||||||
CustomUserSerializer,
|
CustomUserSerializer,
|
||||||
CustomReadOnlyUserSerializer,
|
CustomReadOnlyUserSerializer,
|
||||||
@ -45,6 +48,7 @@ class ErrorMessages:
|
|||||||
USERNAME_EXISTS = "Username already exists."
|
USERNAME_EXISTS = "Username already exists."
|
||||||
MOBILE_EXISTS = "Mobile number already exists."
|
MOBILE_EXISTS = "Mobile number already exists."
|
||||||
INVALID_ID_CARD = "Please enter a valid ID card number."
|
INVALID_ID_CARD = "Please enter a valid ID card number."
|
||||||
|
ID_CARD_EXISTS = "ID card already exists."
|
||||||
INVALID_MOBILE = "Please enter a valid mobile number."
|
INVALID_MOBILE = "Please enter a valid mobile number."
|
||||||
INVALID_ACCOUNT = "Please enter a valid account number."
|
INVALID_ACCOUNT = "Please enter a valid account number."
|
||||||
|
|
||||||
@ -78,15 +82,14 @@ class UpdateUserWalletView(generics.UpdateAPIView):
|
|||||||
return Response({"message": "Wallet balance updated successfully."})
|
return Response({"message": "Wallet balance updated successfully."})
|
||||||
|
|
||||||
|
|
||||||
class CreateUserView(generics.CreateAPIView):
|
class CreateTemporaryUserView(generics.CreateAPIView):
|
||||||
# Create user API view
|
# Create user API view
|
||||||
serializer_class = UserSerializer
|
serializer_class = TemporaryUserSerializer
|
||||||
permission_classes = (permissions.AllowAny,)
|
permission_classes = (permissions.AllowAny,)
|
||||||
queryset = User.objects.all()
|
queryset = TemporaryUser.objects.all()
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
# Extract required fields from request data
|
# Extract required fields from request data
|
||||||
password = request.data.get("password")
|
|
||||||
username = request.data.get("username")
|
username = request.data.get("username")
|
||||||
address = request.data.get("address")
|
address = request.data.get("address")
|
||||||
mobile = request.data.get("mobile")
|
mobile = request.data.get("mobile")
|
||||||
@ -100,16 +103,19 @@ class CreateUserView(generics.CreateAPIView):
|
|||||||
firstname = request.data.get("firstname")
|
firstname = request.data.get("firstname")
|
||||||
lastname = request.data.get("lastname")
|
lastname = request.data.get("lastname")
|
||||||
|
|
||||||
if User.objects.filter(mobile=mobile).exists():
|
if TemporaryUser.objects.filter(t_mobile=mobile).exists():
|
||||||
return Response({"message": ErrorMessages.MOBILE_EXISTS}, status=400)
|
return Response({"message": ErrorMessages.MOBILE_EXISTS}, status=400)
|
||||||
|
|
||||||
if User.objects.filter(username=username).exists():
|
if TemporaryUser.objects.filter(t_username=username).exists():
|
||||||
return Response({"message": ErrorMessages.USERNAME_EXISTS}, status=400)
|
return Response({"message": ErrorMessages.USERNAME_EXISTS}, status=400)
|
||||||
|
|
||||||
|
if TemporaryUser.objects.filter(t_id_card=id_card).exists():
|
||||||
|
return Response({"message": ErrorMessages.ID_CARD_EXISTS}, status=400)
|
||||||
|
|
||||||
if id_card and not re.match(ID_CARD_PATTERN, id_card):
|
if id_card and not re.match(ID_CARD_PATTERN, id_card):
|
||||||
return Response({"message": ErrorMessages.INVALID_ID_CARD}, status=400)
|
return Response({"message": ErrorMessages.INVALID_ID_CARD}, status=400)
|
||||||
|
|
||||||
if User.objects.filter(id_card=id_card).exists():
|
if TemporaryUser.objects.filter(t_id_card=id_card).exists():
|
||||||
return Response({"message": "ID card already exists."}, status=400)
|
return Response({"message": "ID card already exists."}, status=400)
|
||||||
|
|
||||||
if mobile is None or not re.match(MOBILE_PATTERN, mobile):
|
if mobile is None or not re.match(MOBILE_PATTERN, mobile):
|
||||||
@ -133,23 +139,28 @@ class CreateUserView(generics.CreateAPIView):
|
|||||||
return Response({"message": "Island not found."}, status=404)
|
return Response({"message": "Island not found."}, status=404)
|
||||||
|
|
||||||
# Create user
|
# Create user
|
||||||
user = User.objects.create_user(
|
temp_user = TemporaryUser.objects.create(
|
||||||
first_name=firstname,
|
t_first_name=firstname,
|
||||||
last_name=lastname,
|
t_last_name=lastname,
|
||||||
username=str(username),
|
t_username=str(username),
|
||||||
password=password,
|
t_email=None,
|
||||||
email=None,
|
t_address=address,
|
||||||
address=address,
|
t_mobile=mobile,
|
||||||
mobile=mobile,
|
t_acc_no=acc_no,
|
||||||
acc_no=acc_no,
|
t_id_card=id_card,
|
||||||
id_card=id_card,
|
t_dob=dob,
|
||||||
dob=dob,
|
t_atoll=atoll,
|
||||||
atoll=atoll,
|
t_island=island,
|
||||||
island=island,
|
t_terms_accepted=terms_accepted,
|
||||||
terms_accepted=terms_accepted,
|
t_policy_accepted=policy_accepted,
|
||||||
policy_accepted=policy_accepted,
|
|
||||||
)
|
)
|
||||||
serializer = self.get_serializer(user)
|
otp = temp_user.generate_otp()
|
||||||
|
send_otp(
|
||||||
|
temp_user.t_mobile,
|
||||||
|
otp,
|
||||||
|
f"Your Registration SARLink OTP is: {otp}, valid for 30 seconds. Please do not share it with anyone.",
|
||||||
|
)
|
||||||
|
serializer = self.get_serializer(temp_user)
|
||||||
headers = self.get_success_headers(serializer.data)
|
headers = self.get_success_headers(serializer.data)
|
||||||
return Response(
|
return Response(
|
||||||
serializer.data, status=status.HTTP_201_CREATED, headers=headers
|
serializer.data, status=status.HTTP_201_CREATED, headers=headers
|
||||||
@ -159,7 +170,6 @@ class CreateUserView(generics.CreateAPIView):
|
|||||||
required_fields = {
|
required_fields = {
|
||||||
"firstname": "First name",
|
"firstname": "First name",
|
||||||
"lastname": "Last name",
|
"lastname": "Last name",
|
||||||
"password": "Password",
|
|
||||||
"username": "Username",
|
"username": "Username",
|
||||||
"address": "Address",
|
"address": "Address",
|
||||||
"mobile": "Mobile number",
|
"mobile": "Mobile number",
|
||||||
@ -182,6 +192,50 @@ class CreateUserView(generics.CreateAPIView):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class VerifyOTPView(generics.GenericAPIView):
|
||||||
|
permission_classes = (permissions.AllowAny,)
|
||||||
|
serializer_class = OTPVerificationSerializer
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
serializer = self.get_serializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
data = request.data
|
||||||
|
print(data)
|
||||||
|
try:
|
||||||
|
temp_user = TemporaryUser.objects.get(t_mobile=data["mobile"])
|
||||||
|
except TemporaryUser.DoesNotExist:
|
||||||
|
return Response({"message": "User not found."}, status=404)
|
||||||
|
|
||||||
|
if temp_user.is_expired():
|
||||||
|
return Response({"message": "OTP expired."}, status=400)
|
||||||
|
|
||||||
|
if not temp_user.verify_otp(data["otp"]):
|
||||||
|
return Response({"message": "Invalid OTP."}, status=400)
|
||||||
|
|
||||||
|
# Create real user
|
||||||
|
User.objects.create_user(
|
||||||
|
first_name=temp_user.t_first_name,
|
||||||
|
last_name=temp_user.t_last_name,
|
||||||
|
username=temp_user.t_username,
|
||||||
|
password="",
|
||||||
|
address=temp_user.t_address,
|
||||||
|
mobile=temp_user.t_mobile,
|
||||||
|
acc_no=temp_user.t_acc_no,
|
||||||
|
id_card=temp_user.t_id_card,
|
||||||
|
dob=temp_user.t_dob,
|
||||||
|
atoll=temp_user.t_atoll,
|
||||||
|
island=temp_user.t_island,
|
||||||
|
terms_accepted=temp_user.t_terms_accepted,
|
||||||
|
policy_accepted=temp_user.t_policy_accepted,
|
||||||
|
)
|
||||||
|
|
||||||
|
# You can now trigger registry verification as a signal or task
|
||||||
|
temp_user.otp_verified = True
|
||||||
|
temp_user.save()
|
||||||
|
|
||||||
|
return Response({"message": "User created successfully."})
|
||||||
|
|
||||||
|
|
||||||
class LoginView(KnoxLoginView):
|
class LoginView(KnoxLoginView):
|
||||||
# login view extending KnoxLoginView
|
# login view extending KnoxLoginView
|
||||||
serializer_class = AuthSerializer
|
serializer_class = AuthSerializer
|
||||||
|
Loading…
x
Reference in New Issue
Block a user