1212from rest_framework .response import Response
1313
1414from care .emr .api .viewsets .base import EMRBaseViewSet
15- from care .facility .models .patient import PatientMobileOTP
15+ from care .facility .models .patient import MobileOTP
1616from care .utils import sms
1717from care .utils .models .validators import mobile_validator
18- from care .utils .sms .utils import get_sms_content
1918from config .patient_otp_token import PatientToken
2019
2120logger = logging .getLogger (__name__ )
2221
2322
23+ class BaseOTPType :
24+ def render_content (self , otp : str ) -> str :
25+ pass
26+
27+
28+ class LoginOTP (BaseOTPType ):
29+ @classmethod
30+ def render_content (cls , otp : str ) -> str :
31+ return settings .OTP_SMS_LOGIN_CONTENT .format (otp = otp )
32+
33+
2434def rand_pass (size ):
2535 return "" .join (secrets .choice (string .digits ) for _ in range (size ))
2636
2737
28- class OTPLoginRequestSpec (BaseModel ):
38+ def send_otp (phone_number , otp_type : BaseOTPType ):
39+ sent_otps = MobileOTP .objects .filter (
40+ created_date__gte = (timezone .now () - timedelta (settings .OTP_REPEAT_WINDOW )),
41+ is_used = False ,
42+ phone_number = phone_number ,
43+ )
44+ if sent_otps .count () >= settings .OTP_MAX_REPEATS_WINDOW :
45+ raise ValueError ("Max Retries has exceeded" )
46+
47+ random_otp = ""
48+ if settings .USE_SMS :
49+ random_otp = rand_pass (settings .OTP_LENGTH )
50+ try :
51+ content = otp_type .render_content (random_otp )
52+ sms .send_text_message (
53+ content = content ,
54+ recipients = [phone_number ],
55+ )
56+ except Exception as e :
57+ raise Exception ("Error while sending OTP. Contact admin." ) from e
58+ elif settings .IS_PRODUCTION :
59+ random_otp = rand_pass (settings .OTP_LENGTH )
60+ else :
61+ random_otp = "45612"
62+
63+ MobileOTP .objects .create (phone_number = phone_number , otp = random_otp )
64+
65+
66+ class OTPRequestBaseSpec (BaseModel ):
2967 phone_number : str
3068
3169 @field_validator ("phone_number" )
@@ -39,7 +77,7 @@ def validate_phone_number(cls, value):
3977 return value
4078
4179
42- class OTPLoginSpec (OTPLoginRequestSpec ):
80+ class OTPLoginSpec (OTPRequestBaseSpec ):
4381 otp : str = Field (min_length = settings .OTP_LENGTH , max_length = settings .OTP_LENGTH )
4482
4583
@@ -48,41 +86,17 @@ class OTPLoginView(EMRBaseViewSet):
4886 permission_classes = []
4987
5088 @extend_schema (
51- request = OTPLoginRequestSpec ,
89+ request = OTPRequestBaseSpec ,
5290 )
5391 @action (detail = False , methods = ["POST" ])
5492 def send (self , request ):
55- data = OTPLoginRequestSpec (** request .data )
56- sent_otps = PatientMobileOTP .objects .filter (
57- created_date__gte = (timezone .now () - timedelta (settings .OTP_REPEAT_WINDOW )),
58- is_used = False ,
59- phone_number = data .phone_number ,
60- )
61- if sent_otps .count () >= settings .OTP_MAX_REPEATS_WINDOW :
62- raise ValidationError ({"phone_number" : "Max Retries has exceeded" })
63- random_otp = ""
64- if settings .USE_SMS :
65- random_otp = rand_pass (settings .OTP_LENGTH )
66- try :
67- content = get_sms_content (
68- settings .OTP_SMS_TEMPLATE_PATH , {"random_otp" : random_otp }
69- )
70- sms .send_text_message (
71- content = content ,
72- recipients = [data .phone_number ],
73- )
74- except Exception as e :
75- logger .error (e )
76- return Response (
77- {"error" : "Error while sending OTP. Contact admin." }, status = 400
78- )
79- elif settings .IS_PRODUCTION :
80- random_otp = rand_pass (settings .OTP_LENGTH )
81- else :
82- random_otp = "45612"
83-
84- otp_obj = PatientMobileOTP (phone_number = data .phone_number , otp = random_otp )
85- otp_obj .save ()
93+ data = OTPRequestBaseSpec (** request .data )
94+ try :
95+ send_otp (data .phone_number , otp_type = LoginOTP )
96+ except ValueError as e :
97+ raise ValidationError ({"phone_number" : "Unable to send OTP" }) from e
98+ except Exception :
99+ return Response ({"error" : "Unable to send OTP" }, status = 400 )
86100 return Response ({"otp" : "generated" })
87101
88102 @extend_schema (
@@ -91,7 +105,7 @@ def send(self, request):
91105 @action (detail = False , methods = ["POST" ])
92106 def login (self , request ):
93107 data = OTPLoginSpec (** request .data )
94- otp_object = PatientMobileOTP .objects .filter (
108+ otp_object = MobileOTP .objects .filter (
95109 phone_number = data .phone_number , otp = data .otp , is_used = False
96110 ).first ()
97111 if not otp_object :
0 commit comments