""" Social Media Exceptions 소셜 미디어 연동 관련 예외 클래스를 정의합니다. """ from fastapi import status class SocialException(Exception): """소셜 미디어 기본 예외""" def __init__( self, message: str, status_code: int = status.HTTP_500_INTERNAL_SERVER_ERROR, code: str = "SOCIAL_ERROR", ): self.message = message self.status_code = status_code self.code = code super().__init__(self.message) # ============================================================================= # OAuth 관련 예외 # ============================================================================= class OAuthException(SocialException): """OAuth 관련 예외 기본 클래스""" def __init__( self, message: str = "OAuth 인증 중 오류가 발생했습니다.", status_code: int = status.HTTP_401_UNAUTHORIZED, code: str = "OAUTH_ERROR", ): super().__init__(message, status_code, code) class InvalidStateError(OAuthException): """CSRF state 토큰 불일치""" def __init__(self, message: str = "유효하지 않은 인증 세션입니다. 다시 시도해주세요."): super().__init__( message=message, status_code=status.HTTP_400_BAD_REQUEST, code="INVALID_STATE", ) class OAuthStateExpiredError(OAuthException): """OAuth state 토큰 만료""" def __init__(self, message: str = "인증 세션이 만료되었습니다. 다시 시도해주세요."): super().__init__( message=message, status_code=status.HTTP_400_BAD_REQUEST, code="STATE_EXPIRED", ) class OAuthTokenError(OAuthException): """OAuth 토큰 교환 실패""" def __init__(self, platform: str, message: str = ""): error_message = f"{platform} 토큰 발급에 실패했습니다." if message: error_message += f" ({message})" super().__init__( message=error_message, status_code=status.HTTP_401_UNAUTHORIZED, code="TOKEN_EXCHANGE_FAILED", ) class TokenRefreshError(OAuthException): """토큰 갱신 실패""" def __init__(self, platform: str): super().__init__( message=f"{platform} 토큰 갱신에 실패했습니다. 재연동이 필요합니다.", status_code=status.HTTP_401_UNAUTHORIZED, code="TOKEN_REFRESH_FAILED", ) class OAuthCodeExchangeError(OAuthException): """OAuth 인가 코드 교환 실패""" def __init__(self, platform: str, detail: str = ""): error_message = f"{platform} 인가 코드 교환에 실패했습니다." if detail: error_message += f" ({detail})" super().__init__( message=error_message, status_code=status.HTTP_401_UNAUTHORIZED, code="CODE_EXCHANGE_FAILED", ) class OAuthTokenRefreshError(OAuthException): """OAuth 토큰 갱신 실패""" def __init__(self, platform: str, detail: str = ""): error_message = f"{platform} 토큰 갱신에 실패했습니다." if detail: error_message += f" ({detail})" super().__init__( message=error_message, status_code=status.HTTP_401_UNAUTHORIZED, code="TOKEN_REFRESH_FAILED", ) class TokenExpiredError(OAuthException): """토큰 만료""" def __init__(self, platform: str): super().__init__( message=f"{platform} 인증이 만료되었습니다. 재연동이 필요합니다.", status_code=status.HTTP_401_UNAUTHORIZED, code="TOKEN_EXPIRED", ) # ============================================================================= # 소셜 계정 관련 예외 # ============================================================================= class SocialAccountException(SocialException): """소셜 계정 관련 예외 기본 클래스""" pass class SocialAccountNotFoundError(SocialAccountException): """연동된 계정을 찾을 수 없음""" def __init__(self, platform: str = ""): message = f"{platform} 계정이 연동되어 있지 않습니다." if platform else "연동된 소셜 계정이 없습니다." super().__init__( message=message, status_code=status.HTTP_404_NOT_FOUND, code="SOCIAL_ACCOUNT_NOT_FOUND", ) class SocialAccountAlreadyExistsError(SocialAccountException): """이미 연동된 계정이 존재함""" def __init__(self, platform: str): super().__init__( message=f"이미 {platform} 계정이 연동되어 있습니다.", status_code=status.HTTP_409_CONFLICT, code="SOCIAL_ACCOUNT_EXISTS", ) # Alias for backward compatibility SocialAccountAlreadyConnectedError = SocialAccountAlreadyExistsError class SocialAccountInactiveError(SocialAccountException): """비활성화된 소셜 계정""" def __init__(self, platform: str): super().__init__( message=f"{platform} 계정이 비활성화 상태입니다. 재연동이 필요합니다.", status_code=status.HTTP_403_FORBIDDEN, code="SOCIAL_ACCOUNT_INACTIVE", ) class SocialAccountError(SocialAccountException): """소셜 계정 일반 오류""" def __init__(self, platform: str, detail: str = ""): error_message = f"{platform} 계정 처리 중 오류가 발생했습니다." if detail: error_message += f" ({detail})" super().__init__( message=error_message, status_code=status.HTTP_400_BAD_REQUEST, code="SOCIAL_ACCOUNT_ERROR", ) # ============================================================================= # 업로드 관련 예외 # ============================================================================= class UploadException(SocialException): """업로드 관련 예외 기본 클래스""" pass class UploadError(UploadException): """업로드 일반 오류""" def __init__(self, platform: str, detail: str = ""): error_message = f"{platform} 업로드 중 오류가 발생했습니다." if detail: error_message += f" ({detail})" super().__init__( message=error_message, status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, code="UPLOAD_ERROR", ) class UploadValidationError(UploadException): """업로드 유효성 검사 실패""" def __init__(self, message: str): super().__init__( message=message, status_code=status.HTTP_400_BAD_REQUEST, code="UPLOAD_VALIDATION_FAILED", ) class VideoNotFoundError(UploadException): """영상을 찾을 수 없음""" def __init__(self, video_id: int, detail: str = ""): message = f"영상을 찾을 수 없습니다. (video_id: {video_id})" if detail: message = detail super().__init__( message=message, status_code=status.HTTP_404_NOT_FOUND, code="VIDEO_NOT_FOUND", ) class VideoNotReadyError(UploadException): """영상이 준비되지 않음""" def __init__(self, video_id: int): super().__init__( message=f"영상이 아직 준비되지 않았습니다. (video_id: {video_id})", status_code=status.HTTP_400_BAD_REQUEST, code="VIDEO_NOT_READY", ) class UploadFailedError(UploadException): """업로드 실패""" def __init__(self, platform: str, message: str = ""): error_message = f"{platform} 업로드에 실패했습니다." if message: error_message += f" ({message})" super().__init__( message=error_message, status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, code="UPLOAD_FAILED", ) class UploadQuotaExceededError(UploadException): """업로드 할당량 초과""" def __init__(self, platform: str): super().__init__( message=f"{platform} 일일 업로드 할당량이 초과되었습니다.", status_code=status.HTTP_429_TOO_MANY_REQUESTS, code="UPLOAD_QUOTA_EXCEEDED", ) class UploadNotFoundError(UploadException): """업로드 기록을 찾을 수 없음""" def __init__(self, upload_id: int): super().__init__( message=f"업로드 기록을 찾을 수 없습니다. (upload_id: {upload_id})", status_code=status.HTTP_404_NOT_FOUND, code="UPLOAD_NOT_FOUND", ) # ============================================================================= # 플랫폼 API 관련 예외 # ============================================================================= class PlatformAPIError(SocialException): """플랫폼 API 호출 오류""" def __init__(self, platform: str, message: str = ""): error_message = f"{platform} API 호출 중 오류가 발생했습니다." if message: error_message += f" ({message})" super().__init__( message=error_message, status_code=status.HTTP_502_BAD_GATEWAY, code="PLATFORM_API_ERROR", ) class RateLimitError(PlatformAPIError): """API 요청 한도 초과""" def __init__(self, platform: str, retry_after: int | None = None): message = f"{platform} API 요청 한도가 초과되었습니다." if retry_after: message += f" {retry_after}초 후에 다시 시도해주세요." super().__init__( platform=platform, message=message, ) self.retry_after = retry_after self.code = "RATE_LIMIT_EXCEEDED" class UnsupportedPlatformError(SocialException): """지원하지 않는 플랫폼""" def __init__(self, platform: str): super().__init__( message=f"지원하지 않는 플랫폼입니다: {platform}", status_code=status.HTTP_400_BAD_REQUEST, code="UNSUPPORTED_PLATFORM", )