"""Session management service 處理 user_sessions 資料庫操作: - 建立/查詢/刪除 session - 更新活動時間戳 - 管理 refresh 重試計數器 """ import uuid from datetime import datetime from sqlalchemy.orm import Session from app.modules.auth.models import UserSession class SessionService: """Session management service""" def create_session( self, db: Session, username: str, display_name: str, ad_token: str, encrypted_password: str, ad_token_expires_at: datetime, ) -> UserSession: """Create new user session Args: db: Database session username: User email from AD display_name: Display name from AD ad_token: AD API token encrypted_password: Encrypted password for auto-refresh ad_token_expires_at: AD token expiry datetime Returns: Created UserSession object """ # Generate unique internal token internal_token = str(uuid.uuid4()) session = UserSession( username=username, display_name=display_name, internal_token=internal_token, ad_token=ad_token, encrypted_password=encrypted_password, ad_token_expires_at=ad_token_expires_at, refresh_attempt_count=0, last_activity=datetime.utcnow(), ) db.add(session) db.commit() db.refresh(session) return session def get_session_by_token(self, db: Session, internal_token: str) -> UserSession | None: """Get session by internal token Args: db: Database session internal_token: Internal session token (UUID) Returns: UserSession if found, None otherwise """ return db.query(UserSession).filter(UserSession.internal_token == internal_token).first() def update_activity(self, db: Session, session_id: int) -> None: """Update last_activity timestamp Args: db: Database session session_id: Session ID """ db.query(UserSession).filter(UserSession.id == session_id).update( {"last_activity": datetime.utcnow()} ) db.commit() def update_ad_token( self, db: Session, session_id: int, new_ad_token: str, new_expires_at: datetime ) -> None: """Update AD token after successful refresh Args: db: Database session session_id: Session ID new_ad_token: New AD token new_expires_at: New expiry datetime """ db.query(UserSession).filter(UserSession.id == session_id).update( { "ad_token": new_ad_token, "ad_token_expires_at": new_expires_at, "refresh_attempt_count": 0, # Reset counter on success } ) db.commit() def increment_refresh_attempts(self, db: Session, session_id: int) -> int: """Increment refresh attempt counter Args: db: Database session session_id: Session ID Returns: New refresh_attempt_count value """ session = db.query(UserSession).filter(UserSession.id == session_id).first() if session: session.refresh_attempt_count += 1 db.commit() return session.refresh_attempt_count return 0 def reset_refresh_attempts(self, db: Session, session_id: int) -> None: """Reset refresh attempt counter Args: db: Database session session_id: Session ID """ db.query(UserSession).filter(UserSession.id == session_id).update( {"refresh_attempt_count": 0} ) db.commit() def delete_session(self, db: Session, session_id: int) -> None: """Delete session Args: db: Database session session_id: Session ID """ db.query(UserSession).filter(UserSession.id == session_id).delete() db.commit() # Singleton instance session_service = SessionService()