All checks were successful
Build Docker Image / build (pull_request) Successful in 3m38s
aiohttp follows 307 redirects but converts POST to GET, silently
dropping the request body. Standardize all @router.post('') to
@router.post('/') so the canonical URL always has a trailing slash,
preventing 307 redirects when clients POST with trailing slashes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
128 lines
3.7 KiB
Python
128 lines
3.7 KiB
Python
"""
|
|
Team Router - Refactored
|
|
Thin HTTP layer using TeamService for business logic.
|
|
"""
|
|
|
|
from fastapi import APIRouter, Query, Response, Depends
|
|
from typing import List, Optional, Literal
|
|
|
|
from ..dependencies import (
|
|
oauth2_scheme,
|
|
PRIVATE_IN_SCHEMA,
|
|
handle_db_errors,
|
|
cache_result,
|
|
)
|
|
from ..services.base import BaseService
|
|
from ..services.team_service import TeamService
|
|
|
|
router = APIRouter(prefix="/api/v3/teams", tags=["teams"])
|
|
|
|
|
|
@router.get("")
|
|
@handle_db_errors
|
|
@cache_result(ttl=10 * 60, key_prefix="teams")
|
|
async def get_teams(
|
|
season: Optional[int] = None,
|
|
owner_id: list = Query(default=None),
|
|
manager_id: list = Query(default=None),
|
|
team_abbrev: list = Query(default=None),
|
|
active_only: Optional[bool] = False,
|
|
short_output: Optional[bool] = False,
|
|
csv: Optional[bool] = False,
|
|
):
|
|
"""Get teams with filtering."""
|
|
result = TeamService.get_teams(
|
|
season=season,
|
|
owner_id=owner_id if owner_id else None,
|
|
manager_id=manager_id if manager_id else None,
|
|
team_abbrev=team_abbrev if team_abbrev else None,
|
|
active_only=active_only or False,
|
|
short_output=short_output or False,
|
|
as_csv=csv or False,
|
|
)
|
|
|
|
if csv:
|
|
return Response(content=result, media_type="text/csv")
|
|
return result
|
|
|
|
|
|
@router.get("/{team_id}")
|
|
@handle_db_errors
|
|
@cache_result(ttl=30 * 60, key_prefix="team")
|
|
async def get_one_team(team_id: int):
|
|
"""Get a single team by ID."""
|
|
return TeamService.get_team(team_id)
|
|
|
|
|
|
@router.get("/{team_id}/roster")
|
|
@handle_db_errors
|
|
@cache_result(ttl=30 * 60, key_prefix="team-roster")
|
|
async def get_team_roster_default(team_id: int, sort: Optional[str] = None):
|
|
"""Get team roster with IL lists (defaults to current season)."""
|
|
return TeamService.get_team_roster(team_id, "current", sort=sort)
|
|
|
|
|
|
@router.get("/{team_id}/roster/{which}")
|
|
@handle_db_errors
|
|
@cache_result(ttl=30 * 60, key_prefix="team-roster")
|
|
async def get_team_roster(
|
|
team_id: int, which: Literal["current", "next"], sort: Optional[str] = None
|
|
):
|
|
"""Get team roster with IL lists."""
|
|
return TeamService.get_team_roster(team_id, which, sort=sort)
|
|
|
|
|
|
@router.patch("/{team_id}")
|
|
async def patch_team(
|
|
team_id: int,
|
|
token: str = Depends(oauth2_scheme),
|
|
manager1_id: Optional[int] = None,
|
|
manager2_id: Optional[int] = None,
|
|
gmid: Optional[int] = None,
|
|
gmid2: Optional[int] = None,
|
|
mascot: Optional[str] = None,
|
|
stadium: Optional[str] = None,
|
|
thumbnail: Optional[str] = None,
|
|
color: Optional[str] = None,
|
|
abbrev: Optional[str] = None,
|
|
sname: Optional[str] = None,
|
|
lname: Optional[str] = None,
|
|
dice_color: Optional[str] = None,
|
|
division_id: Optional[int] = None,
|
|
):
|
|
"""Patch a team (partial update)."""
|
|
# Build dict of provided fields
|
|
data = {
|
|
key: value
|
|
for key, value in {
|
|
"manager1_id": manager1_id,
|
|
"manager2_id": manager2_id,
|
|
"gmid": gmid,
|
|
"gmid2": gmid2,
|
|
"mascot": mascot,
|
|
"stadium": stadium,
|
|
"thumbnail": thumbnail,
|
|
"color": color,
|
|
"abbrev": abbrev,
|
|
"sname": sname,
|
|
"lname": lname,
|
|
"dice_color": dice_color,
|
|
"division_id": division_id,
|
|
}.items()
|
|
if value is not None
|
|
}
|
|
|
|
return TeamService.update_team(team_id, data, token)
|
|
|
|
|
|
@router.post("/")
|
|
async def post_teams(team_list: dict, token: str = Depends(oauth2_scheme)):
|
|
"""Create multiple teams."""
|
|
return TeamService.create_teams(team_list.get("teams", []), token)
|
|
|
|
|
|
@router.delete("/{team_id}")
|
|
async def delete_team(team_id: int, token: str = Depends(oauth2_scheme)):
|
|
"""Delete a team."""
|
|
return TeamService.delete_team(team_id, token)
|