331 lines
10 KiB
Python
331 lines
10 KiB
Python
"""
|
|
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",
|
|
)
|