Update OTP generation interval, enhance SMS sending functionality, and add age validation for temporary user registration
Some checks failed
Build and Push Docker Images / Build and Push Docker Images (push) Failing after 1m50s

This commit is contained in:
i701 2025-04-19 16:18:45 +05:00
parent f77779a84f
commit c006525aaa
Signed by: i701
GPG Key ID: 54A0DA1E26D8E587
5 changed files with 92 additions and 15 deletions

View File

@ -79,11 +79,11 @@ class TemporaryUser(models.Model):
otp_verified = models.BooleanField(default=False) otp_verified = models.BooleanField(default=False)
def generate_otp(self): def generate_otp(self):
totp = pyotp.TOTP(self.otp_secret, interval=300) totp = pyotp.TOTP(self.otp_secret, interval=1800)
return totp.now() return totp.now()
def verify_otp(self, otp): def verify_otp(self, otp):
totp = pyotp.TOTP(self.otp_secret, interval=300) totp = pyotp.TOTP(self.otp_secret, interval=1800)
return totp.verify(otp) return totp.verify(otp)
def is_expired(self): def is_expired(self):

View File

@ -28,3 +28,30 @@ def send_otp(mobile: str, otp: int, message: str):
else: else:
logger.debug(f"Failed to send SMS. Status code: {response.status_code}") logger.debug(f"Failed to send SMS. Status code: {response.status_code}")
return False return False
def send_sms(mobile: str, message: str):
logger.info(f"Sending SMS to {mobile}")
try:
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
except requests.exceptions.RequestException as e:
logger.debug(f"Failed to send SMS. Error: {e}")
return False

View File

@ -1,8 +1,12 @@
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from api.models import User from api.models import User
from api.sms import send_sms
import requests import requests
from apibase.env import env, BASE_DIR from apibase.env import env, BASE_DIR
import os import os
import logging
logger = logging.getLogger(__name__)
env.read_env(os.path.join(BASE_DIR, ".env")) env.read_env(os.path.join(BASE_DIR, ".env"))
@ -26,32 +30,57 @@ def verify_user_with_person_api_task(user_id: int):
api_name = data.get("name_en") api_name = data.get("name_en")
api_house_name = data.get("house_name_en") api_house_name = data.get("house_name_en")
api_dob = data.get("dob") api_dob = data.get("dob")
print(f"API nic: {api_nic}") api_atoll = data.get("atoll_en")
print(f"API name: {api_name}") api_island_name = data.get("island_name_en")
print(f"API house name: {api_house_name}")
print(f"API dob: {api_dob}") logger.info(f"API nic: {api_nic}")
logger.info(f"API name: {api_name}")
logger.info(f"API house name: {api_house_name}")
logger.info(f"API dob: {api_dob}")
logger.info(f"API atoll: {api_atoll}")
logger.info(f"API island name: {api_island_name}")
user_nic = user.id_card user_nic = user.id_card
user_name = f"{user.first_name} {user.last_name}" user_name = f"{user.first_name} {user.last_name}"
user_house_name = user.address user_house_name = user.address
user_dob = user.dob.isoformat() user_dob = user.dob.isoformat()
print(f"User nic: {user_nic}") logger.info(f"User nic: {user_nic}")
print(f"User name: {user_name}") logger.info(f"User name: {user_name}")
print(f"User house name: {user_house_name}") logger.info(f"User house name: {user_house_name}")
print(f"User dob: {user_dob}") logger.info(f"User dob: {user_dob}")
logger.info(f"User atoll: {user.atoll}")
logger.info(f"User island name: {user.island}")
logger.info(f"case User atoll: {user.atoll == api_atoll}")
logger.info("api atoll type: ", {type(api_atoll)})
logger.info("user atoll type: ", {type(user.atoll.name)})
logger.info(f"case User island name: {user.island == api_island_name}")
logger.info(f"api island name type: {type(api_island_name)}")
logger.info(f"user island name type: {type(user.island.name)}")
if ( if (
data.get("nic") == user.id_card data.get("nic") == user.id_card
and data.get("name_en") == f"{user.first_name} {user.last_name}" and data.get("name_en") == f"{user.first_name} {user.last_name}"
and data.get("house_name_en") == user.address and data.get("house_name_en") == user.address
and data.get("dob").split("T")[0] == user.dob.isoformat() and data.get("dob").split("T")[0] == user.dob.isoformat()
and data.get("atoll_en").strip() == user.atoll.name
and data.get("island_name_en").strip() == user.island.name
): ):
user.verified = True user.verified = True
user.save() user.save()
send_sms(
user.mobile,
f"Dear {user.first_name} {user.last_name}, \n\nYour account has been successfully and verified. \n\nYou can now manage your devices and make payments through our portal at https://portal.sarlink.net. \n\n - SAR Link",
)
return True return True
else: else:
user.verified = False user.verified = False
user.save() user.save()
send_sms(
user.mobile,
f"Dear {user.first_name} {user.last_name}, \n\nYour account registration is being processed. \n\nWe will notify you once verification is complete. \n\n - SAR Link",
)
return False return False
else: else:
# Handle the error case # Handle the error case

