o2o-castad-backend/app/user/schemas/user_schema.py

131 lines
4.7 KiB
Python

"""
User 모듈 Pydantic 스키마 정의
API 요청/응답 검증을 위한 스키마들입니다.
"""
from datetime import datetime
from typing import Optional
from pydantic import BaseModel, Field
# =============================================================================
# 카카오 OAuth 스키마
# =============================================================================
class KakaoLoginResponse(BaseModel):
"""카카오 로그인 URL 응답"""
auth_url: str = Field(..., description="카카오 인증 페이지 URL")
class KakaoCallbackRequest(BaseModel):
"""카카오 콜백 요청 (인가 코드)"""
code: str = Field(..., min_length=1, description="카카오 인가 코드")
# =============================================================================
# JWT 토큰 스키마
# =============================================================================
class TokenResponse(BaseModel):
"""토큰 발급 응답"""
access_token: str = Field(..., description="액세스 토큰")
refresh_token: str = Field(..., description="리프레시 토큰")
token_type: str = Field(default="Bearer", description="토큰 타입")
expires_in: int = Field(..., description="액세스 토큰 만료 시간 (초)")
class AccessTokenResponse(BaseModel):
"""액세스 토큰 갱신 응답"""
access_token: str = Field(..., description="액세스 토큰")
token_type: str = Field(default="Bearer", description="토큰 타입")
expires_in: int = Field(..., description="액세스 토큰 만료 시간 (초)")
class RefreshTokenRequest(BaseModel):
"""토큰 갱신 요청"""
refresh_token: str = Field(..., min_length=1, description="리프레시 토큰")
# =============================================================================
# 사용자 정보 스키마
# =============================================================================
class UserResponse(BaseModel):
"""사용자 정보 응답"""
id: int = Field(..., description="사용자 ID")
kakao_id: int = Field(..., description="카카오 회원번호")
email: Optional[str] = Field(None, description="이메일")
nickname: Optional[str] = Field(None, description="닉네임")
profile_image_url: Optional[str] = Field(None, description="프로필 이미지 URL")
thumbnail_image_url: Optional[str] = Field(None, description="썸네일 이미지 URL")
is_active: bool = Field(..., description="계정 활성화 상태")
is_admin: bool = Field(..., description="관리자 여부")
last_login_at: Optional[datetime] = Field(None, description="마지막 로그인 일시")
created_at: datetime = Field(..., description="가입 일시")
model_config = {"from_attributes": True}
class UserBriefResponse(BaseModel):
"""사용자 간략 정보 (토큰 응답에 포함)"""
id: int = Field(..., description="사용자 ID")
nickname: Optional[str] = Field(None, description="닉네임")
email: Optional[str] = Field(None, description="이메일")
profile_image_url: Optional[str] = Field(None, description="프로필 이미지 URL")
is_new_user: bool = Field(..., description="신규 가입 여부")
model_config = {"from_attributes": True}
class LoginResponse(BaseModel):
"""로그인 응답 (토큰 + 사용자 정보)"""
access_token: str = Field(..., description="액세스 토큰")
refresh_token: str = Field(..., description="리프레시 토큰")
token_type: str = Field(default="Bearer", description="토큰 타입")
expires_in: int = Field(..., description="액세스 토큰 만료 시간 (초)")
user: UserBriefResponse = Field(..., description="사용자 정보")
# =============================================================================
# 내부 사용 스키마 (카카오 API 응답 파싱)
# =============================================================================
class KakaoTokenResponse(BaseModel):
"""카카오 토큰 응답 (내부 사용)"""
access_token: str
token_type: str
refresh_token: Optional[str] = None
expires_in: int
scope: Optional[str] = None
refresh_token_expires_in: Optional[int] = None
class KakaoProfile(BaseModel):
"""카카오 프로필 정보 (내부 사용)"""
nickname: Optional[str] = None
profile_image_url: Optional[str] = None
thumbnail_image_url: Optional[str] = None
is_default_image: Optional[bool] = None
class KakaoAccount(BaseModel):
"""카카오 계정 정보 (내부 사용)"""
email: Optional[str] = None
profile: Optional[KakaoProfile] = None
class KakaoUserInfo(BaseModel):
"""카카오 사용자 정보 (내부 사용)"""
id: int
kakao_account: Optional[KakaoAccount] = None