chaors: db optimization
This commit is contained in:
parent
62b6020897
commit
6c4fcca9bd
|
|
@ -12,15 +12,10 @@ from sqlalchemy.exc import SQLAlchemyError
|
||||||
engine = create_engine(
|
engine = create_engine(
|
||||||
os.getenv("DB_URL"),
|
os.getenv("DB_URL"),
|
||||||
pool_pre_ping=True,
|
pool_pre_ping=True,
|
||||||
pool_size=2, # Reduced from 5
|
echo=True if os.getenv("IS_DEV") == "True" else False, # Disable in production - this uses memory
|
||||||
max_overflow=3, # Reduced from 10
|
|
||||||
pool_recycle=1800, # Reduced to 30 minutes
|
|
||||||
pool_timeout=30, # Add connection timeout
|
|
||||||
echo=False, # Disable in production - this uses memory
|
|
||||||
connect_args={
|
connect_args={
|
||||||
"sslmode": "require" if os.getenv("IS_DEV") == "False" else "disable",
|
"sslmode": "require" if os.getenv("IS_DEV") == "False" else "disable",
|
||||||
"connect_timeout": 10, # Connection timeout
|
"connect_timeout": 10, # Connection timeout
|
||||||
"command_timeout": 60, # Query timeout
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ from schemas.BaseSchemas import AuthBase, AuthOTP
|
||||||
from exceptions.unauthorized_exception import UnauthorizedException
|
from exceptions.unauthorized_exception import UnauthorizedException
|
||||||
|
|
||||||
from database import get_db
|
from database import get_db
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
|
||||||
class AuthService:
|
class AuthService:
|
||||||
|
|
@ -35,6 +35,7 @@ class AuthService:
|
||||||
self.db = next(get_db())
|
self.db = next(get_db())
|
||||||
self.email_service = EmailService()
|
self.email_service = EmailService()
|
||||||
self.url = os.getenv("FRONTEND_URL")
|
self.url = os.getenv("FRONTEND_URL")
|
||||||
|
self.logger = logger
|
||||||
|
|
||||||
async def login(self, data: AuthBase) -> str:
|
async def login(self, data: AuthBase) -> str:
|
||||||
|
|
||||||
|
|
@ -58,58 +59,75 @@ class AuthService:
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def blockEmailSNS(self, body: str):
|
def blockEmailSNS(self, body: str):
|
||||||
# confirm subscription
|
try:
|
||||||
if body["Type"] == "SubscriptionConfirmation":
|
# confirm subscription
|
||||||
urllib.request.urlopen(body["SubscribeURL"])
|
if body["Type"] == "SubscriptionConfirmation":
|
||||||
|
urllib.request.urlopen(body["SubscribeURL"])
|
||||||
|
|
||||||
# disable automatic unsubscribe confirmation by activating subscription again
|
# disable automatic unsubscribe confirmation by activating subscription again
|
||||||
elif body["Type"] == "UnsubscribeConfirmation":
|
elif body["Type"] == "UnsubscribeConfirmation":
|
||||||
urllib.request.urlopen(body["SubscribeURL"])
|
urllib.request.urlopen(body["SubscribeURL"])
|
||||||
|
|
||||||
# handle bounce notifications only
|
# handle bounce notifications only
|
||||||
elif body["Type"] == "Notification":
|
elif body["Type"] == "Notification":
|
||||||
msg = json.loads(body["Message"])
|
msg = json.loads(body["Message"])
|
||||||
|
|
||||||
# check if msg contains notificationType
|
# check if msg contains notificationType
|
||||||
if "notificationType" not in msg:
|
if "notificationType" not in msg:
|
||||||
return
|
return
|
||||||
|
|
||||||
recepients = msg["bounce"]["bouncedRecipients"]
|
recepients = msg["bounce"]["bouncedRecipients"]
|
||||||
|
|
||||||
for recipient in recepients:
|
for recipient in recepients:
|
||||||
blockEmail = BlockedEmail(email=recipient["emailAddress"], reason=msg["notificationType"], severity=msg["bounce"]["bounceType"])
|
blockEmail = BlockedEmail(email=recipient["emailAddress"], reason=msg["notificationType"], severity=msg["bounce"]["bounceType"])
|
||||||
self.db.add(blockEmail)
|
self.db.add(blockEmail)
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
|
|
||||||
return "OK"
|
return "OK"
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error blocking email: {e}")
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def send_otp(self, email:str):
|
async def send_otp(self, email:str):
|
||||||
otp = generateOTP()
|
try:
|
||||||
self.email_service.send_otp_email(email, otp)
|
otp = generateOTP()
|
||||||
|
self.email_service.send_otp_email(email, otp)
|
||||||
|
|
||||||
# Create OTP record with proper datetime handling
|
# Create OTP record with proper datetime handling
|
||||||
expire_time = datetime.datetime.now() + datetime.timedelta(minutes=10)
|
expire_time = datetime.datetime.now() + datetime.timedelta(minutes=10)
|
||||||
otp_record = OTP(email=email, otp=otp, expireAt=expire_time)
|
otp_record = OTP(email=email, otp=otp, expireAt=expire_time)
|
||||||
self.db.add(otp_record)
|
self.db.add(otp_record)
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
|
|
||||||
return
|
return
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error sending OTP: {e}")
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def verify_otp(self, data: AuthOTP):
|
async def verify_otp(self, data: AuthOTP):
|
||||||
db_otp = self.db.query(OTP).filter(OTP.email == data.email, OTP.otp == data.otp).first()
|
try:
|
||||||
if not db_otp:
|
db_otp = self.db.query(OTP).filter(OTP.email == data.email, OTP.otp == data.otp).first()
|
||||||
raise ValidationException("Invalid OTP")
|
if not db_otp:
|
||||||
if db_otp.otp != data.otp:
|
raise ValidationException("Invalid OTP")
|
||||||
raise ValidationException("Invalid OTP")
|
if db_otp.otp != data.otp:
|
||||||
if db_otp.expireAt < datetime.datetime.now():
|
raise ValidationException("Invalid OTP")
|
||||||
raise ValidationException("OTP expired")
|
if db_otp.expireAt < datetime.datetime.now():
|
||||||
|
raise ValidationException("OTP expired")
|
||||||
|
|
||||||
# OTP is valid, delete it to prevent reuse
|
# OTP is valid, delete it to prevent reuse
|
||||||
# self.db.delete(db_otp)
|
self.db.delete(db_otp)
|
||||||
# self.db.commit()
|
self.db.commit()
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error verifying OTP: {e}")
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def get_admins(self, user, limit:int, offset:int, search:str):
|
async def get_admins(self, user, limit:int, offset:int, search:str):
|
||||||
try:
|
try:
|
||||||
|
|
@ -138,112 +156,144 @@ class AuthService:
|
||||||
|
|
||||||
return common_response
|
return common_response
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error getting admins: {e}")
|
||||||
raise e
|
raise e
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def create_super_admin(self, user, data: CreateSuperAdmin):
|
async def create_super_admin(self, user, data: CreateSuperAdmin):
|
||||||
|
try:
|
||||||
|
if user["userType"] != UserType.SUPER_ADMIN:
|
||||||
|
raise UnauthorizedException("User is not authorized to perform this action")
|
||||||
|
|
||||||
if user["userType"] != UserType.SUPER_ADMIN:
|
# password = "admin@123"
|
||||||
raise UnauthorizedException("User is not authorized to perform this action")
|
password = generate_secure_password()
|
||||||
|
hashed_password = hash_password(password)
|
||||||
|
|
||||||
# password = "admin@123"
|
# check if username and email are unique
|
||||||
password = generate_secure_password()
|
existing_user = (
|
||||||
hashed_password = hash_password(password)
|
self.db.query(Users)
|
||||||
|
.filter(
|
||||||
# check if username and email are unique
|
Users.email == data.email.lower(),
|
||||||
existing_user = (
|
)
|
||||||
self.db.query(Users)
|
.first()
|
||||||
.filter(
|
|
||||||
Users.email == data.email.lower(),
|
|
||||||
)
|
)
|
||||||
.first()
|
|
||||||
)
|
|
||||||
|
|
||||||
if existing_user:
|
if existing_user:
|
||||||
raise ValidationException("User with same email already exists")
|
raise ValidationException("User with same email already exists")
|
||||||
|
|
||||||
user = Users(
|
user = Users(
|
||||||
username=data.username,
|
username=data.username,
|
||||||
email=data.email.lower(),
|
email=data.email.lower(),
|
||||||
password=hashed_password,
|
password=hashed_password,
|
||||||
userType=UserType.SUPER_ADMIN,
|
userType=UserType.SUPER_ADMIN,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
self.db.add(user)
|
self.db.add(user)
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
|
|
||||||
|
|
||||||
LOGIN_URL = self.url
|
LOGIN_URL = self.url
|
||||||
|
|
||||||
# send email to user
|
# send email to user
|
||||||
self.email_service.send_new_admin_email(data.username, data.email, password, LOGIN_URL)
|
self.email_service.send_new_admin_email(data.username, data.email, password, LOGIN_URL)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error creating super admin: {e}")
|
||||||
|
raise e
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
|
|
||||||
async def update_super_admin(self, user, user_id: int, data: UpdateSuperAdmin):
|
async def update_super_admin(self, user, user_id: int, data: UpdateSuperAdmin):
|
||||||
if user["userType"] != UserType.SUPER_ADMIN:
|
try:
|
||||||
raise UnauthorizedException("User is not authorized to perform this action")
|
if user["userType"] != UserType.SUPER_ADMIN:
|
||||||
|
raise UnauthorizedException("User is not authorized to perform this action")
|
||||||
|
|
||||||
user = self.db.query(Users).filter(Users.id == user_id).first()
|
user = self.db.query(Users).filter(Users.id == user_id).first()
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
raise ResourceNotFoundException("User not found")
|
raise ResourceNotFoundException("User not found")
|
||||||
|
|
||||||
user.username = data.username.lower()
|
user.username = data.username.lower()
|
||||||
|
|
||||||
self.db.add(user)
|
self.db.add(user)
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
|
|
||||||
return
|
return
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error updating super admin: {e}")
|
||||||
|
raise e
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def delete_super_admin(self, user, user_id: int):
|
async def delete_super_admin(self, user, user_id: int):
|
||||||
if user["userType"] != UserType.SUPER_ADMIN:
|
try:
|
||||||
raise UnauthorizedException("User is not authorized to perform this action")
|
if user["userType"] != UserType.SUPER_ADMIN:
|
||||||
|
raise UnauthorizedException("User is not authorized to perform this action")
|
||||||
|
|
||||||
user = self.db.query(Users).filter(Users.id == user_id).first()
|
user = self.db.query(Users).filter(Users.id == user_id).first()
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
raise ResourceNotFoundException("User not found")
|
raise ResourceNotFoundException("User not found")
|
||||||
|
|
||||||
user.soft_delete(self.db)
|
user.soft_delete(self.db)
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error deleting super admin: {e}")
|
||||||
|
raise e
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def forget_password(self, email: str):
|
async def forget_password(self, email: str):
|
||||||
user = self.db.query(Users).filter(Users.email == email.lower()).first()
|
try:
|
||||||
|
user = self.db.query(Users).filter(Users.email == email.lower()).first()
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
raise ResourceNotFoundException("User not found")
|
raise ResourceNotFoundException("User not found")
|
||||||
|
|
||||||
# get reset password token
|
# get reset password token
|
||||||
reset_password_token = generate_reset_password_token()
|
reset_password_token = generate_reset_password_token()
|
||||||
|
|
||||||
reset_password = ResetPasswordTokens(email=email, token=reset_password_token)
|
reset_password = ResetPasswordTokens(email=email, token=reset_password_token)
|
||||||
self.db.add(reset_password)
|
self.db.add(reset_password)
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
|
|
||||||
reset_password_url = f"{self.url}/auth/reset-password?token={reset_password_token}"
|
reset_password_url = f"{self.url}/auth/reset-password?token={reset_password_token}"
|
||||||
|
|
||||||
self.email_service.send_reset_password_email(email, reset_password_url)
|
self.email_service.send_reset_password_email(email, reset_password_url)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error forgetting password: {e}")
|
||||||
|
raise e
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def reset_password(self, token: str, password: str):
|
async def reset_password(self, token: str, password: str):
|
||||||
reset_password = self.db.query(ResetPasswordTokens).filter(ResetPasswordTokens.token == token).first()
|
try:
|
||||||
|
reset_password = self.db.query(ResetPasswordTokens).filter(ResetPasswordTokens.token == token).first()
|
||||||
|
|
||||||
if not reset_password:
|
if not reset_password:
|
||||||
raise ResourceNotFoundException("Reset password token not found")
|
raise ResourceNotFoundException("Reset password token not found")
|
||||||
|
|
||||||
user = self.db.query(Users).filter(Users.email == reset_password.email).first()
|
user = self.db.query(Users).filter(Users.email == reset_password.email).first()
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
raise ResourceNotFoundException("User not found")
|
raise ResourceNotFoundException("User not found")
|
||||||
|
|
||||||
user.password = hash_password(password)
|
user.password = hash_password(password)
|
||||||
self.db.delete(reset_password)
|
self.db.delete(reset_password)
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
|
|
||||||
return
|
return
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error resetting password: {e}")
|
||||||
|
raise e
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -13,32 +13,46 @@ from models.CallTranscripts import CallTranscripts
|
||||||
from exceptions.business_exception import BusinessValidationException
|
from exceptions.business_exception import BusinessValidationException
|
||||||
from services.s3Service import get_signed_url
|
from services.s3Service import get_signed_url
|
||||||
from interface.common_response import CommonResponse
|
from interface.common_response import CommonResponse
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
from exceptions.db_exceptions import DBExceptionHandler
|
||||||
|
|
||||||
class CallTranscriptServices:
|
class CallTranscriptServices:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.db:Session = next(get_db())
|
self.db:Session = next(get_db())
|
||||||
|
self.logger = logger
|
||||||
|
|
||||||
async def get_call_transcripts(self, limit:int, offset:int):
|
async def get_call_transcripts(self, limit:int, offset:int):
|
||||||
call_transcripts = self.db.query(CallTranscripts).limit(limit).offset(offset).all()
|
try:
|
||||||
|
call_transcripts = self.db.query(CallTranscripts).limit(limit).offset(offset).all()
|
||||||
|
|
||||||
total = self.db.query(CallTranscripts).count()
|
total = self.db.query(CallTranscripts).count()
|
||||||
|
|
||||||
response = [CallTranscriptsResponse(**call_transcript.__dict__.copy()) for call_transcript in call_transcripts]
|
response = [CallTranscriptsResponse(**call_transcript.__dict__.copy()) for call_transcript in call_transcripts]
|
||||||
|
|
||||||
for call_transcript in response:
|
for call_transcript in response:
|
||||||
call_transcript.transcript_key_id = get_signed_url(call_transcript.transcript_key_id)
|
call_transcript.transcript_key_id = get_signed_url(call_transcript.transcript_key_id)
|
||||||
|
|
||||||
return_response = CommonResponse(data=response, total=total)
|
return_response = CommonResponse(data=response, total=total)
|
||||||
|
|
||||||
return return_response
|
return return_response
|
||||||
|
except Exception as e:
|
||||||
|
DBExceptionHandler.handle_exception(e, context="getting call transcripts")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
def download_call_transcript(self, key_id: str):
|
def download_call_transcript(self, key_id: str):
|
||||||
call_transcript = self.db.query(CallTranscripts).filter(CallTranscripts.transcript_key_id == key_id).first()
|
try:
|
||||||
|
call_transcript = self.db.query(CallTranscripts).filter(CallTranscripts.transcript_key_id == key_id).first()
|
||||||
|
|
||||||
if not call_transcript:
|
if not call_transcript:
|
||||||
raise BusinessValidationException("Call transcript not found!")
|
raise BusinessValidationException("Call transcript not found!")
|
||||||
|
|
||||||
return get_signed_url(call_transcript.transcript_key_id)
|
return get_signed_url(call_transcript.transcript_key_id)
|
||||||
|
except Exception as e:
|
||||||
|
DBExceptionHandler.handle_exception(e, context="downloading call transcript")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
|
|
||||||
def download_file(self, url: str, file_path: str) -> None:
|
def download_file(self, url: str, file_path: str) -> None:
|
||||||
|
|
@ -85,61 +99,65 @@ class CallTranscriptServices:
|
||||||
print(f"Error during cleanup: {e}")
|
print(f"Error during cleanup: {e}")
|
||||||
|
|
||||||
async def bulk_download_call_transcripts(self, key_ids: list[int], background_tasks: BackgroundTasks):
|
async def bulk_download_call_transcripts(self, key_ids: list[int], background_tasks: BackgroundTasks):
|
||||||
|
try:
|
||||||
|
transcript_ids = self.db.query(CallTranscripts).filter(CallTranscripts.id.in_(key_ids)).all()
|
||||||
|
|
||||||
transcript_ids = self.db.query(CallTranscripts).filter(CallTranscripts.id.in_(key_ids)).all()
|
keys = [transcript.transcript_key_id for transcript in transcript_ids]
|
||||||
|
|
||||||
keys = [transcript.transcript_key_id for transcript in transcript_ids]
|
if len(keys) < 1:
|
||||||
|
raise BusinessValidationException("No call transcripts found!")
|
||||||
if len(keys) < 1:
|
|
||||||
raise BusinessValidationException("No call transcripts found!")
|
|
||||||
|
|
||||||
|
|
||||||
temp_dir = tempfile.mkdtemp(prefix="call_transcripts_")
|
temp_dir = tempfile.mkdtemp(prefix="call_transcripts_")
|
||||||
zip_path = os.path.join(temp_dir, "call_transcripts.zip")
|
zip_path = os.path.join(temp_dir, "call_transcripts.zip")
|
||||||
|
|
||||||
# Prepare download information
|
# Prepare download information
|
||||||
download_info = []
|
download_info = []
|
||||||
for key in keys:
|
for key in keys:
|
||||||
# Generate signed URL for each key
|
# Generate signed URL for each key
|
||||||
url = get_signed_url(key)
|
url = get_signed_url(key)
|
||||||
|
|
||||||
|
# Determine filename (using key's basename or a formatted name)
|
||||||
|
filename = os.path.basename(key)
|
||||||
|
file_path = os.path.join(temp_dir, filename)
|
||||||
|
download_info.append((url, file_path, filename))
|
||||||
|
|
||||||
# Determine filename (using key's basename or a formatted name)
|
# Use ThreadPoolExecutor for concurrent downloads
|
||||||
filename = os.path.basename(key)
|
# Adjust max_workers based on your system capabilities and S3 rate limits
|
||||||
file_path = os.path.join(temp_dir, filename)
|
max_workers = min(32, len(download_info)) # Cap at 32 threads or number of files, whichever is smaller
|
||||||
download_info.append((url, file_path, filename))
|
|
||||||
|
|
||||||
# Use ThreadPoolExecutor for concurrent downloads
|
|
||||||
# Adjust max_workers based on your system capabilities and S3 rate limits
|
|
||||||
max_workers = min(32, len(download_info)) # Cap at 32 threads or number of files, whichever is smaller
|
|
||||||
|
|
||||||
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
|
||||||
# Submit all download tasks
|
|
||||||
future_to_file = {executor.submit(self.download_file, url, file_path): (file_path, filename)
|
|
||||||
for url, file_path, filename in download_info}
|
|
||||||
|
|
||||||
# Collect results as they complete
|
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
||||||
file_paths = []
|
# Submit all download tasks
|
||||||
for future in as_completed(future_to_file):
|
future_to_file = {executor.submit(self.download_file, url, file_path): (file_path, filename)
|
||||||
file_path, filename = future_to_file[future]
|
for url, file_path, filename in download_info}
|
||||||
try:
|
|
||||||
future.result() # Get the result to catch any exceptions
|
# Collect results as they complete
|
||||||
file_paths.append((file_path, filename))
|
file_paths = []
|
||||||
except Exception as e:
|
for future in as_completed(future_to_file):
|
||||||
print(f"Error downloading {filename}: {e}")
|
file_path, filename = future_to_file[future]
|
||||||
|
try:
|
||||||
# Create zip file from downloaded files
|
future.result() # Get the result to catch any exceptions
|
||||||
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zip_file:
|
file_paths.append((file_path, filename))
|
||||||
for file_path, arcname in file_paths:
|
except Exception as e:
|
||||||
if os.path.exists(file_path):
|
print(f"Error downloading {filename}: {e}")
|
||||||
zip_file.write(file_path, arcname=arcname)
|
|
||||||
|
# Create zip file from downloaded files
|
||||||
|
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zip_file:
|
||||||
|
for file_path, arcname in file_paths:
|
||||||
|
if os.path.exists(file_path):
|
||||||
|
zip_file.write(file_path, arcname=arcname)
|
||||||
|
|
||||||
# Add cleanup task to run after response is sent
|
# Add cleanup task to run after response is sent
|
||||||
background_tasks.add_task(self.cleanup_temp_files, temp_dir, zip_path)
|
background_tasks.add_task(self.cleanup_temp_files, temp_dir, zip_path)
|
||||||
|
|
||||||
# Return the zip file as a response
|
# Return the zip file as a response
|
||||||
return FileResponse(
|
return FileResponse(
|
||||||
path=zip_path,
|
path=zip_path,
|
||||||
media_type="application/zip",
|
media_type="application/zip",
|
||||||
filename="call_transcripts.zip",
|
filename="call_transcripts.zip",
|
||||||
background=background_tasks
|
background=background_tasks
|
||||||
)
|
)
|
||||||
|
except Exception as e:
|
||||||
|
DBExceptionHandler.handle_exception(e, context="bulk downloading call transcripts")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
@ -80,6 +80,8 @@ class ClinicDoctorsServices:
|
||||||
self.logger.error(e)
|
self.logger.error(e)
|
||||||
self.db.rollback()
|
self.db.rollback()
|
||||||
raise e
|
raise e
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def update_clinic_doctor(
|
async def update_clinic_doctor(
|
||||||
self, user, clinic_doctor_id: int, clinic_doctor_data: ClinicDoctorUpdate
|
self, user, clinic_doctor_id: int, clinic_doctor_data: ClinicDoctorUpdate
|
||||||
|
|
@ -155,6 +157,8 @@ class ClinicDoctorsServices:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.db.rollback()
|
self.db.rollback()
|
||||||
raise e
|
raise e
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def delete_clinic_doctor(self, clinic_doctor_id: int):
|
async def delete_clinic_doctor(self, clinic_doctor_id: int):
|
||||||
try:
|
try:
|
||||||
|
|
@ -167,26 +171,32 @@ class ClinicDoctorsServices:
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise e
|
raise e
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def get_doctor_status_count(self):
|
async def get_doctor_status_count(self):
|
||||||
|
try:
|
||||||
# Query to count doctors by status
|
# Query to count doctors by status
|
||||||
status_counts = (
|
status_counts = (
|
||||||
self.db.query(
|
self.db.query(
|
||||||
ClinicDoctors.status, func.count(ClinicDoctors.id).label("count")
|
ClinicDoctors.status, func.count(ClinicDoctors.id).label("count")
|
||||||
|
)
|
||||||
|
.group_by(ClinicDoctors.status)
|
||||||
|
.all()
|
||||||
)
|
)
|
||||||
.group_by(ClinicDoctors.status)
|
|
||||||
.all()
|
|
||||||
)
|
|
||||||
|
|
||||||
# Initialize result dictionary with all possible statuses set to 0
|
# Initialize result dictionary with all possible statuses set to 0
|
||||||
result = {status.value: 0 for status in ClinicDoctorStatus}
|
result = {status.value: 0 for status in ClinicDoctorStatus}
|
||||||
|
|
||||||
# Update with actual counts from the query
|
# Update with actual counts from the query
|
||||||
for status, count in status_counts:
|
for status, count in status_counts:
|
||||||
result[status.value] = count
|
result[status.value] = count
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
except Exception as e:
|
||||||
|
raise e
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def get_clinic_doctors(self, limit: int, offset: int, search: str = "", sort_by: str = DEFAULT_ORDER, sort_order: str = DEFAULT_ORDER_BY):
|
async def get_clinic_doctors(self, limit: int, offset: int, search: str = "", sort_by: str = DEFAULT_ORDER, sort_order: str = DEFAULT_ORDER_BY):
|
||||||
try:
|
try:
|
||||||
|
|
@ -258,3 +268,5 @@ class ClinicDoctorsServices:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(e)
|
self.logger.error(e)
|
||||||
raise e
|
raise e
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
|
||||||
|
|
@ -14,325 +14,390 @@ from services.s3Service import get_file_key, get_signed_url
|
||||||
from models import ClinicFileVerifications, ClinicOffers, Clinics, Users
|
from models import ClinicFileVerifications, ClinicOffers, Clinics, Users
|
||||||
from schemas.BaseSchemas import ClinicFileVerificationBase, ClinicOffersBase
|
from schemas.BaseSchemas import ClinicFileVerificationBase, ClinicOffersBase
|
||||||
from services.emailService import EmailService
|
from services.emailService import EmailService
|
||||||
|
from loguru import logger
|
||||||
|
from sqlalchemy import func
|
||||||
|
|
||||||
|
from exceptions.db_exceptions import DBExceptionHandler
|
||||||
class ClinicServices:
|
class ClinicServices:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.db: Session = next(get_db())
|
self.db: Session = next(get_db())
|
||||||
self.email_service = EmailService()
|
self.email_service = EmailService()
|
||||||
|
self.logger = logger
|
||||||
|
|
||||||
async def get_clinics(self, user, limit:int, offset:int, filter_type: Union[Literal["UNREGISTERED"], Literal["REGISTERED"]] = "UNREGISTERED", search:str = ""):
|
async def get_clinics(self, user, limit:int, offset:int, filter_type: Union[Literal["UNREGISTERED"], Literal["REGISTERED"]] = "UNREGISTERED", search:str = ""):
|
||||||
|
try:
|
||||||
|
if user["userType"] != UserType.SUPER_ADMIN:
|
||||||
|
raise UnauthorizedException("You are not authorized to get clinics")
|
||||||
|
|
||||||
if user["userType"] != UserType.SUPER_ADMIN:
|
clinics_query = self.db.query(Clinics).order_by(Clinics.update_time.desc())
|
||||||
raise UnauthorizedException("You are not authorized to get clinics")
|
|
||||||
|
|
||||||
clinics_query = self.db.query(Clinics).order_by(Clinics.update_time.desc())
|
if filter_type == "UNREGISTERED":
|
||||||
|
clinics_query = clinics_query.filter(not_(Clinics.status == ClinicStatus.ACTIVE),not_(Clinics.status == ClinicStatus.INACTIVE))
|
||||||
|
elif filter_type == "REGISTERED":
|
||||||
|
clinics_query = clinics_query.filter(or_(Clinics.status == ClinicStatus.ACTIVE,Clinics.status == ClinicStatus.INACTIVE))
|
||||||
|
|
||||||
if filter_type == "UNREGISTERED":
|
if search:
|
||||||
clinics_query = clinics_query.filter(not_(Clinics.status == ClinicStatus.ACTIVE),not_(Clinics.status == ClinicStatus.INACTIVE))
|
clinics_query = clinics_query.filter(
|
||||||
elif filter_type == "REGISTERED":
|
or_(
|
||||||
clinics_query = clinics_query.filter(or_(Clinics.status == ClinicStatus.ACTIVE,Clinics.status == ClinicStatus.INACTIVE))
|
Clinics.name.contains(search),
|
||||||
|
Clinics.email.contains(search),
|
||||||
if search:
|
Clinics.phone.contains(search),
|
||||||
clinics_query = clinics_query.filter(
|
Clinics.address.contains(search)
|
||||||
or_(
|
|
||||||
Clinics.name.contains(search),
|
|
||||||
Clinics.email.contains(search),
|
|
||||||
Clinics.phone.contains(search),
|
|
||||||
Clinics.address.contains(search)
|
|
||||||
|
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
clinics = clinics_query.offset(offset).limit(limit).all()
|
clinics = clinics_query.offset(offset).limit(limit).all()
|
||||||
|
|
||||||
count_query = text("""
|
count_query = text("""
|
||||||
SELECT
|
SELECT
|
||||||
COUNT(*) as total,
|
COUNT(*) as total,
|
||||||
COUNT(CASE WHEN status = 'ACTIVE' OR status = 'INACTIVE' THEN 1 END) as active,
|
COUNT(CASE WHEN status = 'ACTIVE' OR status = 'INACTIVE' THEN 1 END) as active,
|
||||||
COUNT(CASE WHEN status != 'ACTIVE' AND status != 'INACTIVE' THEN 1 END) as rejected
|
COUNT(CASE WHEN status != 'ACTIVE' AND status != 'INACTIVE' THEN 1 END) as rejected
|
||||||
FROM clinics
|
FROM clinics
|
||||||
""")
|
""")
|
||||||
|
|
||||||
result = self.db.execute(count_query).first()
|
result = self.db.execute(count_query).first()
|
||||||
|
|
||||||
totalClinics = result.total or 0
|
totalClinics = result.total or 0
|
||||||
totalRegisteredClinics = result.active or 0
|
totalRegisteredClinics = result.active or 0
|
||||||
totalRejectedClinics = result.rejected or 0
|
totalRejectedClinics = result.rejected or 0
|
||||||
|
|
||||||
clinic_response = [Clinic(**clinic.__dict__.copy()) for clinic in clinics]
|
clinic_response = [Clinic(**clinic.__dict__.copy()) for clinic in clinics]
|
||||||
|
|
||||||
for clinic in clinic_response:
|
for clinic in clinic_response:
|
||||||
clinic.logo = await get_signed_url(clinic.logo) if clinic.logo else None
|
clinic.logo = await get_signed_url(clinic.logo) if clinic.logo else None
|
||||||
|
|
||||||
clinic_response_with_total = {
|
clinic_response_with_total = {
|
||||||
"clinics": clinic_response,
|
"clinics": clinic_response,
|
||||||
"totalRegisteredClinics": totalRegisteredClinics,
|
"totalRegisteredClinics": totalRegisteredClinics,
|
||||||
"totalRejectedClinics": totalRejectedClinics,
|
"totalRejectedClinics": totalRejectedClinics,
|
||||||
}
|
}
|
||||||
|
|
||||||
response = CommonResponse(data=clinic_response_with_total, total=totalClinics)
|
response = CommonResponse(data=clinic_response_with_total, total=totalClinics)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
except Exception as e:
|
||||||
|
DBExceptionHandler.handle_exception(e, context="getting clinics")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def get_latest_clinic_id(self) -> int:
|
async def get_latest_clinic_id(self) -> int:
|
||||||
clinic = self.db.query(Clinics).order_by(Clinics.id.desc()).first()
|
try:
|
||||||
return clinic.id if clinic else 0
|
clinic = self.db.query(Clinics).order_by(Clinics.id.desc()).first()
|
||||||
|
return clinic.id if clinic else 0
|
||||||
|
except Exception as e:
|
||||||
|
DBExceptionHandler.handle_exception(e, context="getting latest clinic id")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
|
|
||||||
async def get_clinic_by_id(self, clinic_id: int):
|
async def get_clinic_by_id(self, clinic_id: int):
|
||||||
clinic = self.db.query(Clinics).options(joinedload(Clinics.creator)).filter(Clinics.id == clinic_id).first()
|
try:
|
||||||
|
clinic = self.db.query(Clinics).options(joinedload(Clinics.creator)).filter(Clinics.id == clinic_id).first()
|
||||||
|
|
||||||
if clinic is None:
|
if clinic is None:
|
||||||
raise ResourceNotFoundException("Clinic not found")
|
raise ResourceNotFoundException("Clinic not found")
|
||||||
|
|
||||||
clinic_response = Clinic(**clinic.__dict__.copy())
|
clinic_response = Clinic(**clinic.__dict__.copy())
|
||||||
|
|
||||||
clinic_response.logo = await get_signed_url(clinic_response.logo) if clinic_response.logo else None
|
clinic_response.logo = await get_signed_url(clinic_response.logo) if clinic_response.logo else None
|
||||||
clinic_response.abn_doc = await get_signed_url(clinic_response.abn_doc) if clinic_response.abn_doc else None
|
clinic_response.abn_doc = await get_signed_url(clinic_response.abn_doc) if clinic_response.abn_doc else None
|
||||||
clinic_response.contract_doc = await get_signed_url(clinic_response.contract_doc) if clinic_response.contract_doc else None
|
clinic_response.contract_doc = await get_signed_url(clinic_response.contract_doc) if clinic_response.contract_doc else None
|
||||||
|
|
||||||
clinicFiles = None
|
clinicFiles = None
|
||||||
if(clinic.status != ClinicStatus.ACTIVE):
|
if(clinic.status != ClinicStatus.ACTIVE):
|
||||||
clinicFiles = self.db.query(ClinicFileVerifications).filter(ClinicFileVerifications.clinic_id == clinic_id).first()
|
clinicFiles = self.db.query(ClinicFileVerifications).filter(ClinicFileVerifications.clinic_id == clinic_id).first()
|
||||||
|
|
||||||
clinic_resp = {
|
clinic_resp = {
|
||||||
"clinic": clinic_response,
|
"clinic": clinic_response,
|
||||||
"creator": {
|
"creator": {
|
||||||
"name": clinic.creator.username,
|
"name": clinic.creator.username,
|
||||||
"email": clinic.creator.email,
|
"email": clinic.creator.email,
|
||||||
"phone": clinic.creator.mobile,
|
"phone": clinic.creator.mobile,
|
||||||
"designation": clinic.creator.clinicRole
|
"designation": clinic.creator.clinicRole
|
||||||
},
|
},
|
||||||
"clinic_files": await self.get_clinic_files(clinic_id),
|
"clinic_files": await self.get_clinic_files(clinic_id),
|
||||||
"fileStatus": {"reason":clinicFiles.rejection_reason if clinicFiles else None},
|
"fileStatus": {"reason":clinicFiles.rejection_reason if clinicFiles else None},
|
||||||
}
|
}
|
||||||
|
|
||||||
return clinic_resp
|
return clinic_resp
|
||||||
|
except Exception as e:
|
||||||
|
DBExceptionHandler.handle_exception(e, context="getting clinic by id")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def get_clinic_files(self, clinic_id: int):
|
async def get_clinic_files(self, clinic_id: int):
|
||||||
clinic_files = self.db.query(ClinicFileVerifications).filter(ClinicFileVerifications.clinic_id == clinic_id).first()
|
try:
|
||||||
|
clinic_files = self.db.query(ClinicFileVerifications).filter(ClinicFileVerifications.clinic_id == clinic_id).first()
|
||||||
|
|
||||||
if clinic_files is None:
|
if clinic_files is None:
|
||||||
raise ResourceNotFoundException("Clinic not found")
|
raise ResourceNotFoundException("Clinic not found")
|
||||||
|
|
||||||
response = ClinicFileVerificationBase(**clinic_files.__dict__.copy())
|
response = ClinicFileVerificationBase(**clinic_files.__dict__.copy())
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
except Exception as e:
|
||||||
|
DBExceptionHandler.handle_exception(e, context="getting clinic files")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def update_clinic(self, user, clinic_id: int, clinic_data: ClinicUpdate):
|
async def update_clinic(self, user, clinic_id: int, clinic_data: ClinicUpdate):
|
||||||
clinic = self.db.query(Clinics).filter(Clinics.id == clinic_id).first()
|
try:
|
||||||
|
clinic = self.db.query(Clinics).filter(Clinics.id == clinic_id).first()
|
||||||
|
|
||||||
if clinic is None:
|
if clinic is None:
|
||||||
raise ResourceNotFoundException("Clinic not found")
|
raise ResourceNotFoundException("Clinic not found")
|
||||||
|
|
||||||
if clinic.creator_id != user["id"]:
|
if clinic.creator_id != user["id"]:
|
||||||
raise UnauthorizedException("You are not authorized to update this clinic")
|
raise UnauthorizedException("You are not authorized to update this clinic")
|
||||||
|
|
||||||
clinic_data.abn_doc = get_file_key(clinic_data.abn_doc) if clinic_data.abn_doc else None
|
clinic_data.abn_doc = get_file_key(clinic_data.abn_doc) if clinic_data.abn_doc else None
|
||||||
clinic_data.contract_doc = get_file_key(clinic_data.contract_doc) if clinic_data.contract_doc else None
|
clinic_data.contract_doc = get_file_key(clinic_data.contract_doc) if clinic_data.contract_doc else None
|
||||||
clinic_data.logo = get_file_key(clinic_data.logo) if clinic_data.logo else None
|
clinic_data.logo = get_file_key(clinic_data.logo) if clinic_data.logo else None
|
||||||
|
|
||||||
update_data = clinic_data.model_dump(exclude_unset=True)
|
update_data = clinic_data.model_dump(exclude_unset=True)
|
||||||
|
|
||||||
for key, value in update_data.items():
|
for key, value in update_data.items():
|
||||||
setattr(clinic, key, value)
|
setattr(clinic, key, value)
|
||||||
|
|
||||||
self.db.add(clinic)
|
self.db.add(clinic)
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
self.db.refresh(clinic)
|
self.db.refresh(clinic)
|
||||||
|
|
||||||
clinic_response = Clinic(**clinic.__dict__.copy())
|
clinic_response = Clinic(**clinic.__dict__.copy())
|
||||||
clinic_response.logo = get_signed_url(clinic_response.logo) if clinic_response.logo else None
|
clinic_response.logo = get_signed_url(clinic_response.logo) if clinic_response.logo else None
|
||||||
|
|
||||||
return clinic_response
|
return clinic_response
|
||||||
|
except Exception as e:
|
||||||
|
DBExceptionHandler.handle_exception(e, context="updating clinic")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def delete_clinic(self, clinic_id: int):
|
async def delete_clinic(self, clinic_id: int):
|
||||||
clinic = self.db.query(Clinics).filter(Clinics.id == clinic_id).first()
|
try:
|
||||||
|
clinic = self.db.query(Clinics).filter(Clinics.id == clinic_id).first()
|
||||||
|
|
||||||
if clinic is None:
|
if clinic is None:
|
||||||
raise ResourceNotFoundException("Clinic not found")
|
raise ResourceNotFoundException("Clinic not found")
|
||||||
|
|
||||||
clinic.soft_delete(self.db)
|
clinic.soft_delete(self.db)
|
||||||
|
except Exception as e:
|
||||||
|
DBExceptionHandler.handle_exception(e, context="deleting clinic")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def get_clinic_count(self):
|
async def get_clinic_count(self):
|
||||||
from sqlalchemy import func
|
try:
|
||||||
|
# Get total count
|
||||||
# Get total count
|
totalClinics = self.db.query(Clinics).count()
|
||||||
totalClinics = self.db.query(Clinics).count()
|
|
||||||
|
# Get counts for specific statuses in a single query
|
||||||
# Get counts for specific statuses in a single query
|
status_counts = self.db.query(
|
||||||
status_counts = self.db.query(
|
Clinics.status,
|
||||||
Clinics.status,
|
func.count(Clinics.id).label('count')
|
||||||
func.count(Clinics.id).label('count')
|
).filter(
|
||||||
).filter(
|
Clinics.status.in_([
|
||||||
Clinics.status.in_([
|
ClinicStatus.ACTIVE,
|
||||||
ClinicStatus.ACTIVE,
|
ClinicStatus.UNDER_REVIEW,
|
||||||
ClinicStatus.UNDER_REVIEW,
|
ClinicStatus.REJECTED
|
||||||
ClinicStatus.REJECTED
|
])
|
||||||
])
|
).group_by(Clinics.status).all()
|
||||||
).group_by(Clinics.status).all()
|
|
||||||
|
# Initialize counts with 0
|
||||||
# Initialize counts with 0
|
counts = {
|
||||||
counts = {
|
"totalClinics": totalClinics,
|
||||||
"totalClinics": totalClinics,
|
"totalActiveClinics": 0,
|
||||||
"totalActiveClinics": 0,
|
"totalUnderReviewClinics": 0,
|
||||||
"totalUnderReviewClinics": 0,
|
"totalRejectedClinics": 0
|
||||||
"totalRejectedClinics": 0
|
}
|
||||||
}
|
|
||||||
|
# Map status values to their respective count keys
|
||||||
# Map status values to their respective count keys
|
status_to_key = {
|
||||||
status_to_key = {
|
ClinicStatus.ACTIVE: "totalActiveClinics",
|
||||||
ClinicStatus.ACTIVE: "totalActiveClinics",
|
ClinicStatus.UNDER_REVIEW: "totalUnderReviewClinics",
|
||||||
ClinicStatus.UNDER_REVIEW: "totalUnderReviewClinics",
|
ClinicStatus.REJECTED: "totalRejectedClinics"
|
||||||
ClinicStatus.REJECTED: "totalRejectedClinics"
|
}
|
||||||
}
|
|
||||||
|
# Update counts with actual values from the query
|
||||||
# Update counts with actual values from the query
|
for status, count in status_counts:
|
||||||
for status, count in status_counts:
|
key = status_to_key.get(status)
|
||||||
key = status_to_key.get(status)
|
if key:
|
||||||
if key:
|
counts[key] = count
|
||||||
counts[key] = count
|
|
||||||
|
return counts
|
||||||
return counts
|
except Exception as e:
|
||||||
|
DBExceptionHandler.handle_exception(e, context="getting clinic count")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
|
|
||||||
async def update_clinic_status(self, user, clinic_id: int, status: ClinicStatus, documentStatus: Optional[dict] = None, rejection_reason: Optional[str] = None):
|
async def update_clinic_status(self, user, clinic_id: int, status: ClinicStatus, documentStatus: Optional[dict] = None, rejection_reason: Optional[str] = None):
|
||||||
if user["userType"] != UserType.SUPER_ADMIN:
|
try:
|
||||||
raise UnauthorizedException("You are not authorized to update clinic status")
|
if user["userType"] != UserType.SUPER_ADMIN:
|
||||||
|
raise UnauthorizedException("You are not authorized to update clinic status")
|
||||||
|
|
||||||
clinic = self.db.query(Clinics).filter(Clinics.id == clinic_id).first()
|
clinic = self.db.query(Clinics).filter(Clinics.id == clinic_id).first()
|
||||||
|
|
||||||
if clinic is None:
|
if clinic is None:
|
||||||
raise ResourceNotFoundException("Clinic not found")
|
raise ResourceNotFoundException("Clinic not found")
|
||||||
|
|
||||||
clinic.status = status
|
clinic.status = status
|
||||||
self.db.add(clinic)
|
self.db.add(clinic)
|
||||||
self.db.commit()
|
|
||||||
self.db.refresh(clinic)
|
|
||||||
|
|
||||||
if clinic.status == ClinicStatus.ACTIVE:
|
|
||||||
clinic_file_verification = self.db.query(ClinicFileVerifications).filter(ClinicFileVerifications.clinic_id == clinic_id).first()
|
|
||||||
|
|
||||||
clinic_file_verification.logo_is_verified = True
|
|
||||||
clinic_file_verification.abn_doc_is_verified = True
|
|
||||||
clinic_file_verification.contract_doc_is_verified = True
|
|
||||||
|
|
||||||
self.db.add(clinic_file_verification)
|
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
|
self.db.refresh(clinic)
|
||||||
|
|
||||||
# send mail to user
|
if clinic.status == ClinicStatus.ACTIVE:
|
||||||
self.email_service.send_apporve_clinic_email(clinic.email, clinic.name)
|
clinic_file_verification = self.db.query(ClinicFileVerifications).filter(ClinicFileVerifications.clinic_id == clinic_id).first()
|
||||||
|
|
||||||
|
clinic_file_verification.logo_is_verified = True
|
||||||
|
clinic_file_verification.abn_doc_is_verified = True
|
||||||
|
clinic_file_verification.contract_doc_is_verified = True
|
||||||
|
|
||||||
|
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:
|
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()
|
clinic_file_verification = self.db.query(ClinicFileVerifications).filter(ClinicFileVerifications.clinic_id == clinic_id).first()
|
||||||
|
|
||||||
|
|
||||||
if documentStatus and "LOGO" in documentStatus:
|
if documentStatus and "LOGO" in documentStatus:
|
||||||
clinic_file_verification.logo_is_verified = documentStatus.get("LOGO")
|
clinic_file_verification.logo_is_verified = documentStatus.get("LOGO")
|
||||||
clinic_file_verification.rejection_reason = rejection_reason
|
clinic_file_verification.rejection_reason = rejection_reason
|
||||||
|
|
||||||
if documentStatus and "ABN" in documentStatus:
|
if documentStatus and "ABN" in documentStatus:
|
||||||
clinic_file_verification.abn_doc_is_verified = documentStatus.get("ABN")
|
clinic_file_verification.abn_doc_is_verified = documentStatus.get("ABN")
|
||||||
clinic_file_verification.rejection_reason = rejection_reason
|
clinic_file_verification.rejection_reason = rejection_reason
|
||||||
|
|
||||||
if documentStatus and "CONTRACT" in documentStatus:
|
if documentStatus and "CONTRACT" in documentStatus:
|
||||||
clinic_file_verification.contract_doc_is_verified = documentStatus.get("CONTRACT")
|
clinic_file_verification.contract_doc_is_verified = documentStatus.get("CONTRACT")
|
||||||
clinic_file_verification.rejection_reason = rejection_reason
|
clinic_file_verification.rejection_reason = rejection_reason
|
||||||
|
|
||||||
|
|
||||||
self.db.add(clinic_file_verification)
|
self.db.add(clinic_file_verification)
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
|
|
||||||
|
|
||||||
# send mail to user
|
# send mail to user
|
||||||
self.email_service.send_reject_clinic_email(clinic.email, clinic.name)
|
self.email_service.send_reject_clinic_email(clinic.email, clinic.name)
|
||||||
|
|
||||||
|
|
||||||
# if rejected or under review then email to clinic creator
|
# if rejected or under review then email to clinic creator
|
||||||
if clinic.status == ClinicStatus.REJECTED or clinic.status == ClinicStatus.UNDER_REVIEW:
|
if clinic.status == ClinicStatus.REJECTED or clinic.status == ClinicStatus.UNDER_REVIEW:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# handle inactive status
|
# handle inactive status
|
||||||
if clinic.status == ClinicStatus.INACTIVE:
|
if clinic.status == ClinicStatus.INACTIVE:
|
||||||
# get clinic creator
|
# get clinic creator
|
||||||
# clinic_creator = self.db.query(Users).options(joinedload(Users.created_clinics)).filter(Clinics.id == clinic.id).first()
|
# clinic_creator = self.db.query(Users).options(joinedload(Users.created_clinics)).filter(Clinics.id == clinic.id).first()
|
||||||
|
|
||||||
# # block clinic creator
|
# # block clinic creator
|
||||||
# clinic_creator.isBlocked = True
|
# clinic_creator.isBlocked = True
|
||||||
# self.db.add(clinic_creator)
|
# self.db.add(clinic_creator)
|
||||||
# self.db.commit()
|
# self.db.commit()
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return
|
return
|
||||||
|
except Exception as e:
|
||||||
|
DBExceptionHandler.handle_exception(e, context="updating clinic status")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def get_clinic_offer_by_clinic_email(self, clinic_email: str):
|
async def get_clinic_offer_by_clinic_email(self, clinic_email: str):
|
||||||
clinic_offer = self.db.query(ClinicOffers).filter(ClinicOffers.clinic_email == clinic_email).first()
|
try:
|
||||||
return clinic_offer
|
clinic_offer = self.db.query(ClinicOffers).filter(ClinicOffers.clinic_email == clinic_email).first()
|
||||||
|
return clinic_offer
|
||||||
|
except Exception as e:
|
||||||
|
DBExceptionHandler.handle_exception(e, context="getting clinic offer by clinic email")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def get_clinic_offers(self, user, limit:int, offset:int, search:str = ""):
|
async def get_clinic_offers(self, user, limit:int, offset:int, search:str = ""):
|
||||||
|
try:
|
||||||
|
if user["userType"] != UserType.SUPER_ADMIN:
|
||||||
|
raise UnauthorizedException("You are not authorized to get clinic offers")
|
||||||
|
|
||||||
if user["userType"] != UserType.SUPER_ADMIN:
|
clinic_offers_query = self.db.query(ClinicOffers)
|
||||||
raise UnauthorizedException("You are not authorized to get clinic offers")
|
|
||||||
|
|
||||||
clinic_offers_query = self.db.query(ClinicOffers)
|
|
||||||
|
|
||||||
total = clinic_offers_query.count()
|
|
||||||
|
|
||||||
if search:
|
|
||||||
clinic_offers_query = clinic_offers_query.filter(ClinicOffers.clinic_email.contains(search))
|
|
||||||
total = clinic_offers_query.count()
|
total = clinic_offers_query.count()
|
||||||
|
|
||||||
clinic_offers = clinic_offers_query.limit(limit).offset(offset).all()
|
if search:
|
||||||
|
clinic_offers_query = clinic_offers_query.filter(ClinicOffers.clinic_email.contains(search))
|
||||||
|
total = clinic_offers_query.count()
|
||||||
|
|
||||||
clinic_offers_response = [ClinicOfferResponse(**clinic_offer.__dict__.copy()) for clinic_offer in clinic_offers]
|
clinic_offers = clinic_offers_query.limit(limit).offset(offset).all()
|
||||||
|
|
||||||
response = CommonResponse(data=clinic_offers_response, total=total)
|
clinic_offers_response = [ClinicOfferResponse(**clinic_offer.__dict__.copy()) for clinic_offer in clinic_offers]
|
||||||
|
|
||||||
return response
|
response = CommonResponse(data=clinic_offers_response, total=total)
|
||||||
|
|
||||||
|
return response
|
||||||
|
except Exception as e:
|
||||||
|
DBExceptionHandler.handle_exception(e, context="getting clinic offers")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def create_clinic_offer(self, user, clinic_offer_data: ClinicOffersBase):
|
async def create_clinic_offer(self, user, clinic_offer_data: ClinicOffersBase):
|
||||||
if user["userType"] != UserType.SUPER_ADMIN:
|
try:
|
||||||
raise UnauthorizedException("You are not authorized to create clinic offer")
|
if user["userType"] != UserType.SUPER_ADMIN:
|
||||||
|
raise UnauthorizedException("You are not authorized to create clinic offer")
|
||||||
|
|
||||||
existing_offer = self.db.query(ClinicOffers).filter(ClinicOffers.clinic_email == clinic_offer_data.clinic_email).first()
|
existing_offer = self.db.query(ClinicOffers).filter(ClinicOffers.clinic_email == clinic_offer_data.clinic_email).first()
|
||||||
|
|
||||||
if existing_offer:
|
if existing_offer:
|
||||||
raise ValidationException("Offer already exists for this clinic")
|
raise ValidationException("Offer already exists for this clinic")
|
||||||
|
|
||||||
clinic_offer = ClinicOffers(**clinic_offer_data.model_dump())
|
clinic_offer = ClinicOffers(**clinic_offer_data.model_dump())
|
||||||
|
|
||||||
self.db.add(clinic_offer)
|
self.db.add(clinic_offer)
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
|
|
||||||
return
|
return
|
||||||
|
except Exception as e:
|
||||||
|
DBExceptionHandler.handle_exception(e, context="creating clinic offer")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def update_clinic_offer(self, user, clinic_offer_id: int, clinic_offer_data: ClinicOffersBase):
|
async def update_clinic_offer(self, user, clinic_offer_id: int, clinic_offer_data: ClinicOffersBase):
|
||||||
if user["userType"] != UserType.SUPER_ADMIN:
|
try:
|
||||||
raise UnauthorizedException("You are not authorized to update clinic offer")
|
if user["userType"] != UserType.SUPER_ADMIN:
|
||||||
|
raise UnauthorizedException("You are not authorized to update clinic offer")
|
||||||
|
|
||||||
clinic_offer = self.db.query(ClinicOffers).filter(ClinicOffers.id == clinic_offer_id).first()
|
clinic_offer = self.db.query(ClinicOffers).filter(ClinicOffers.id == clinic_offer_id).first()
|
||||||
|
|
||||||
if clinic_offer is None:
|
if clinic_offer is None:
|
||||||
raise ResourceNotFoundException("Clinic offer not found")
|
raise ResourceNotFoundException("Clinic offer not found")
|
||||||
|
|
||||||
clinic_offer.setup_fees_waived = clinic_offer_data.setup_fees_waived
|
clinic_offer.setup_fees_waived = clinic_offer_data.setup_fees_waived
|
||||||
clinic_offer.special_offer_for_month = clinic_offer_data.special_offer_for_month
|
clinic_offer.special_offer_for_month = clinic_offer_data.special_offer_for_month
|
||||||
|
|
||||||
self.db.add(clinic_offer)
|
self.db.add(clinic_offer)
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
|
|
||||||
return
|
return
|
||||||
|
except Exception as e:
|
||||||
|
DBExceptionHandler.handle_exception(e, context="updating clinic offer")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def delete_clinic_offer(self, user, clinic_offer_id: int):
|
async def delete_clinic_offer(self, user, clinic_offer_id: int):
|
||||||
if user["userType"] != UserType.SUPER_ADMIN:
|
try:
|
||||||
raise UnauthorizedException("You are not authorized to delete clinic offer")
|
if user["userType"] != UserType.SUPER_ADMIN:
|
||||||
|
raise UnauthorizedException("You are not authorized to delete clinic offer")
|
||||||
|
|
||||||
clinic_offer = self.db.query(ClinicOffers).filter(ClinicOffers.id == clinic_offer_id).first()
|
clinic_offer = self.db.query(ClinicOffers).filter(ClinicOffers.id == clinic_offer_id).first()
|
||||||
|
|
||||||
if clinic_offer is None:
|
if clinic_offer is None:
|
||||||
raise ResourceNotFoundException("Clinic offer not found")
|
raise ResourceNotFoundException("Clinic offer not found")
|
||||||
|
|
||||||
clinic_offer.soft_delete(self.db)
|
clinic_offer.soft_delete(self.db)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
except Exception as e:
|
||||||
|
DBExceptionHandler.handle_exception(e, context="deleting clinic offer")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
@ -7,12 +7,13 @@ from models.SignupPricingMaster import SignupPricingMaster
|
||||||
from exceptions import UnauthorizedException
|
from exceptions import UnauthorizedException
|
||||||
from enums.enums import UserType
|
from enums.enums import UserType
|
||||||
from exceptions import ResourceNotFoundException
|
from exceptions import ResourceNotFoundException
|
||||||
|
from loguru import logger
|
||||||
class DashboardService:
|
class DashboardService:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.db = next(get_db())
|
self.db = next(get_db())
|
||||||
self.clinicDoctorsServices = ClinicDoctorsServices()
|
self.clinicDoctorsServices = ClinicDoctorsServices()
|
||||||
self.clinicServices = ClinicServices()
|
self.clinicServices = ClinicServices()
|
||||||
|
self.logger = logger
|
||||||
|
|
||||||
async def get_dashboard_counts(self, isSuperAdmin: bool):
|
async def get_dashboard_counts(self, isSuperAdmin: bool):
|
||||||
if isSuperAdmin:
|
if isSuperAdmin:
|
||||||
|
|
@ -25,50 +26,62 @@ class DashboardService:
|
||||||
async def update_signup_pricing_master(
|
async def update_signup_pricing_master(
|
||||||
self, user, pricing_data: SignupPricingMasterBase
|
self, user, pricing_data: SignupPricingMasterBase
|
||||||
):
|
):
|
||||||
if user["userType"] != UserType.SUPER_ADMIN:
|
try:
|
||||||
raise UnauthorizedException(
|
if user["userType"] != UserType.SUPER_ADMIN:
|
||||||
"You are not authorized to update signup pricing master"
|
raise UnauthorizedException(
|
||||||
)
|
"You are not authorized to update signup pricing master"
|
||||||
|
)
|
||||||
|
|
||||||
existing_pricing = self.db.query(SignupPricingMaster).first()
|
existing_pricing = self.db.query(SignupPricingMaster).first()
|
||||||
|
|
||||||
if existing_pricing is None:
|
if existing_pricing is None:
|
||||||
# Create new record
|
# Create new record
|
||||||
new_pricing = SignupPricingMaster(
|
new_pricing = SignupPricingMaster(
|
||||||
**pricing_data.model_dump()
|
**pricing_data.model_dump()
|
||||||
)
|
)
|
||||||
self.db.add(new_pricing)
|
self.db.add(new_pricing)
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
self.db.refresh(new_pricing)
|
self.db.refresh(new_pricing)
|
||||||
|
|
||||||
response = SignupPricingMasterResponse(
|
response = SignupPricingMasterResponse(
|
||||||
**new_pricing.__dict__.copy()
|
**new_pricing.__dict__.copy()
|
||||||
)
|
)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
else:
|
else:
|
||||||
# Update existing record with values from the request
|
# Update existing record with values from the request
|
||||||
existing_pricing.setup_fees = pricing_data.setup_fees
|
existing_pricing.setup_fees = pricing_data.setup_fees
|
||||||
existing_pricing.subscription_fees = pricing_data.subscription_fees
|
existing_pricing.subscription_fees = pricing_data.subscription_fees
|
||||||
existing_pricing.per_call_charges = pricing_data.per_call_charges
|
existing_pricing.per_call_charges = pricing_data.per_call_charges
|
||||||
|
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
self.db.refresh(existing_pricing)
|
self.db.refresh(existing_pricing)
|
||||||
|
|
||||||
response = SignupPricingMasterResponse(
|
response = SignupPricingMasterResponse(
|
||||||
**existing_pricing.__dict__.copy()
|
**existing_pricing.__dict__.copy()
|
||||||
)
|
)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error updating signup pricing master: {e}")
|
||||||
|
raise e
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
|
|
||||||
async def get_signup_pricing_master(self):
|
async def get_signup_pricing_master(self):
|
||||||
signup_pricing_master = self.db.query(SignupPricingMaster).first()
|
try:
|
||||||
if signup_pricing_master is None:
|
signup_pricing_master = self.db.query(SignupPricingMaster).first()
|
||||||
raise ResourceNotFoundException("Signup pricing master not found")
|
if signup_pricing_master is None:
|
||||||
|
raise ResourceNotFoundException("Signup pricing master not found")
|
||||||
|
|
||||||
response = SignupPricingMasterResponse(
|
response = SignupPricingMasterResponse(
|
||||||
**signup_pricing_master.__dict__.copy()
|
**signup_pricing_master.__dict__.copy()
|
||||||
)
|
)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error getting signup pricing master: {e}")
|
||||||
|
raise e
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
|
||||||
|
|
@ -6,61 +6,86 @@ from schemas.BaseSchemas import MasterAppointmentTypeBase
|
||||||
from exceptions import ResourceNotFoundException
|
from exceptions import ResourceNotFoundException
|
||||||
from interface.common_response import CommonResponse
|
from interface.common_response import CommonResponse
|
||||||
from schemas.ResponseSchemas import MasterAppointmentTypeResponse
|
from schemas.ResponseSchemas import MasterAppointmentTypeResponse
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
class MasterAppointmentServices:
|
class MasterAppointmentServices:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.db: Session = next(get_db())
|
self.db: Session = next(get_db())
|
||||||
|
self.logger = logger
|
||||||
|
|
||||||
|
|
||||||
async def get_master_appointment_types(self):
|
async def get_master_appointment_types(self):
|
||||||
appointment_types = self.db.query(MasterAppointmentTypes).all()
|
try:
|
||||||
total= self.db.query(MasterAppointmentTypes).count()
|
appointment_types = self.db.query(MasterAppointmentTypes).all()
|
||||||
response = CommonResponse(data=[MasterAppointmentTypeResponse(**appointment_type.__dict__.copy()) for appointment_type in appointment_types], total=total)
|
total= self.db.query(MasterAppointmentTypes).count()
|
||||||
return response
|
response = CommonResponse(data=[MasterAppointmentTypeResponse(**appointment_type.__dict__.copy()) for appointment_type in appointment_types], total=total)
|
||||||
|
return response
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error getting master appointment types: {e}")
|
||||||
|
raise e
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
def is_appointment_type_exists(self, appointment_type: MasterAppointmentTypeBase):
|
def is_appointment_type_exists(self, appointment_type: MasterAppointmentTypeBase):
|
||||||
existing_appointment_type = self.db.query(MasterAppointmentTypes).filter(MasterAppointmentTypes.type == appointment_type.type.lower()).first()
|
existing_appointment_type = self.db.query(MasterAppointmentTypes).filter(MasterAppointmentTypes.type == appointment_type.type.lower()).first()
|
||||||
return existing_appointment_type
|
return existing_appointment_type
|
||||||
|
|
||||||
async def create_master_appointment_type(self, appointment_type: MasterAppointmentTypeBase):
|
async def create_master_appointment_type(self, appointment_type: MasterAppointmentTypeBase):
|
||||||
|
try:
|
||||||
|
# get existing appointment type
|
||||||
|
existing_appointment_type = self.is_appointment_type_exists(appointment_type)
|
||||||
|
|
||||||
# get existing appointment type
|
if existing_appointment_type:
|
||||||
existing_appointment_type = self.is_appointment_type_exists(appointment_type)
|
return
|
||||||
|
|
||||||
if existing_appointment_type:
|
appointment_type.type = appointment_type.type.lower()
|
||||||
|
|
||||||
|
appointment_type = MasterAppointmentTypes(**appointment_type.model_dump())
|
||||||
|
self.db.add(appointment_type)
|
||||||
|
self.db.commit()
|
||||||
return
|
return
|
||||||
|
except Exception as e:
|
||||||
appointment_type.type = appointment_type.type.lower()
|
self.logger.error(f"Error creating master appointment type: {e}")
|
||||||
|
raise e
|
||||||
appointment_type = MasterAppointmentTypes(**appointment_type.model_dump())
|
finally:
|
||||||
self.db.add(appointment_type)
|
self.db.close()
|
||||||
self.db.commit()
|
|
||||||
return
|
|
||||||
|
|
||||||
async def delete_master_appointment_type(self, appointment_type_id: int):
|
async def delete_master_appointment_type(self, appointment_type_id: int):
|
||||||
appointment_type = self.db.query(MasterAppointmentTypes).filter(MasterAppointmentTypes.id == appointment_type_id).first()
|
try:
|
||||||
|
appointment_type = self.db.query(MasterAppointmentTypes).filter(MasterAppointmentTypes.id == appointment_type_id).first()
|
||||||
|
|
||||||
if appointment_type is None:
|
if appointment_type is None:
|
||||||
raise ResourceNotFoundException("Appointment type not found")
|
raise ResourceNotFoundException("Appointment type not found")
|
||||||
|
|
||||||
appointment_type.soft_delete(self.db)
|
appointment_type.soft_delete(self.db)
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
return
|
return
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error deleting master appointment type: {e}")
|
||||||
|
raise e
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def update_master_appointment_type(self, appointment_type_id: int, appointment_type: MasterAppointmentTypeBase):
|
async def update_master_appointment_type(self, appointment_type_id: int, appointment_type: MasterAppointmentTypeBase):
|
||||||
appointment_type_db = self.db.query(MasterAppointmentTypes).filter(MasterAppointmentTypes.id == appointment_type_id).first()
|
try:
|
||||||
|
appointment_type_db = self.db.query(MasterAppointmentTypes).filter(MasterAppointmentTypes.id == appointment_type_id).first()
|
||||||
|
|
||||||
if appointment_type_db is None:
|
if appointment_type_db is None:
|
||||||
raise ResourceNotFoundException("Appointment type not found")
|
raise ResourceNotFoundException("Appointment type not found")
|
||||||
|
|
||||||
# get existing appointment type
|
# get existing appointment type
|
||||||
existing_appointment_type = self.is_appointment_type_exists(appointment_type)
|
existing_appointment_type = self.is_appointment_type_exists(appointment_type)
|
||||||
|
|
||||||
if existing_appointment_type and existing_appointment_type.id != appointment_type_id:
|
if existing_appointment_type and existing_appointment_type.id != appointment_type_id:
|
||||||
raise ResourceNotFoundException("Appointment type already exists")
|
raise ResourceNotFoundException("Appointment type already exists")
|
||||||
|
|
||||||
appointment_type_db.type = appointment_type.type
|
appointment_type_db.type = appointment_type.type
|
||||||
|
|
||||||
self.db.add(appointment_type_db)
|
self.db.add(appointment_type_db)
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
return
|
return
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error updating master appointment type: {e}")
|
||||||
|
raise e
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
@ -186,6 +186,8 @@ class StripeServices:
|
||||||
except stripe.error.StripeError as e:
|
except stripe.error.StripeError as e:
|
||||||
self.logger.error(f"Error creating checkout session: {e}")
|
self.logger.error(f"Error creating checkout session: {e}")
|
||||||
raise
|
raise
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
|
|
||||||
async def handle_webhook(self, request: Request):
|
async def handle_webhook(self, request: Request):
|
||||||
|
|
@ -212,6 +214,8 @@ class StripeServices:
|
||||||
except stripe.error.SignatureVerificationError as e:
|
except stripe.error.SignatureVerificationError as e:
|
||||||
self.logger.error(f"Invalid signature: {e}")
|
self.logger.error(f"Invalid signature: {e}")
|
||||||
raise
|
raise
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def update_payment_log(self, unique_clinic_id:str, clinic_id:int):
|
async def update_payment_log(self, unique_clinic_id:str, clinic_id:int):
|
||||||
try:
|
try:
|
||||||
|
|
@ -227,4 +231,6 @@ class StripeServices:
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(f"Error updating payment log: {e}")
|
self.logger.error(f"Error updating payment log: {e}")
|
||||||
raise
|
raise
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
@ -173,6 +173,7 @@ class UserServices:
|
||||||
DBExceptionHandler.handle_exception(e, context="creating user")
|
DBExceptionHandler.handle_exception(e, context="creating user")
|
||||||
finally:
|
finally:
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
|
|
||||||
async def get_user(self, user_id) -> UserResponse:
|
async def get_user(self, user_id) -> UserResponse:
|
||||||
|
|
@ -205,88 +206,113 @@ class UserServices:
|
||||||
# Return the response as a dictionary
|
# Return the response as a dictionary
|
||||||
return user_response.model_dump()
|
return user_response.model_dump()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Use the centralized exception handler
|
|
||||||
from twillio.exceptions.db_exceptions import DBExceptionHandler
|
|
||||||
DBExceptionHandler.handle_exception(e, context="getting user")
|
DBExceptionHandler.handle_exception(e, context="getting user")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def get_users(self, limit:int, offset:int, search:str):
|
async def get_users(self, limit:int, offset:int, search:str):
|
||||||
query = self.db.query(Users)
|
try:
|
||||||
if search:
|
query = self.db.query(Users)
|
||||||
query = query.filter(
|
if search:
|
||||||
or_(
|
query = query.filter(
|
||||||
Users.username.contains(search),
|
or_(
|
||||||
Users.email.contains(search),
|
Users.username.contains(search),
|
||||||
|
Users.email.contains(search),
|
||||||
Users.clinicRole.contains(search),
|
Users.clinicRole.contains(search),
|
||||||
Users.userType.contains(search)
|
Users.userType.contains(search)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
users = query.limit(limit).offset(offset).all()
|
users = query.limit(limit).offset(offset).all()
|
||||||
|
|
||||||
total = self.db.query(Users).count()
|
total = self.db.query(Users).count()
|
||||||
|
|
||||||
response = CommonResponse(data=[UserResponse(**user.__dict__.copy()) for user in users], total=total)
|
response = CommonResponse(data=[UserResponse(**user.__dict__.copy()) for user in users], total=total)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
except Exception as e:
|
||||||
|
DBExceptionHandler.handle_exception(e, context="getting users")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def get_user_by_email(self, email: str) -> UserResponse:
|
async def get_user_by_email(self, email: str) -> UserResponse:
|
||||||
user = self.db.query(Users).filter(Users.email == email.lower()).first()
|
try:
|
||||||
|
user = self.db.query(Users).filter(Users.email == email.lower()).first()
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
logger.error("User not found")
|
logger.error("User not found")
|
||||||
raise ResourceNotFoundException("User not found")
|
raise ResourceNotFoundException("User not found")
|
||||||
|
|
||||||
user_dict = user.__dict__.copy()
|
user_dict = user.__dict__.copy()
|
||||||
|
|
||||||
user_response = UserResponse(**user_dict)
|
user_response = UserResponse(**user_dict)
|
||||||
|
|
||||||
return user_response
|
return user_response
|
||||||
|
except Exception as e:
|
||||||
|
DBExceptionHandler.handle_exception(e, context="getting user by email")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def update_user(self, admin_id:int|None, user_id: int, user_data: UserUpdate) -> UserResponse:
|
async def update_user(self, admin_id:int|None, user_id: int, user_data: UserUpdate) -> UserResponse:
|
||||||
# Check admin authorization if admin_id is provided
|
try:
|
||||||
if admin_id:
|
# Check admin authorization if admin_id is provided
|
||||||
admin = self.db.query(Users).filter(Users.id == admin_id).first()
|
if admin_id:
|
||||||
if not admin:
|
admin = self.db.query(Users).filter(Users.id == admin_id).first()
|
||||||
logger.error("Admin not found")
|
if not admin:
|
||||||
raise ResourceNotFoundException("Admin not found")
|
logger.error("Admin not found")
|
||||||
|
raise ResourceNotFoundException("Admin not found")
|
||||||
# Only check admin type if admin_id was provided
|
|
||||||
if admin.userType != UserType.SUPER_ADMIN:
|
# Only check admin type if admin_id was provided
|
||||||
logger.error("User is not authorized to perform this action")
|
if admin.userType != UserType.SUPER_ADMIN:
|
||||||
raise UnauthorizedException("User is not authorized to perform this action")
|
logger.error("User is not authorized to perform this action")
|
||||||
|
raise UnauthorizedException("User is not authorized to perform this action")
|
||||||
|
|
||||||
# Find the user to update
|
# Find the user to update
|
||||||
user = self.db.query(Users).filter(Users.id == user_id).first()
|
user = self.db.query(Users).filter(Users.id == user_id).first()
|
||||||
if not user:
|
if not user:
|
||||||
logger.error("User not found")
|
logger.error("User not found")
|
||||||
raise ResourceNotFoundException("User not found")
|
raise ResourceNotFoundException("User not found")
|
||||||
|
|
||||||
# Update only the fields that were provided
|
# Update only the fields that were provided
|
||||||
update_data = user_data.model_dump(exclude_unset=True)
|
update_data = user_data.model_dump(exclude_unset=True)
|
||||||
for key, value in update_data.items():
|
for key, value in update_data.items():
|
||||||
setattr(user, key, value)
|
setattr(user, key, value)
|
||||||
|
|
||||||
self.db.add(user)
|
self.db.add(user)
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
self.db.refresh(user)
|
self.db.refresh(user)
|
||||||
|
|
||||||
# Return properly serialized response
|
# Return properly serialized response
|
||||||
return UserResponse.model_validate(user)
|
return UserResponse.model_validate(user)
|
||||||
|
except Exception as e:
|
||||||
|
DBExceptionHandler.handle_exception(e, context="updating user")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def delete_user(self, user_id: int):
|
async def delete_user(self, user_id: int):
|
||||||
user = self.db.query(Users).filter(Users.id == user_id).first()
|
try:
|
||||||
|
user = self.db.query(Users).filter(Users.id == user_id).first()
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
logger.error("User not found")
|
logger.error("User not found")
|
||||||
raise ResourceNotFoundException("User not found")
|
raise ResourceNotFoundException("User not found")
|
||||||
|
|
||||||
# Use the soft_delete method from CustomBase
|
# Use the soft_delete method from CustomBase
|
||||||
user.soft_delete(self.db)
|
user.soft_delete(self.db)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
DBExceptionHandler.handle_exception(e, context="deleting user")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def get_super_admins(self):
|
async def get_super_admins(self):
|
||||||
return self.db.query(Users).filter(Users.userType == UserType.SUPER_ADMIN).all()
|
try:
|
||||||
|
return self.db.query(Users).filter(Users.userType == UserType.SUPER_ADMIN).all()
|
||||||
|
except Exception as e:
|
||||||
|
DBExceptionHandler.handle_exception(e, context="getting super admins")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def _send_emails_to_admins(self, clinic_name):
|
async def _send_emails_to_admins(self, clinic_name):
|
||||||
"""Helper method to send emails to all super admins"""
|
"""Helper method to send emails to all super admins"""
|
||||||
|
|
@ -300,12 +326,19 @@ class UserServices:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Log the error but don't interrupt the main flow
|
# Log the error but don't interrupt the main flow
|
||||||
logger.error(f"Error sending admin emails: {str(e)}")
|
logger.error(f"Error sending admin emails: {str(e)}")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def create_payment_link(self, user_id: int):
|
async def create_payment_link(self, user_id: int):
|
||||||
user = self.db.query(Users).filter(Users.id == user_id).first()
|
try:
|
||||||
|
user = self.db.query(Users).filter(Users.id == user_id).first()
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
logger.error("User not found")
|
logger.error("User not found")
|
||||||
raise ResourceNotFoundException("User not found")
|
raise ResourceNotFoundException("User not found")
|
||||||
|
|
||||||
return self.stripe_service.create_payment_link(user_id)
|
return self.stripe_service.create_payment_link(user_id)
|
||||||
|
except Exception as e:
|
||||||
|
DBExceptionHandler.handle_exception(e, context="creating payment link")
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
Loading…
Reference in New Issue