"""User API router for Mantimon TCG. This module provides endpoints for user profile management: - Get current user profile - Update profile (display name, avatar) - List linked OAuth accounts - Session management All endpoints require authentication. Example: # Get current user GET /api/users/me Authorization: Bearer # Update profile PATCH /api/users/me {"display_name": "NewName"} """ from fastapi import APIRouter from pydantic import BaseModel, Field from app.api.deps import CurrentUser, DbSession from app.schemas.user import UserResponse, UserUpdate from app.services.token_store import token_store from app.services.user_service import user_service router = APIRouter(prefix="/users", tags=["users"]) class LinkedAccountResponse(BaseModel): """Response for a linked OAuth account.""" provider: str = Field(..., description="OAuth provider name") email: str | None = Field(None, description="Email from this provider") linked_at: str = Field(..., description="When account was linked (ISO format)") class SessionsResponse(BaseModel): """Response for active sessions count.""" active_sessions: int = Field(..., description="Number of active sessions") @router.get("/me", response_model=UserResponse) async def get_current_user_profile( user: CurrentUser, ) -> UserResponse: """Get the current user's profile. Returns: User profile information. """ return UserResponse.model_validate(user) @router.patch("/me", response_model=UserResponse) async def update_current_user_profile( user: CurrentUser, db: DbSession, update_data: UserUpdate, ) -> UserResponse: """Update the current user's profile. Only provided fields are updated. Args: update_data: Fields to update (display_name, avatar_url). Returns: Updated user profile. """ updated_user = await user_service.update(db, user, update_data) return UserResponse.model_validate(updated_user) @router.get("/me/linked-accounts", response_model=list[LinkedAccountResponse]) async def get_linked_accounts( user: CurrentUser, ) -> list[LinkedAccountResponse]: """Get all OAuth accounts linked to the current user. Returns the primary OAuth provider plus any additional linked accounts. Returns: List of linked OAuth accounts. """ accounts = [] # Add primary OAuth account accounts.append( LinkedAccountResponse( provider=user.oauth_provider, email=user.email, linked_at=user.created_at.isoformat(), ) ) # Add additional linked accounts for linked in user.linked_accounts: accounts.append( LinkedAccountResponse( provider=linked.provider, email=linked.email, linked_at=linked.linked_at.isoformat(), ) ) return accounts @router.get("/me/sessions", response_model=SessionsResponse) async def get_active_sessions( user: CurrentUser, ) -> SessionsResponse: """Get the number of active sessions for the current user. Each session corresponds to a valid refresh token. Returns: Number of active sessions. """ from uuid import UUID user_id = UUID(user.id) if isinstance(user.id, str) else user.id count = await token_store.get_active_session_count(user_id) return SessionsResponse(active_sessions=count)