feat: otp table

This commit is contained in:
2025-05-20 18:20:36 +05:30
parent 727d979145
commit eaa7519303
11 changed files with 180 additions and 32 deletions
+37 -4
View File
@@ -1,12 +1,17 @@
import datetime
import json
import urllib.request
from sqlalchemy.orm import Session
from services.jwtService import create_jwt_token
from services.userServices import UserServices
from models import BlockedEmail
from services.emailService import EmailService
from exceptions.validation_exception import ValidationException
from models import OTP
from utils.constants import generateOTP
from utils.password_utils import verify_password
from schemas.CreateSchemas import UserCreate
from schemas.BaseSchemas import AuthBase
from schemas.BaseSchemas import AuthBase, AuthOTP
from exceptions.unauthorized_exception import UnauthorizedException
from database import get_db
@@ -17,6 +22,7 @@ class AuthService:
def __init__(self):
self.user_service = UserServices()
self.db = next(get_db())
self.email_service = EmailService()
def login(self, data: AuthBase) -> str:
@@ -35,8 +41,8 @@ class AuthService:
token = create_jwt_token(user_dict)
return token
def register(self, user_data: UserCreate):
response = self.user_service.create_user(user_data)
def register(self, user_data: UserCreate, background_tasks=None):
response = self.user_service.create_user(user_data, background_tasks)
user = {
"id": response.id,
"username": response.username,
@@ -73,4 +79,31 @@ class AuthService:
self.db.add(blockEmail)
self.db.commit()
return "OK"
return "OK"
def send_otp(self, email:str):
otp = generateOTP()
self.email_service.send_otp_email(email, otp)
# Create OTP record with proper datetime handling
expire_time = datetime.datetime.now() + datetime.timedelta(minutes=10)
otp_record = OTP(email=email, otp=otp, expireAt=expire_time)
self.db.add(otp_record)
self.db.commit()
return
def verify_otp(self, data: AuthOTP):
db_otp = self.db.query(OTP).filter(OTP.email == data.email, OTP.otp == data.otp).first()
if not db_otp:
raise ValidationException("Invalid OTP")
if db_otp.otp != data.otp:
raise ValidationException("Invalid OTP")
if db_otp.expireAt < datetime.datetime.now():
raise ValidationException("OTP expired")
# OTP is valid, delete it to prevent reuse
# self.db.delete(db_otp)
# self.db.commit()
return
+11 -4
View File
@@ -9,14 +9,17 @@ from enums.enums import ClinicStatus, UserType
from exceptions.unauthorized_exception import UnauthorizedException
from interface.common_response import CommonResponse
from sqlalchemy import or_,func, case
from sqlalchemy import text
from services.s3Service import get_signed_url
from models import ClinicFileVerifications
from schemas.BaseSchemas import ClinicFileVerificationBase
from services.emailService import EmailService
class ClinicServices:
def __init__(self):
self.db: Session = next(get_db())
self.email_service = EmailService()
def get_clinics(self, user, limit:int, offset:int, filter_type: Union[Literal["UNREGISTERED"], Literal["REGISTERED"]] = "UNREGISTERED", search:str = ""):
@@ -42,10 +45,7 @@ class ClinicServices:
)
clinics = clinics_query.limit(limit).offset(offset).all()
# Get all counts in a single optimized query
from sqlalchemy import text
count_query = text("""
SELECT
COUNT(*) as total,
@@ -216,6 +216,9 @@ class ClinicServices:
self.db.add(clinic_file_verification)
self.db.commit()
# send mail to user
self.email_service.send_apporve_clinic_email(clinic.email, clinic.name)
if clinic.status == ClinicStatus.REJECTED or clinic.status == ClinicStatus.UNDER_REVIEW:
clinic_file_verification = self.db.query(ClinicFileVerifications).filter(ClinicFileVerifications.clinic_id == clinic_id).first()
@@ -238,6 +241,10 @@ class ClinicServices:
self.db.commit()
# send mail to user
self.email_service.send_reject_clinic_email(clinic.email, clinic.name)
# if rejected or under review then email to clinic creator
if clinic.status == ClinicStatus.REJECTED or clinic.status == ClinicStatus.UNDER_REVIEW:
pass
+40 -8
View File
@@ -76,7 +76,7 @@ class EmailService:
logger.error(f"Failed to create template: {e}")
raise Exception("Failed to create template")
def send_email(self, template_name: str, to_address: str, template_data: dict):
def send_email(self, template_name: str, to_address: str, template_data: dict) -> None:
"""Send an email using a template"""
try:
response = self.client.send_templated_email(
@@ -89,15 +89,47 @@ class EmailService:
ReplyToAddresses=[self.senderEmail]
)
logger.info(f"Email sent to {to_address} successfully. MessageId: {response['MessageId']}")
return response
return
except Exception as e:
logger.error(f"Error sending email to {to_address}: {str(e)}")
raise
def send_otp_email(self, email: str, otp: str):
"""Send OTP email"""
return self.send_email(
template_name="sendOTP",
def send_otp_email(self, email: str, otp: str) -> None:
try:
"""Send OTP email"""
self.send_email(
template_name="sendOTP",
to_address=email,
template_data={"otp": otp, "email": email}
)
return
except Exception as e:
logger.error(f"Error sending OTP email to {email}: {str(e)}")
raise
def send_new_clinic_email(self, email: str, clinic_name: str):
"""Send new clinic email"""
self.send_email(
template_name="newClinic",
to_address=email,
template_data={"otp": otp, "email": email}
)
template_data={"clinic_name": clinic_name, "email": email}
)
return
def send_reject_clinic_email(self, email: str, clinic_name: str):
"""Send reject clinic email"""
self.send_email(
template_name="rejectClinic",
to_address=email,
template_data={"clinic_name": clinic_name, "email": email}
)
return
def send_apporve_clinic_email(self, email: str, clinic_name: str):
"""Send apporve clinic email"""
self.send_email(
template_name="apporveClinic",
to_address=email,
template_data={"clinic_name": clinic_name, "email": email}
)
return
+24 -3
View File
@@ -17,13 +17,14 @@ from schemas.CreateSchemas import UserCreate
from exceptions.resource_not_found_exception import ResourceNotFoundException
from exceptions.db_exceptions import DBExceptionHandler
from sqlalchemy.orm import joinedload
from services.emailService import EmailService
class UserServices:
def __init__(self):
self.db: Session = next(get_db())
self.email_service = EmailService()
def create_user(self, user_data: UserCreate):
def create_user(self, user_data: UserCreate, background_tasks=None):
# Start a transaction
try:
user = user_data.user
@@ -116,6 +117,11 @@ class UserServices:
# Now commit both user and clinic in a single transaction
self.db.commit()
# Send mail to admin in a non-blocking way using background tasks
if background_tasks:
background_tasks.add_task(self._send_emails_to_admins, clinic.email)
# If no background_tasks provided, we don't send emails
return new_user
except Exception as e:
logger.error(f"Error creating user: {str(e)}")
@@ -234,4 +240,19 @@ class UserServices:
user.soft_delete(self.db)
return True
def get_super_admins(self):
return self.db.query(Users).filter(Users.userType == UserType.SUPER_ADMIN).all()
def _send_emails_to_admins(self, clinic_name):
"""Helper method to send emails to all super admins"""
try:
admins = self.get_super_admins()
for admin in admins:
self.email_service.send_new_clinic_email(
to_address=admin.email,
clinic_name=clinic_name
)
except Exception as e:
# Log the error but don't interrupt the main flow
logger.error(f"Error sending admin emails: {str(e)}")