## Authentication Implementation ### Backend - Implemented complete Discord OAuth flow in auth.py: * POST /api/auth/discord/callback - Exchange code for tokens * POST /api/auth/refresh - Refresh JWT tokens * GET /api/auth/me - Get authenticated user info * GET /api/auth/verify - Verify auth status - JWT token creation with 7-day expiration - Refresh token support for session persistence - Bearer token authentication for Discord API calls ### Frontend - Created auth/login.vue - Discord OAuth initiation page - Created auth/callback.vue - OAuth callback handler with states - Integrated with existing auth store (already implemented) - LocalStorage persistence for tokens and user data - Full error handling and loading states ### Configuration - Updated backend .env with Discord OAuth credentials - Updated frontend .env with Discord Client ID - Fixed redirect URI to port 3001 ## SBA API Integration ### Backend - Extended SbaApiClient with get_teams(season, active_only=True) - Added bearer token auth support (_get_headers method) - Created /api/teams route with TeamResponse model - Registered teams router in main.py - Filters out IL (Injured List) teams automatically - Returns team data: id, abbrev, names, color, gmid, division ### Integration - Connected to production SBA API: https://api.sba.manticorum.com - Bearer token authentication working - Successfully fetches ~16 active Season 3 teams ## Documentation - Created SESSION_NOTES.md - Current session accomplishments - Created NEXT_SESSION.md - Game creation implementation guide - Updated implementation/NEXT_SESSION.md ## Testing - ✅ Discord OAuth flow tested end-to-end - ✅ User authentication and session persistence verified - ✅ Teams API returns real data from production - ✅ All services running and communicating ## What Works Now - User can sign in with Discord - Sessions persist across reloads - Backend fetches real teams from SBA API - Ready for game creation implementation ## Next Steps See .claude/NEXT_SESSION.md for detailed game creation implementation plan. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
60 lines
1.6 KiB
Python
60 lines
1.6 KiB
Python
import logging
|
|
|
|
from fastapi import APIRouter, HTTPException, Query
|
|
from pydantic import BaseModel
|
|
|
|
from app.services.sba_api_client import sba_api_client
|
|
|
|
logger = logging.getLogger(f"{__name__}.teams")
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
class TeamResponse(BaseModel):
|
|
"""Team information response"""
|
|
|
|
id: int
|
|
abbrev: str
|
|
sname: str
|
|
lname: str
|
|
color: str | None = None
|
|
manager_legacy: str | None = None
|
|
gmid: str | None = None
|
|
gmid2: str | None = None
|
|
division: dict | None = None
|
|
|
|
|
|
@router.get("/", response_model=list[TeamResponse])
|
|
async def get_teams(season: int = Query(..., description="Season number (e.g., 3)")):
|
|
"""
|
|
Get all active teams for a season from SBA API.
|
|
|
|
Args:
|
|
season: Season number to fetch teams for
|
|
|
|
Returns:
|
|
List of active teams (excludes IL teams)
|
|
"""
|
|
try:
|
|
logger.info(f"Fetching teams for season {season}")
|
|
teams = await sba_api_client.get_teams(season=season, active_only=True)
|
|
|
|
return [
|
|
TeamResponse(
|
|
id=team["id"],
|
|
abbrev=team["abbrev"],
|
|
sname=team["sname"],
|
|
lname=team["lname"],
|
|
color=team.get("color"),
|
|
manager_legacy=team.get("manager_legacy"),
|
|
gmid=team.get("gmid"),
|
|
gmid2=team.get("gmid2"),
|
|
division=team.get("division"),
|
|
)
|
|
for team in teams
|
|
]
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to fetch teams: {e}", exc_info=True)
|
|
raise HTTPException(status_code=500, detail="Failed to fetch teams")
|