feat: user routes
fix: global delete filter refactor: user update schema
This commit is contained in:
parent
8d8f205eb1
commit
c235196990
|
|
@ -5,7 +5,7 @@ from fastapi.security import HTTPBearer
|
||||||
# Import the security scheme
|
# Import the security scheme
|
||||||
bearer_scheme = HTTPBearer(scheme_name="Bearer Authentication")
|
bearer_scheme = HTTPBearer(scheme_name="Bearer Authentication")
|
||||||
|
|
||||||
from .endpoints import clinics, doctors, calender, appointments, patients, admin, auth, s3
|
from .endpoints import clinics, doctors, calender, appointments, patients, admin, auth, s3, users
|
||||||
|
|
||||||
api_router = APIRouter()
|
api_router = APIRouter()
|
||||||
# api_router.include_router(twilio.router, prefix="/twilio")
|
# api_router.include_router(twilio.router, prefix="/twilio")
|
||||||
|
|
@ -21,3 +21,4 @@ api_router.include_router(
|
||||||
tags=["admin"])
|
tags=["admin"])
|
||||||
api_router.include_router(auth.router, prefix="/auth", tags=["auth"])
|
api_router.include_router(auth.router, prefix="/auth", tags=["auth"])
|
||||||
api_router.include_router(s3.router, dependencies=[Depends(auth_required)], prefix="/s3", tags=["s3"])
|
api_router.include_router(s3.router, dependencies=[Depends(auth_required)], prefix="/s3", tags=["s3"])
|
||||||
|
api_router.include_router(users.router, prefix="/users", tags=["users"], dependencies=[Depends(auth_required)])
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
from fastapi import APIRouter, Request, Depends
|
||||||
|
|
||||||
|
from middleware.auth_dependency import auth_required
|
||||||
|
from services.userServices import UserServices
|
||||||
|
from schemas.ApiResponse import ApiResponse
|
||||||
|
from schemas.UpdateSchemas import UserUpdate
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
@router.get("/")
|
||||||
|
async def get_users():
|
||||||
|
user = await UserServices().get_users()
|
||||||
|
return ApiResponse(
|
||||||
|
data=user,
|
||||||
|
message="User fetched successfully"
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.get("/me")
|
||||||
|
async def get_user(request: Request):
|
||||||
|
user_id = request.state.user["id"]
|
||||||
|
user = await UserServices().get_user(user_id)
|
||||||
|
return ApiResponse(
|
||||||
|
data=user,
|
||||||
|
message="User fetched successfully"
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.get("/{user_id}")
|
||||||
|
async def get_user(request: Request, user_id: int):
|
||||||
|
user = await UserServices().get_user(user_id)
|
||||||
|
return ApiResponse(
|
||||||
|
data=user,
|
||||||
|
message="User fetched successfully"
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.delete("/")
|
||||||
|
async def delete_user(request: Request):
|
||||||
|
user_id = request.state.user["id"]
|
||||||
|
await UserServices().delete_user(user_id)
|
||||||
|
return ApiResponse(
|
||||||
|
data="OK",
|
||||||
|
message="User deleted successfully"
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.put("/")
|
||||||
|
async def update_user(request: Request, user_data: UserUpdate):
|
||||||
|
user_id = request.state.user["id"]
|
||||||
|
user = await UserServices().update_user(user_id, user_data)
|
||||||
|
return ApiResponse(
|
||||||
|
data=user,
|
||||||
|
message="User updated successfully"
|
||||||
|
)
|
||||||
|
|
||||||
|
@router.put("/{user_id}")
|
||||||
|
async def update_user(request: Request, user_id: int, user_data: UserUpdate):
|
||||||
|
user = await UserServices().update_user(user_id, user_data)
|
||||||
|
return ApiResponse(
|
||||||
|
data=user,
|
||||||
|
message="User updated successfully"
|
||||||
|
)
|
||||||
|
|
@ -22,26 +22,22 @@ class CustomBase:
|
||||||
session.add(self)
|
session.add(self)
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
# Global filter for deleted records
|
# Global filter for deleted records
|
||||||
@staticmethod
|
@event.listens_for(SessionLocal, "do_orm_execute")
|
||||||
@event.listens_for(Query, "before_compile", retval=True)
|
def _add_filtering_criteria(execute_state):
|
||||||
def _filter_deleted(query):
|
if (
|
||||||
# Skip filtering if this query explicitly asks to include deleted items
|
execute_state.is_select
|
||||||
for option in query._with_options:
|
and not execute_state.execution_options.get("include_deleted", False)
|
||||||
if getattr(option, 'name', None) == 'include_deleted':
|
):
|
||||||
return query
|
# Check if any of the entities inherit from CustomBase
|
||||||
|
for entity in execute_state.statement.column_descriptions:
|
||||||
# Find entities that inherit from CustomBase
|
entity_class = entity.get("entity", None)
|
||||||
for entity in query._entities:
|
if entity_class and issubclass(entity_class, CustomBase):
|
||||||
if hasattr(entity, 'entity_zero'):
|
# Add filter condition to exclude soft-deleted records
|
||||||
entity_zero = entity.entity_zero
|
execute_state.statement = execute_state.statement.filter(
|
||||||
if hasattr(entity_zero, 'mapper') and entity_zero.mapper:
|
entity_class.deleted_at.is_(None)
|
||||||
mapper = entity_zero.mapper
|
)
|
||||||
if issubclass(mapper.class_, CustomBase):
|
break
|
||||||
# Apply filter for this entity
|
|
||||||
query = query.filter(mapper.class_.deleted_at.is_(None))
|
|
||||||
|
|
||||||
return query
|
|
||||||
|
|
||||||
# Option to include deleted records
|
# Option to include deleted records
|
||||||
class IncludeDeleted(object):
|
class IncludeDeleted(object):
|
||||||
|
|
|
||||||
|
|
@ -36,3 +36,11 @@ class AppointmentUpdate(BaseModel):
|
||||||
class CalendarUpdate(BaseModel):
|
class CalendarUpdate(BaseModel):
|
||||||
doc_id: Optional[int] = None
|
doc_id: Optional[int] = None
|
||||||
rrule: Optional[str] = None
|
rrule: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
|
class UserUpdate(BaseModel):
|
||||||
|
username: Optional[str] = None
|
||||||
|
clinicRole: Optional[ClinicUserRoles] = None
|
||||||
|
userType: Optional[UserType] = None
|
||||||
|
profile_pic: Optional[str] = None
|
||||||
|
password: Optional[str] = None
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ from exceptions.validation_exception import ValidationException
|
||||||
from schemas.ResponseSchemas import UserResponse
|
from schemas.ResponseSchemas import UserResponse
|
||||||
from models import Clinics
|
from models import Clinics
|
||||||
from enums.enums import ClinicStatus
|
from enums.enums import ClinicStatus
|
||||||
|
from schemas.UpdateSchemas import UserUpdate
|
||||||
|
from exceptions.unauthorized_exception import UnauthorizedException
|
||||||
from utils.password_utils import hash_password
|
from utils.password_utils import hash_password
|
||||||
from schemas.CreateSchemas import UserCreate
|
from schemas.CreateSchemas import UserCreate
|
||||||
from exceptions.resource_not_found_exception import ResourceNotFoundException
|
from exceptions.resource_not_found_exception import ResourceNotFoundException
|
||||||
|
|
@ -118,6 +120,23 @@ class UserServices:
|
||||||
|
|
||||||
return user_response
|
return user_response
|
||||||
|
|
||||||
|
def get_users(self, limit:int, offset:int, search:str):
|
||||||
|
query = self.db.query(Users)
|
||||||
|
if search:
|
||||||
|
query = query.filter(
|
||||||
|
or_(
|
||||||
|
Users.username.contains(search),
|
||||||
|
Users.email.contains(search),
|
||||||
|
Users.clinicRole.contains(search),
|
||||||
|
Users.userType.contains(search)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
users = query.limit(limit).offset(offset).all()
|
||||||
|
|
||||||
|
user_response = [UserResponse(**user.__dict__.copy()) for user in users]
|
||||||
|
|
||||||
|
return user_response
|
||||||
|
|
||||||
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()
|
user = self.db.query(Users).filter(Users.email == email.lower()).first()
|
||||||
|
|
||||||
|
|
@ -131,8 +150,44 @@ class UserServices:
|
||||||
|
|
||||||
return user_response
|
return user_response
|
||||||
|
|
||||||
def update_user(self, user_id, user):
|
def update_user(self, admin_id:int|None, user_id: int, user_data: UserUpdate):
|
||||||
|
|
||||||
|
if admin_id:
|
||||||
|
admin = self.db.query(Users).filter(Users.id == admin_id).first()
|
||||||
|
|
||||||
|
if not admin:
|
||||||
|
logger.error("Admin not found")
|
||||||
|
raise ResourceNotFoundException("Admin not found")
|
||||||
|
|
||||||
|
if admin.userType != UserType.ADMIN:
|
||||||
|
logger.error("User is not authorized to perform this action")
|
||||||
|
raise UnauthorizedException("User is not authorized to perform this action")
|
||||||
|
|
||||||
|
user = self.db.query(Users).filter(Users.id == user_id).first()
|
||||||
|
|
||||||
|
if not user:
|
||||||
|
logger.error("User not found")
|
||||||
|
raise ResourceNotFoundException("User not found")
|
||||||
|
|
||||||
|
user.username = user_data.username
|
||||||
|
user.clinicRole = user_data.clinicRole
|
||||||
|
user.userType = user_data.userType
|
||||||
|
user.profile_pic = user_data.profile_pic
|
||||||
|
|
||||||
|
self.db.add(user)
|
||||||
|
self.db.commit()
|
||||||
|
|
||||||
return user
|
return user
|
||||||
|
|
||||||
def delete_user(self, user_id):
|
def delete_user(self, user_id: int):
|
||||||
return user
|
user = self.db.query(Users).filter(Users.id == user_id).first()
|
||||||
|
|
||||||
|
if not user:
|
||||||
|
logger.error("User not found")
|
||||||
|
raise ResourceNotFoundException("User not found")
|
||||||
|
|
||||||
|
# Use the soft_delete method from CustomBase
|
||||||
|
user.soft_delete(self.db)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
Loading…
Reference in New Issue