View File

@ -19,6 +19,8 @@ from api.serializers import (
TemporaryUserSerializer, TemporaryUserSerializer,
) )
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.utils import timezone
from datetime import timedelta
# knox imports # knox imports
from knox.views import LoginView as KnoxLoginView from knox.views import LoginView as KnoxLoginView
@ -52,6 +54,7 @@ class ErrorMessages:
ID_CARD_EXISTS = "ID card already exists." 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."
UNDERAGE_ERROR = "You must be 18 and above to signup."
class UpdateUserWalletView(generics.UpdateAPIView): class UpdateUserWalletView(generics.UpdateAPIView):
@ -105,6 +108,23 @@ class CreateTemporaryUserView(generics.CreateAPIView):
firstname = request.data.get("firstname") firstname = request.data.get("firstname")
lastname = request.data.get("lastname") lastname = request.data.get("lastname")
current_date = timezone.now()
try:
dob = timezone.datetime.strptime(dob, "%Y-%m-%d").date()
except ValueError:
return Response(
{"message": "Invalid date format for DOB. Use YYYY-MM-DD."}, status=400
)
age_from_dob = (
current_date.year
- dob.year
- ((current_date.month, current_date.day) < (dob.month, dob.day))
)
if age_from_dob < 18:
return Response({"message": ErrorMessages.UNDERAGE_ERROR}, status=400)
if ( if (
TemporaryUser.objects.filter(t_mobile=mobile).exists() TemporaryUser.objects.filter(t_mobile=mobile).exists()
or User.objects.filter(mobile=mobile).exists() or User.objects.filter(mobile=mobile).exists()
@ -162,11 +182,13 @@ class CreateTemporaryUserView(generics.CreateAPIView):
t_terms_accepted=terms_accepted, t_terms_accepted=terms_accepted,
t_policy_accepted=policy_accepted, t_policy_accepted=policy_accepted,
) )
otp_expiry = timezone.now() + timedelta(minutes=3)
formatted_time = otp_expiry.strftime("%d/%m/%Y %H:%M:%S")
otp = temp_user.generate_otp() otp = temp_user.generate_otp()
send_otp( send_otp(
temp_user.t_mobile, temp_user.t_mobile,
otp, otp,
f"Your Registration SARLink OTP is: {otp}, valid for 30 seconds. Please do not share it with anyone.", f"Your Registration SARLink OTP: {otp}. \nExpires at {formatted_time}. \n\n- SAR Link",
) )
serializer = self.get_serializer(temp_user) serializer = self.get_serializer(temp_user)
headers = self.get_success_headers(serializer.data) headers = self.get_success_headers(serializer.data)

View File

@ -205,8 +205,7 @@ AUTH_PASSWORD_VALIDATORS = [
LANGUAGE_CODE = "en-us" LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC" TIME_ZONE = "Asia/Atyrau"
USE_I18N = True USE_I18N = True
USE_TZ = True USE_TZ = True
@ -293,7 +292,7 @@ STORAGES = {
LOGGING_CONFIG = None LOGGING_CONFIG = None
LOGLEVEL = os.environ.get("LOGLEVEL", "WARNING").upper() LOGLEVEL = os.environ.get("LOGLEVEL", "INFO").upper()
logging.config.dictConfig( logging.config.dictConfig(
{ {
@ -321,7 +320,7 @@ logging.config.dictConfig(
}, },
"loggers": { "loggers": {
"": { "": {
"level": "WARNING", "level": LOGLEVEL,
"handlers": ["console"], "handlers": ["console"],
}, },
"app": { "app": {