from rest_framework.response import Response from typing import Optional from datetime import date from django.utils import timezone import re ID_CARD_PATTERN = r"^[A-Z]{1,2}[0-9]{6,7}$" MOBILE_PATTERN = r"^[7|9][0-9]{6}$" ACCOUNT_NUMBER_PATTERN = r"^(7\d{12}|9\d{16})$" class ErrorMessages: USERNAME_EXISTS = "Username already exists." MOBILE_EXISTS = "Mobile number already exists." 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_ACCOUNT = "Please enter a valid account number." UNDERAGE_ERROR = "You must be 18 and above to signup." def validate_required_fields(data) -> Optional[Response]: required_fields = { "firstname": "First name", "lastname": "Last name", "username": "Username", "address": "Address", "mobile": "Mobile number", "acc_no": "Account number", "id_card": "ID card", "dob": "Date of birth", "atoll": "Atoll", "island": "Island", } for field, label in required_fields.items(): if not data.get(field): return Response({"message": f"{label} is required."}, status=400) if data.get("terms_accepted") is None: return Response({"message": "Terms acceptance is required."}, status=400) if data.get("policy_accepted") is None: return Response({"message": "Policy acceptance is required."}, status=400) return None from .models import TemporaryUser, User def validate_unique_fields(username, mobile, id_card) -> Optional[Response]: if mobile and (TemporaryUser.objects.filter(t_mobile=mobile).exists() or User.objects.filter(mobile=mobile).exists()): return Response({"message": ErrorMessages.MOBILE_EXISTS}, status=400) if username and (TemporaryUser.objects.filter(t_username=username).exists() or User.objects.filter(username=username).exists()): return Response({"message": ErrorMessages.USERNAME_EXISTS}, status=400) if id_card and (TemporaryUser.objects.filter(t_id_card=id_card).exists() or User.objects.filter(id_card=id_card).exists()): return Response({"message": ErrorMessages.ID_CARD_EXISTS}, status=400) return None def validate_patterns(id_card, mobile, acc_no) -> Optional[Response]: if id_card and not re.match(ID_CARD_PATTERN, id_card): return Response({"message": ErrorMessages.INVALID_ID_CARD}, status=400) if mobile is None or not re.match(MOBILE_PATTERN, mobile): return Response({"message": ErrorMessages.INVALID_MOBILE}, status=400) if acc_no is None or not re.match(ACCOUNT_NUMBER_PATTERN, acc_no): return Response({"message": ErrorMessages.INVALID_ACCOUNT}, status=400) return None def calculate_age(dob: date) -> int: today = timezone.now().date() return today.year - dob.year - ((today.month, today.day) < (dob.month, dob.day))