from fastapi import HTTPException, status from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from app.config import settings from typing import Optional class ListNotFoundError(HTTPException): """Raised when a list is not found.""" def __init__(self, list_id: int): super().__init__( status_code=status.HTTP_404_NOT_FOUND, detail=f"List {list_id} not found" ) class ListPermissionError(HTTPException): """Raised when a user doesn't have permission to access a list.""" def __init__(self, list_id: int, action: str = "access"): super().__init__( status_code=status.HTTP_403_FORBIDDEN, detail=f"You do not have permission to {action} list {list_id}" ) class ListCreatorRequiredError(HTTPException): """Raised when an action requires the list creator but the user is not the creator.""" def __init__(self, list_id: int, action: str): super().__init__( status_code=status.HTTP_403_FORBIDDEN, detail=f"Only the list creator can {action} list {list_id}" ) class GroupNotFoundError(HTTPException): """Raised when a group is not found.""" def __init__(self, group_id: int): super().__init__( status_code=status.HTTP_404_NOT_FOUND, detail=f"Group {group_id} not found" ) class GroupPermissionError(HTTPException): """Raised when a user doesn't have permission to perform an action in a group.""" def __init__(self, group_id: int, action: str): super().__init__( status_code=status.HTTP_403_FORBIDDEN, detail=f"You do not have permission to {action} in group {group_id}" ) class GroupMembershipError(HTTPException): """Raised when a user attempts to perform an action that requires group membership.""" def __init__(self, group_id: int, action: str = "access"): super().__init__( status_code=status.HTTP_403_FORBIDDEN, detail=f"You must be a member of group {group_id} to {action}" ) class GroupOperationError(HTTPException): """Raised when a group operation fails.""" def __init__(self, detail: str): super().__init__( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=detail ) class GroupValidationError(HTTPException): """Raised when a group operation is invalid.""" def __init__(self, detail: str): super().__init__( status_code=status.HTTP_400_BAD_REQUEST, detail=detail ) class ItemNotFoundError(HTTPException): """Raised when an item is not found.""" def __init__(self, item_id: int): super().__init__( status_code=status.HTTP_404_NOT_FOUND, detail=f"Item {item_id} not found" ) class UserNotFoundError(HTTPException): """Raised when a user is not found.""" def __init__(self, user_id: Optional[int] = None, identifier: Optional[str] = None): detail_msg = "User not found." if user_id: detail_msg = f"User with ID {user_id} not found." elif identifier: detail_msg = f"User with identifier '{identifier}' not found." super().__init__( status_code=status.HTTP_404_NOT_FOUND, detail=detail_msg ) class InvalidOperationError(HTTPException): """Raised when an operation is invalid or disallowed by business logic.""" def __init__(self, detail: str, status_code: int = status.HTTP_400_BAD_REQUEST): super().__init__( status_code=status_code, detail=detail ) class DatabaseConnectionError(HTTPException): """Raised when there is an error connecting to the database.""" def __init__(self): super().__init__( status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail=settings.DB_CONNECTION_ERROR ) class DatabaseIntegrityError(HTTPException): """Raised when a database integrity constraint is violated.""" def __init__(self): super().__init__( status_code=status.HTTP_400_BAD_REQUEST, detail=settings.DB_INTEGRITY_ERROR ) class DatabaseTransactionError(HTTPException): """Raised when a database transaction fails.""" def __init__(self): super().__init__( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=settings.DB_TRANSACTION_ERROR ) class DatabaseQueryError(HTTPException): """Raised when a database query fails.""" def __init__(self): super().__init__( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=settings.DB_QUERY_ERROR ) class OCRServiceUnavailableError(HTTPException): """Raised when the OCR service is unavailable.""" def __init__(self): super().__init__( status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail=settings.OCR_SERVICE_UNAVAILABLE ) class OCRServiceConfigError(HTTPException): """Raised when there is an error in the OCR service configuration.""" def __init__(self): super().__init__( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=settings.OCR_SERVICE_CONFIG_ERROR ) class OCRUnexpectedError(HTTPException): """Raised when there is an unexpected error in the OCR service.""" def __init__(self): super().__init__( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=settings.OCR_UNEXPECTED_ERROR ) class OCRQuotaExceededError(HTTPException): """Raised when the OCR service quota is exceeded.""" def __init__(self): super().__init__( status_code=status.HTTP_429_TOO_MANY_REQUESTS, detail=settings.OCR_QUOTA_EXCEEDED ) class InvalidFileTypeError(HTTPException): """Raised when an invalid file type is uploaded for OCR.""" def __init__(self): super().__init__( status_code=status.HTTP_400_BAD_REQUEST, detail=settings.OCR_INVALID_FILE_TYPE.format(types=", ".join(settings.ALLOWED_IMAGE_TYPES)) ) class FileTooLargeError(HTTPException): """Raised when an uploaded file exceeds the size limit.""" def __init__(self): super().__init__( status_code=status.HTTP_400_BAD_REQUEST, detail=settings.OCR_FILE_TOO_LARGE.format(size=settings.MAX_FILE_SIZE_MB) ) class OCRProcessingError(HTTPException): """Raised when there is an error processing the image with OCR.""" def __init__(self, detail: str): super().__init__( status_code=status.HTTP_400_BAD_REQUEST, detail=settings.OCR_PROCESSING_ERROR.format(detail=detail) ) class EmailAlreadyRegisteredError(HTTPException): """Raised when attempting to register with an email that is already in use.""" def __init__(self): super().__init__( status_code=status.HTTP_400_BAD_REQUEST, detail="Email already registered." ) class UserCreationError(HTTPException): """Raised when there is an error creating a new user.""" def __init__(self): super().__init__( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="An error occurred during user creation." ) class InviteNotFoundError(HTTPException): """Raised when an invite is not found.""" def __init__(self, invite_code: str): super().__init__( status_code=status.HTTP_404_NOT_FOUND, detail=f"Invite code {invite_code} not found" ) class InviteExpiredError(HTTPException): """Raised when an invite has expired.""" def __init__(self, invite_code: str): super().__init__( status_code=status.HTTP_410_GONE, detail=f"Invite code {invite_code} has expired" ) class InviteAlreadyUsedError(HTTPException): """Raised when an invite has already been used.""" def __init__(self, invite_code: str): super().__init__( status_code=status.HTTP_410_GONE, detail=f"Invite code {invite_code} has already been used" ) class InviteCreationError(HTTPException): """Raised when an invite cannot be created.""" def __init__(self, group_id: int): super().__init__( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to create invite for group {group_id}" ) class ListStatusNotFoundError(HTTPException): """Raised when a list's status cannot be retrieved.""" def __init__(self, list_id: int): super().__init__( status_code=status.HTTP_404_NOT_FOUND, detail=f"Status for list {list_id} not found" ) class ConflictError(HTTPException): """Raised when an optimistic lock version conflict occurs.""" def __init__(self, detail: str): super().__init__( status_code=status.HTTP_409_CONFLICT, detail=detail ) class InvalidCredentialsError(HTTPException): """Raised when login credentials are invalid.""" def __init__(self): super().__init__( status_code=status.HTTP_401_UNAUTHORIZED, detail=settings.AUTH_INVALID_CREDENTIALS, headers={settings.AUTH_HEADER_NAME: f"{settings.AUTH_HEADER_PREFIX} error=\"invalid_credentials\""} ) class NotAuthenticatedError(HTTPException): """Raised when the user is not authenticated.""" def __init__(self): super().__init__( status_code=status.HTTP_401_UNAUTHORIZED, detail=settings.AUTH_NOT_AUTHENTICATED, headers={settings.AUTH_HEADER_NAME: f"{settings.AUTH_HEADER_PREFIX} error=\"not_authenticated\""} ) class JWTError(HTTPException): """Raised when there is an error with the JWT token.""" def __init__(self, error: str): super().__init__( status_code=status.HTTP_401_UNAUTHORIZED, detail=settings.JWT_ERROR.format(error=error), headers={settings.AUTH_HEADER_NAME: f"{settings.AUTH_HEADER_PREFIX} error=\"invalid_token\""} ) class JWTUnexpectedError(HTTPException): """Raised when there is an unexpected error with the JWT token.""" def __init__(self, error: str): super().__init__( status_code=status.HTTP_401_UNAUTHORIZED, detail=settings.JWT_UNEXPECTED_ERROR.format(error=error), headers={settings.AUTH_HEADER_NAME: f"{settings.AUTH_HEADER_PREFIX} error=\"invalid_token\""} )