youtube bug fix, timezone 수정, lazyloading 수정 .
parent
40afe9392c
commit
e29e10eb29
|
|
@ -4,6 +4,7 @@ Social Account Service
|
|||
소셜 계정 연동 관련 비즈니스 로직을 처리합니다.
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import secrets
|
||||
from datetime import timedelta
|
||||
|
|
@ -27,10 +28,8 @@ redis_client = Redis(
|
|||
decode_responses=True,
|
||||
)
|
||||
from app.social.exceptions import (
|
||||
InvalidStateError,
|
||||
OAuthStateExpiredError,
|
||||
OAuthTokenRefreshError,
|
||||
SocialAccountAlreadyConnectedError,
|
||||
SocialAccountNotFoundError,
|
||||
TokenExpiredError,
|
||||
)
|
||||
|
|
@ -90,7 +89,7 @@ class SocialAccountService:
|
|||
await redis_client.setex(
|
||||
state_key,
|
||||
social_oauth_settings.OAUTH_STATE_TTL_SECONDS,
|
||||
str(state_data),
|
||||
json.dumps(state_data), # JSON으로 직렬화
|
||||
)
|
||||
logger.debug(f"[SOCIAL] OAuth state 저장 - key: {state_key}")
|
||||
|
||||
|
|
@ -126,9 +125,7 @@ class SocialAccountService:
|
|||
SocialAccountResponse: 연동된 소셜 계정 정보
|
||||
|
||||
Raises:
|
||||
InvalidStateError: state 토큰이 유효하지 않은 경우
|
||||
OAuthStateExpiredError: state 토큰이 만료된 경우
|
||||
SocialAccountAlreadyConnectedError: 이미 연동된 계정인 경우
|
||||
OAuthStateExpiredError: state 토큰이 만료되거나 유효하지 않은 경우
|
||||
"""
|
||||
logger.info(f"[SOCIAL] OAuth 콜백 처리 시작 - state: {state[:20]}...")
|
||||
|
||||
|
|
@ -140,8 +137,8 @@ class SocialAccountService:
|
|||
logger.warning(f"[SOCIAL] state 토큰 없음 또는 만료 - state: {state[:20]}...")
|
||||
raise OAuthStateExpiredError()
|
||||
|
||||
# state 데이터 파싱
|
||||
state_data = eval(state_data_str) # {"user_uuid": "...", "platform": "..."}
|
||||
# state 데이터 파싱 (JSON 역직렬화)
|
||||
state_data = json.loads(state_data_str)
|
||||
user_uuid = state_data["user_uuid"]
|
||||
platform = SocialPlatform(state_data["platform"])
|
||||
|
||||
|
|
@ -307,7 +304,9 @@ class SocialAccountService:
|
|||
if account.token_expires_at is None:
|
||||
should_refresh = True
|
||||
else:
|
||||
buffer_time = now() + timedelta(hours=1)
|
||||
# DB datetime은 naive, now()는 aware이므로 naive로 통일하여 비교
|
||||
current_time = now().replace(tzinfo=None)
|
||||
buffer_time = current_time + timedelta(hours=1)
|
||||
if account.token_expires_at <= buffer_time:
|
||||
should_refresh = True
|
||||
|
||||
|
|
@ -514,7 +513,9 @@ class SocialAccountService:
|
|||
)
|
||||
should_refresh = True
|
||||
else:
|
||||
buffer_time = now() + timedelta(minutes=10)
|
||||
# DB datetime은 naive, now()는 aware이므로 naive로 통일하여 비교
|
||||
current_time = now().replace(tzinfo=None)
|
||||
buffer_time = current_time + timedelta(minutes=10)
|
||||
if account.token_expires_at <= buffer_time:
|
||||
logger.info(
|
||||
f"[SOCIAL] 토큰 만료 임박, 갱신 시작 - account_id: {account.id}"
|
||||
|
|
@ -573,11 +574,13 @@ class SocialAccountService:
|
|||
if token_response.refresh_token:
|
||||
account.refresh_token = token_response.refresh_token
|
||||
if token_response.expires_in:
|
||||
account.token_expires_at = now() + timedelta(
|
||||
# DB에 naive datetime으로 저장 (MySQL DateTime은 timezone 미지원)
|
||||
account.token_expires_at = now().replace(tzinfo=None) + timedelta(
|
||||
seconds=token_response.expires_in
|
||||
)
|
||||
|
||||
await session.commit()
|
||||
await session.refresh(account)
|
||||
|
||||
logger.info(f"[SOCIAL] 토큰 갱신 완료 - account_id: {account.id}")
|
||||
return account.access_token
|
||||
|
|
@ -631,10 +634,10 @@ class SocialAccountService:
|
|||
Returns:
|
||||
SocialAccount: 생성된 소셜 계정
|
||||
"""
|
||||
# 토큰 만료 시간 계산
|
||||
# 토큰 만료 시간 계산 (DB에 naive datetime으로 저장)
|
||||
token_expires_at = None
|
||||
if token_response.expires_in:
|
||||
token_expires_at = now() + timedelta(
|
||||
token_expires_at = now().replace(tzinfo=None) + timedelta(
|
||||
seconds=token_response.expires_in
|
||||
)
|
||||
|
||||
|
|
@ -687,7 +690,8 @@ class SocialAccountService:
|
|||
if token_response.refresh_token:
|
||||
account.refresh_token = token_response.refresh_token
|
||||
if token_response.expires_in:
|
||||
account.token_expires_at = now() + timedelta(
|
||||
# DB에 naive datetime으로 저장
|
||||
account.token_expires_at = now().replace(tzinfo=None) + timedelta(
|
||||
seconds=token_response.expires_in
|
||||
)
|
||||
if token_response.scope:
|
||||
|
|
@ -703,7 +707,7 @@ class SocialAccountService:
|
|||
|
||||
# 재연결 시 연결 시간 업데이트
|
||||
if update_connected_at:
|
||||
account.connected_at = now()
|
||||
account.connected_at = now().replace(tzinfo=None)
|
||||
|
||||
await session.commit()
|
||||
await session.refresh(account)
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ async def _update_upload_status(
|
|||
if error_message:
|
||||
upload.error_message = error_message
|
||||
if status == UploadStatus.COMPLETED:
|
||||
upload.uploaded_at = now()
|
||||
upload.uploaded_at = now().replace(tzinfo=None)
|
||||
|
||||
await session.commit()
|
||||
logger.info(
|
||||
|
|
|
|||
|
|
@ -391,6 +391,7 @@ class RefreshToken(Base):
|
|||
user: Mapped["User"] = relationship(
|
||||
"User",
|
||||
back_populates="refresh_tokens",
|
||||
lazy="selectin", # lazy loading 방지
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
|
|
@ -591,6 +592,7 @@ class SocialAccount(Base):
|
|||
user: Mapped["User"] = relationship(
|
||||
"User",
|
||||
back_populates="social_accounts",
|
||||
lazy="selectin", # lazy loading 방지
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
|
|
|
|||
Loading…
Reference in New Issue