CLAUDE: Fix draft list operations and improve add success display
Multiple fixes for draft list functionality:
1. **Model Fix (draft_list.py):**
- API returns nested Team and Player objects, not just IDs
- Changed team_id/player_id from fields to @property methods
- Extract IDs from nested objects via properties
- Fixes Pydantic validation errors on GET operations
2. **Service Fix (draft_list_service.py):**
- Override _extract_items_and_count_from_response() for API quirk
- GET returns items under 'picks' key (not 'draftlist')
- Changed add_to_list() return type from single entry to full list
- Return verification list instead of trying to create new DraftList
- Fixes "Failed to add" error from validation issues
3. **Command Enhancement (list.py):**
- Display full draft list on successful add (not just confirmation)
- Show position where player was added
- Reuse existing create_draft_list_embed() for consistency
- Better UX - user sees complete context after adding player
API Response Format:
GET: {"count": N, "picks": [{team: {...}, player: {...}}]}
POST: {"count": N, "draft_list": [{team_id: X, player_id: Y}]}
This resolves:
- Empty list after adding player (Pydantic validation)
- "Add Failed" error despite successful operation
- Poor UX with minimal success feedback
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
07f69ebd77
commit
5f69d495ab
@ -173,14 +173,14 @@ class DraftListCommands(commands.Cog):
|
||||
return
|
||||
|
||||
# Add to list
|
||||
entry = await draft_list_service.add_to_list(
|
||||
updated_list = await draft_list_service.add_to_list(
|
||||
config.sba_current_season,
|
||||
team.id,
|
||||
player_obj.id,
|
||||
rank
|
||||
)
|
||||
|
||||
if not entry:
|
||||
if not updated_list:
|
||||
embed = EmbedTemplate.error(
|
||||
"Add Failed",
|
||||
f"Failed to add {player_obj.name} to draft queue."
|
||||
@ -188,11 +188,15 @@ class DraftListCommands(commands.Cog):
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Success message
|
||||
rank_str = f"#{entry.rank}" if entry.rank else "at end"
|
||||
description = f"Added **{player_obj.name}** to your draft queue at position **{rank_str}**."
|
||||
# Find the added entry to get its rank
|
||||
added_entry = next((e for e in updated_list if e.player_id == player_obj.id), None)
|
||||
rank_str = f"#{added_entry.rank}" if added_entry else "at end"
|
||||
|
||||
# Success message with full draft list
|
||||
success_msg = f"✅ Added **{player_obj.name}** at position **{rank_str}**"
|
||||
embed = await create_draft_list_embed(team, updated_list)
|
||||
embed.description = f"{success_msg}\n\n{embed.description}"
|
||||
|
||||
embed = EmbedTemplate.success("Player Added", description)
|
||||
await interaction.followup.send(embed=embed)
|
||||
|
||||
@discord.app_commands.command(
|
||||
|
||||
@ -13,22 +13,28 @@ from models.player import Player
|
||||
|
||||
class DraftList(SBABaseModel):
|
||||
"""Draft preference list entry for a team."""
|
||||
|
||||
|
||||
season: int = Field(..., description="Draft season")
|
||||
team_id: int = Field(..., description="Team ID that owns this list entry")
|
||||
rank: int = Field(..., description="Ranking of player on team's draft board")
|
||||
player_id: int = Field(..., description="Player ID on the draft board")
|
||||
|
||||
# Related objects (populated when needed)
|
||||
team: Optional[Team] = Field(None, description="Team object (populated when needed)")
|
||||
player: Optional[Player] = Field(None, description="Player object (populated when needed)")
|
||||
|
||||
|
||||
# API returns nested objects (not just IDs)
|
||||
team: Team = Field(..., description="Team object")
|
||||
player: Player = Field(..., description="Player object")
|
||||
|
||||
@property
|
||||
def team_id(self) -> int:
|
||||
"""Extract team ID from nested team object."""
|
||||
return self.team.id
|
||||
|
||||
@property
|
||||
def player_id(self) -> int:
|
||||
"""Extract player ID from nested player object."""
|
||||
return self.player.id
|
||||
|
||||
@property
|
||||
def is_top_ranked(self) -> bool:
|
||||
"""Check if this is the team's top-ranked available player."""
|
||||
return self.rank == 1
|
||||
|
||||
|
||||
def __str__(self):
|
||||
team_str = self.team.abbrev if self.team else f"Team {self.team_id}"
|
||||
player_str = self.player.name if self.player else f"Player {self.player_id}"
|
||||
return f"{team_str} Draft Board #{self.rank}: {player_str}"
|
||||
return f"{self.team.abbrev} Draft Board #{self.rank}: {self.player.name}"
|
||||
@ -20,6 +20,9 @@ class DraftListService(BaseService[DraftList]):
|
||||
IMPORTANT: This service does NOT use caching decorators because draft lists
|
||||
change as users add/remove players from their auto-draft queues.
|
||||
|
||||
API QUIRK: GET endpoint returns items under 'picks' key, not 'draftlist'.
|
||||
POST endpoint expects items under 'draft_list' key.
|
||||
|
||||
Features:
|
||||
- Get team's draft list (ranked by priority)
|
||||
- Add player to draft list
|
||||
@ -33,6 +36,35 @@ class DraftListService(BaseService[DraftList]):
|
||||
super().__init__(DraftList, 'draftlist')
|
||||
logger.debug("DraftListService initialized")
|
||||
|
||||
def _extract_items_and_count_from_response(self, data):
|
||||
"""
|
||||
Override to handle API quirk: GET returns 'picks' instead of 'draftlist'.
|
||||
|
||||
Args:
|
||||
data: API response data
|
||||
|
||||
Returns:
|
||||
Tuple of (items list, total count)
|
||||
"""
|
||||
from typing import Any, Dict, List, Tuple
|
||||
|
||||
if isinstance(data, list):
|
||||
return data, len(data)
|
||||
|
||||
if not isinstance(data, dict):
|
||||
logger.warning(f"Unexpected response format: {type(data)}")
|
||||
return [], 0
|
||||
|
||||
# Get count
|
||||
count = data.get('count', 0)
|
||||
|
||||
# API returns items under 'picks' key (not 'draftlist')
|
||||
if 'picks' in data and isinstance(data['picks'], list):
|
||||
return data['picks'], count or len(data['picks'])
|
||||
|
||||
# Fallback to standard extraction
|
||||
return super()._extract_items_and_count_from_response(data)
|
||||
|
||||
async def get_team_list(
|
||||
self,
|
||||
season: int,
|
||||
@ -71,7 +103,7 @@ class DraftListService(BaseService[DraftList]):
|
||||
team_id: int,
|
||||
player_id: int,
|
||||
rank: Optional[int] = None
|
||||
) -> Optional[DraftList]:
|
||||
) -> Optional[List[DraftList]]:
|
||||
"""
|
||||
Add player to team's draft list.
|
||||
|
||||
@ -87,7 +119,7 @@ class DraftListService(BaseService[DraftList]):
|
||||
rank: Priority rank (1 = highest), None = add to end
|
||||
|
||||
Returns:
|
||||
Created DraftList entry or None if creation failed
|
||||
Full updated draft list or None if operation failed
|
||||
"""
|
||||
try:
|
||||
# Get current list
|
||||
@ -140,13 +172,21 @@ class DraftListService(BaseService[DraftList]):
|
||||
'draft_list': draft_list_entries
|
||||
}
|
||||
|
||||
await client.post(self.endpoint, payload)
|
||||
logger.debug(f"Posting draft list for team {team_id}: {len(draft_list_entries)} entries")
|
||||
response = await client.post(self.endpoint, payload)
|
||||
logger.debug(f"POST response: {response}")
|
||||
|
||||
# Verify by fetching the list back (API returns full objects)
|
||||
verification = await self.get_team_list(season, team_id)
|
||||
logger.debug(f"Verification: found {len(verification)} entries after POST")
|
||||
|
||||
# Verify the player was added
|
||||
if not any(entry.player_id == player_id for entry in verification):
|
||||
logger.error(f"Player {player_id} not found in list after POST - operation may have failed")
|
||||
return None
|
||||
|
||||
# Return the created entry as a DraftList object
|
||||
created_entry = DraftList.from_api_data(new_entry_data)
|
||||
logger.info(f"Added player {player_id} to team {team_id} draft list at rank {rank}")
|
||||
|
||||
return created_entry
|
||||
return verification # Return full updated list
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error adding player {player_id} to draft list: {e}")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user