Files
Hotel-Booking/Backend/src/reviews/routes/favorite_routes.py
Iliyan Angelov 3d634b4fce updates
2025-12-04 01:07:34 +02:00

114 lines
6.5 KiB
Python

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from sqlalchemy import func
from ...shared.config.database import get_db
from ...security.middleware.auth import get_current_user
from ...auth.models.user import User
from ...auth.models.role import Role
from ..models.favorite import Favorite
from ...rooms.models.room import Room
from ...rooms.models.room_type import RoomType
from ..models.review import Review, ReviewStatus
router = APIRouter(prefix='/favorites', tags=['favorites'])
@router.get('/')
async def get_favorites(current_user: User=Depends(get_current_user), db: Session=Depends(get_db)):
# PERFORMANCE: Use eager-loaded role relationship if available
if hasattr(current_user, 'role') and current_user.role is not None:
role_name = current_user.role.name
else:
# Fallback: query if relationship wasn't loaded
role = db.query(Role).filter(Role.id == current_user.role_id).first()
role_name = role.name if role else 'customer'
if role_name in ['admin', 'staff', 'accountant']:
raise HTTPException(status_code=403, detail='Admin, staff, and accountant users cannot have favorites')
try:
favorites = db.query(Favorite).filter(Favorite.user_id == current_user.id).order_by(Favorite.created_at.desc()).all()
result = []
for favorite in favorites:
if not favorite.room:
continue
room = favorite.room
review_stats = db.query(func.avg(Review.rating).label('average_rating'), func.count(Review.id).label('total_reviews')).filter(Review.room_id == room.id, Review.status == ReviewStatus.approved).first()
room_dict = {'id': room.id, 'room_type_id': room.room_type_id, 'room_number': room.room_number, 'floor': room.floor, 'status': room.status.value if hasattr(room.status, 'value') else room.status, 'price': float(room.price) if room.price else 0.0, 'featured': room.featured, 'description': room.description, 'amenities': room.amenities, 'images': room.images or [], 'average_rating': round(float(review_stats.average_rating or 0), 1) if review_stats and review_stats.average_rating else None, 'total_reviews': review_stats.total_reviews or 0 if review_stats else 0}
if room.room_type:
room_dict['room_type'] = {'id': room.room_type.id, 'name': room.room_type.name, 'description': room.room_type.description, 'base_price': float(room.room_type.base_price) if room.room_type.base_price else 0.0, 'capacity': room.room_type.capacity, 'amenities': room.room_type.amenities}
favorite_dict = {'id': favorite.id, 'user_id': favorite.user_id, 'room_id': favorite.room_id, 'room': room_dict, 'created_at': favorite.created_at.isoformat() if favorite.created_at else None}
result.append(favorite_dict)
return {'status': 'success', 'data': {'favorites': result, 'total': len(result)}}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@router.post('/{room_id}')
async def add_favorite(room_id: int, current_user: User=Depends(get_current_user), db: Session=Depends(get_db)):
# PERFORMANCE: Use eager-loaded role relationship if available
if hasattr(current_user, 'role') and current_user.role is not None:
role_name = current_user.role.name
else:
# Fallback: query if relationship wasn't loaded
role = db.query(Role).filter(Role.id == current_user.role_id).first()
role_name = role.name if role else 'customer'
if role_name in ['admin', 'staff', 'accountant']:
raise HTTPException(status_code=403, detail='Admin, staff, and accountant users cannot add favorites')
try:
room = db.query(Room).filter(Room.id == room_id).first()
if not room:
raise HTTPException(status_code=404, detail='Room not found')
existing = db.query(Favorite).filter(Favorite.user_id == current_user.id, Favorite.room_id == room_id).first()
if existing:
raise HTTPException(status_code=400, detail='Room already in favorites list')
favorite = Favorite(user_id=current_user.id, room_id=room_id)
db.add(favorite)
db.commit()
db.refresh(favorite)
return {'status': 'success', 'message': 'Added to favorites list', 'data': {'favorite': favorite}}
except HTTPException:
raise
except Exception as e:
db.rollback()
raise HTTPException(status_code=500, detail=str(e))
@router.delete('/{room_id}')
async def remove_favorite(room_id: int, current_user: User=Depends(get_current_user), db: Session=Depends(get_db)):
# PERFORMANCE: Use eager-loaded role relationship if available
if hasattr(current_user, 'role') and current_user.role is not None:
role_name = current_user.role.name
else:
# Fallback: query if relationship wasn't loaded
role = db.query(Role).filter(Role.id == current_user.role_id).first()
role_name = role.name if role else 'customer'
if role_name in ['admin', 'staff', 'accountant']:
raise HTTPException(status_code=403, detail='Admin, staff, and accountant users cannot remove favorites')
try:
favorite = db.query(Favorite).filter(Favorite.user_id == current_user.id, Favorite.room_id == room_id).first()
if not favorite:
raise HTTPException(status_code=404, detail='Room not found in favorites list')
db.delete(favorite)
db.commit()
return {'status': 'success', 'message': 'Removed from favorites list'}
except HTTPException:
raise
except Exception as e:
db.rollback()
raise HTTPException(status_code=500, detail=str(e))
@router.get('/check/{room_id}')
async def check_favorite(room_id: int, current_user: User=Depends(get_current_user), db: Session=Depends(get_db)):
# PERFORMANCE: Use eager-loaded role relationship if available
if hasattr(current_user, 'role') and current_user.role is not None:
role_name = current_user.role.name
else:
# Fallback: query if relationship wasn't loaded
role = db.query(Role).filter(Role.id == current_user.role_id).first()
role_name = role.name if role else 'customer'
if role_name in ['admin', 'staff', 'accountant']:
return {'status': 'success', 'data': {'isFavorited': False}}
try:
favorite = db.query(Favorite).filter(Favorite.user_id == current_user.id, Favorite.room_id == room_id).first()
return {'status': 'success', 'data': {'isFavorited': favorite is not None}}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))