bookmyservice-ums / app /routers /guest_router.py
MukeshKapoor25's picture
feat(profiles): add default pet/guest functionality and refactor address model
0f81784
from fastapi import APIRouter, HTTPException, Depends, status
from fastapi.security import HTTPBearer
from app.models.guest_model import GuestModel
from app.schemas.guest_schema import (
GuestCreateRequest,
GuestUpdateRequest,
GuestResponse,
GuestListResponse,
GuestDeleteResponse,
SetDefaultGuestRequest
)
from app.utils.jwt import verify_token
from typing import Dict, Any
import logging
logger = logging.getLogger(__name__)
router = APIRouter()
security = HTTPBearer()
async def get_current_user(token: str = Depends(security)) -> Dict[str, Any]:
"""
Dependency to get current authenticated user from JWT token
"""
try:
payload = verify_token(token.credentials)
if not payload:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid or expired token"
)
return payload
except Exception as e:
logger.error(f"Token verification failed: {str(e)}")
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid or expired token"
)
@router.get("/guests", response_model=GuestListResponse)
async def get_user_guests(
current_user: Dict[str, Any] = Depends(get_current_user)
):
"""
Get all guests for a specific user.
- **customer_id**: ID of the user
- Returns list of guests with total count
"""
try:
# Verify user can only access their own guests
customer_id=current_user.get("sub")
guests_data = await GuestModel.get_user_guests(customer_id)
guests = [GuestResponse(**guest) for guest in guests_data]
return GuestListResponse(
guests=guests,
total_count=len(guests)
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Error getting guests for user {customer_id}: {str(e)}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to retrieve guests"
)
@router.post("/guests", response_model=GuestResponse, status_code=status.HTTP_201_CREATED)
async def create_guest(
guest_data: GuestCreateRequest,
current_user: Dict[str, Any] = Depends(get_current_user)
):
"""
Create a new guest profile for a user.
- **customer_id**: ID of the user creating the guest profile
- **guest_data**: Guest information including name, contact details, etc.
- Returns the created guest profile
"""
try:
# Verify user can only create guests for themselves
customer_id=current_user.get("sub")
# Create guest in database
guest_id=await GuestModel.create_guest(customer_id,guest_data.dict())
if not guest_id:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to create guest profile"
)
# Retrieve and return the created guest
created_guest = await GuestModel.get_guest_by_id(customer_id, guest_id)
if not created_guest:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Guest created but failed to retrieve"
)
return GuestResponse(**created_guest)
except HTTPException:
raise
except Exception as e:
logger.error(f"Error creating guest for user {customer_id}: {str(e)}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to create guest profile"
)
@router.get("/guests/default", response_model=GuestResponse)
async def get_default_guest(
current_user: Dict[str, Any] = Depends(get_current_user)
):
"""Get the default guest for the current user"""
try:
customer_id = current_user.get("sub")
default_guest = await GuestModel.get_default_guest(customer_id)
if not default_guest:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Default guest not set"
)
return GuestResponse(**default_guest)
except HTTPException:
raise
except Exception as e:
logger.error(f"Error getting default guest for user {customer_id}: {str(e)}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to retrieve default guest"
)
@router.post("/guests/set-default", response_model=GuestResponse)
async def set_default_guest(
req: SetDefaultGuestRequest,
current_user: Dict[str, Any] = Depends(get_current_user)
):
"""Set a guest as default for the current user"""
try:
customer_id = current_user.get("sub")
# Verify guest exists and belongs to user
existing_guest = await GuestModel.get_guest_by_id(customer_id, req.guest_id)
if not existing_guest:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Guest not found"
)
if existing_guest.get("customer_id") != customer_id:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Access denied. This guest doesn't belong to you."
)
success = await GuestModel.set_default_guest(customer_id, req.guest_id)
if not success:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to set default guest"
)
updated_guest = await GuestModel.get_guest_by_id(customer_id, req.guest_id)
if not updated_guest:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Default set but failed to retrieve guest"
)
return GuestResponse(**updated_guest)
except HTTPException:
raise
except Exception as e:
logger.error(f"Error setting default guest {req.guest_id} for user {customer_id}: {str(e)}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to set default guest"
)
@router.put("/guests/{guest_id}", response_model=GuestResponse)
async def update_guest(
guest_id: str,
guest_data: GuestUpdateRequest,
current_user: Dict[str, Any] = Depends(get_current_user)
):
"""
Update an existing guest profile.
- **customer_id**: ID of the user who owns the guest profile
- **guest_id**: ID of the guest to update
- **guest_data**: Updated guest information
- Returns the updated guest profile
"""
try:
# Verify user can only update their own guests
customer_id=current_user.get("sub")
# Check if guest exists and belongs to user
existing_guest = await GuestModel.get_guest_by_id(customer_id, guest_id)
if not existing_guest:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Guest not found"
)
if existing_guest.get("customer_id") != customer_id:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Access denied. This guest doesn't belong to you."
)
# Prepare update fields (only include non-None values)
update_fields = {}
for field, value in guest_data.dict(exclude_unset=True).items():
if value is not None:
if hasattr(value, 'value'): # Handle enum values
update_fields[field] = value.value
else:
update_fields[field] = value
if not update_fields:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="No valid fields provided for update"
)
# Update guest in database
success = await GuestModel.update_guest(customer_id, guest_id, update_fields)
if not success:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to update guest profile"
)
# Retrieve and return updated guest
updated_guest = await GuestModel.get_guest_by_id(customer_id, guest_id)
if not updated_guest:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Guest updated but failed to retrieve"
)
return GuestResponse(**updated_guest)
except HTTPException:
raise
except Exception as e:
logger.error(f"Error updating guest {guest_id} for user {customer_id}: {str(e)}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to update guest profile"
)
@router.delete("/guests/{guest_id}", response_model=GuestDeleteResponse)
async def delete_guest(
guest_id: str,
current_user: Dict[str, Any] = Depends(get_current_user)
):
"""
Delete a guest profile.
- **customer_id**: ID of the user who owns the guest profile
- **guest_id**: ID of the guest to delete
- Returns confirmation of deletion
"""
try:
# Verify user can only delete their own guests
customer_id=current_user.get("sub")
# Check if guest exists and belongs to user
existing_guest = await GuestModel.get_guest_by_id(customer_id, guest_id)
if not existing_guest:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="Guest not found"
)
if existing_guest.get("customer_id") != customer_id:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Access denied. This guest doesn't belong to you."
)
# Delete guest from database
success = await GuestModel.delete_guest(customer_id, guest_id)
if not success:
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to delete guest profile"
)
guest_name = existing_guest.get('first_name', 'Guest')
if existing_guest.get('last_name'):
guest_name += f" {existing_guest.get('last_name')}"
return GuestDeleteResponse(
message=f"Guest '{guest_name}' has been successfully deleted",
guest_id=guest_id
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Error deleting guest {guest_id} for user {customer_id}: {str(e)}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Failed to delete guest profile"
)