""" Social Media Models 소셜 미디어 업로드 관련 SQLAlchemy 모델을 정의합니다. """ from datetime import datetime from typing import TYPE_CHECKING, Optional from sqlalchemy import BigInteger, DateTime, ForeignKey, Index, Integer, String, Text, func from sqlalchemy.dialects.mysql import JSON from sqlalchemy.orm import Mapped, mapped_column, relationship from app.database.session import Base if TYPE_CHECKING: from app.user.models import SocialAccount from app.video.models import Video class SocialUpload(Base): """ 소셜 미디어 업로드 기록 테이블 영상의 소셜 미디어 플랫폼별 업로드 상태를 추적합니다. Attributes: id: 고유 식별자 (자동 증가) user_uuid: 사용자 UUID (User.user_uuid 참조) video_id: Video 외래키 social_account_id: SocialAccount 외래키 upload_seq: 업로드 순번 (동일 영상+채널 조합 내 순번, 관리자 추적용) platform: 플랫폼 구분 (youtube, instagram, facebook, tiktok) status: 업로드 상태 (pending, uploading, processing, completed, failed) upload_progress: 업로드 진행률 (0-100) platform_video_id: 플랫폼에서 부여한 영상 ID platform_url: 플랫폼에서의 영상 URL title: 영상 제목 description: 영상 설명 tags: 태그 목록 (JSON) privacy_status: 공개 상태 (public, unlisted, private) platform_options: 플랫폼별 추가 옵션 (JSON) error_message: 에러 메시지 (실패 시) retry_count: 재시도 횟수 uploaded_at: 업로드 완료 시간 created_at: 생성 일시 updated_at: 수정 일시 Relationships: video: 연결된 Video social_account: 연결된 SocialAccount """ __tablename__ = "social_upload" __table_args__ = ( Index("idx_social_upload_user_uuid", "user_uuid"), Index("idx_social_upload_video_id", "video_id"), Index("idx_social_upload_social_account_id", "social_account_id"), Index("idx_social_upload_platform", "platform"), Index("idx_social_upload_status", "status"), Index("idx_social_upload_created_at", "created_at"), # 동일 영상+채널 조합 조회용 인덱스 (유니크 아님 - 여러 번 업로드 가능) Index("idx_social_upload_video_account", "video_id", "social_account_id"), # 순번 조회용 인덱스 Index("idx_social_upload_seq", "video_id", "social_account_id", "upload_seq"), { "mysql_engine": "InnoDB", "mysql_charset": "utf8mb4", "mysql_collate": "utf8mb4_unicode_ci", }, ) # ========================================================================== # 기본 식별자 # ========================================================================== id: Mapped[int] = mapped_column( BigInteger, primary_key=True, nullable=False, autoincrement=True, comment="고유 식별자", ) # ========================================================================== # 관계 필드 # ========================================================================== user_uuid: Mapped[str] = mapped_column( String(36), ForeignKey("user.user_uuid", ondelete="CASCADE"), nullable=False, comment="사용자 UUID (User.user_uuid 참조)", ) video_id: Mapped[int] = mapped_column( Integer, ForeignKey("video.id", ondelete="CASCADE"), nullable=False, comment="Video 외래키", ) social_account_id: Mapped[int] = mapped_column( Integer, ForeignKey("social_account.id", ondelete="CASCADE"), nullable=False, comment="SocialAccount 외래키", ) # ========================================================================== # 업로드 순번 (관리자 추적용) # ========================================================================== upload_seq: Mapped[int] = mapped_column( Integer, nullable=False, default=1, comment="업로드 순번 (동일 영상+채널 조합 내 순번, 1부터 시작)", ) # ========================================================================== # 플랫폼 정보 # ========================================================================== platform: Mapped[str] = mapped_column( String(20), nullable=False, comment="플랫폼 구분 (youtube, instagram, facebook, tiktok)", ) # ========================================================================== # 업로드 상태 # ========================================================================== status: Mapped[str] = mapped_column( String(20), nullable=False, default="pending", comment="업로드 상태 (pending, uploading, processing, completed, failed)", ) upload_progress: Mapped[int] = mapped_column( Integer, nullable=False, default=0, comment="업로드 진행률 (0-100)", ) # ========================================================================== # 플랫폼 결과 # ========================================================================== platform_video_id: Mapped[Optional[str]] = mapped_column( String(100), nullable=True, comment="플랫폼에서 부여한 영상 ID", ) platform_url: Mapped[Optional[str]] = mapped_column( String(500), nullable=True, comment="플랫폼에서의 영상 URL", ) # ========================================================================== # 메타데이터 # ========================================================================== title: Mapped[str] = mapped_column( String(200), nullable=False, comment="영상 제목", ) description: Mapped[Optional[str]] = mapped_column( Text, nullable=True, comment="영상 설명", ) tags: Mapped[Optional[dict]] = mapped_column( JSON, nullable=True, comment="태그 목록 (JSON 배열)", ) privacy_status: Mapped[str] = mapped_column( String(20), nullable=False, default="private", comment="공개 상태 (public, unlisted, private)", ) platform_options: Mapped[Optional[dict]] = mapped_column( JSON, nullable=True, comment="플랫폼별 추가 옵션 (JSON)", ) # ========================================================================== # 에러 정보 # ========================================================================== error_message: Mapped[Optional[str]] = mapped_column( Text, nullable=True, comment="에러 메시지 (실패 시)", ) retry_count: Mapped[int] = mapped_column( Integer, nullable=False, default=0, comment="재시도 횟수", ) # ========================================================================== # 시간 정보 # ========================================================================== uploaded_at: Mapped[Optional[datetime]] = mapped_column( DateTime, nullable=True, comment="업로드 완료 시간", ) created_at: Mapped[datetime] = mapped_column( DateTime, nullable=False, server_default=func.now(), comment="생성 일시", ) updated_at: Mapped[datetime] = mapped_column( DateTime, nullable=False, server_default=func.now(), onupdate=func.now(), comment="수정 일시", ) # ========================================================================== # Relationships # ========================================================================== video: Mapped["Video"] = relationship( "Video", lazy="selectin", ) social_account: Mapped["SocialAccount"] = relationship( "SocialAccount", lazy="selectin", ) def __repr__(self) -> str: return ( f"" )