feat: otp table
This commit is contained in:
+37
-4
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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)}")
|
||||
Reference in New Issue
Block a user