CLAUDE: Add complete draft command suite
Implement all remaining draft commands for comprehensive draft management: New Commands: - /draft-admin (Group) - Admin controls for draft management * info - View current draft configuration * timer - Enable/disable draft timer * set-pick - Set current pick number * channels - Configure Discord channels * reset-deadline - Reset pick deadline - /draft-status - View current draft state - /draft-on-clock - Detailed "on the clock" information with recent/upcoming picks - /draft-list - View team's auto-draft queue - /draft-list-add - Add player to queue - /draft-list-remove - Remove player from queue - /draft-list-clear - Clear entire queue - /draft-board - View draft picks by round New Files: - commands/draft/admin.py - Admin commands (app_commands.Group pattern) - commands/draft/status.py - Status viewing commands - commands/draft/list.py - Auto-draft queue management - commands/draft/board.py - Draft board viewing Features: - Admin-only permissions for draft management - FA player autocomplete for draft list - Complete draft state visibility - Round-by-round draft board viewing - Lock status integration - Timer and deadline management Updated: - commands/draft/__init__.py - Register all new cogs and group All commands use @logged_command decorator for consistent logging and error handling. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
4dd9b21322
commit
4cb64253c4
@ -3,13 +3,23 @@ Draft Commands Package for Discord Bot v2.0
|
||||
|
||||
Contains slash commands for draft operations:
|
||||
- /draft - Make a draft pick with autocomplete
|
||||
- /draft-status - View current draft state (TODO)
|
||||
- /draft-admin - Admin controls for draft management (TODO)
|
||||
- /draft-status - View current draft state
|
||||
- /draft-on-clock - Detailed on the clock information
|
||||
- /draft-admin - Admin controls for draft management
|
||||
- /draft-list - View auto-draft queue
|
||||
- /draft-list-add - Add player to queue
|
||||
- /draft-list-remove - Remove player from queue
|
||||
- /draft-list-clear - Clear entire queue
|
||||
- /draft-board - View draft picks by round
|
||||
"""
|
||||
import logging
|
||||
from discord.ext import commands
|
||||
|
||||
from .picks import DraftPicksCog
|
||||
from .status import DraftStatusCommands
|
||||
from .list import DraftListCommands
|
||||
from .board import DraftBoardCommands
|
||||
from .admin import DraftAdminGroup
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -24,12 +34,16 @@ async def setup_draft(bot: commands.Bot):
|
||||
# Define all draft command cogs to load
|
||||
draft_cogs = [
|
||||
("DraftPicksCog", DraftPicksCog),
|
||||
("DraftStatusCommands", DraftStatusCommands),
|
||||
("DraftListCommands", DraftListCommands),
|
||||
("DraftBoardCommands", DraftBoardCommands),
|
||||
]
|
||||
|
||||
successful = 0
|
||||
failed = 0
|
||||
failed_modules = []
|
||||
|
||||
# Load regular cogs
|
||||
for cog_name, cog_class in draft_cogs:
|
||||
try:
|
||||
await bot.add_cog(cog_class(bot))
|
||||
@ -40,6 +54,16 @@ async def setup_draft(bot: commands.Bot):
|
||||
failed += 1
|
||||
failed_modules.append(cog_name)
|
||||
|
||||
# Load draft admin group (app_commands.Group pattern)
|
||||
try:
|
||||
bot.tree.add_command(DraftAdminGroup())
|
||||
logger.info("✅ Loaded DraftAdminGroup")
|
||||
successful += 1
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Failed to load DraftAdminGroup: {e}", exc_info=True)
|
||||
failed += 1
|
||||
failed_modules.append("DraftAdminGroup")
|
||||
|
||||
# Log summary
|
||||
if failed == 0:
|
||||
logger.info(f"🎉 All {successful} draft command modules loaded successfully")
|
||||
@ -50,4 +74,11 @@ async def setup_draft(bot: commands.Bot):
|
||||
|
||||
|
||||
# Export the setup function for easy importing
|
||||
__all__ = ['setup_draft', 'DraftPicksCog']
|
||||
__all__ = [
|
||||
'setup_draft',
|
||||
'DraftPicksCog',
|
||||
'DraftStatusCommands',
|
||||
'DraftListCommands',
|
||||
'DraftBoardCommands',
|
||||
'DraftAdminGroup'
|
||||
]
|
||||
293
commands/draft/admin.py
Normal file
293
commands/draft/admin.py
Normal file
@ -0,0 +1,293 @@
|
||||
"""
|
||||
Draft Admin Commands
|
||||
|
||||
Admin-only commands for draft management and configuration.
|
||||
"""
|
||||
from typing import Optional
|
||||
|
||||
import discord
|
||||
from discord import app_commands
|
||||
from discord.ext import commands
|
||||
|
||||
from config import get_config
|
||||
from services.draft_service import draft_service
|
||||
from services.draft_pick_service import draft_pick_service
|
||||
from utils.logging import get_contextual_logger
|
||||
from utils.decorators import logged_command
|
||||
from views.draft_views import create_admin_draft_info_embed
|
||||
from views.embeds import EmbedTemplate
|
||||
|
||||
|
||||
class DraftAdminGroup(app_commands.Group):
|
||||
"""Draft administration command group."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
name="draft-admin",
|
||||
description="Admin commands for draft management"
|
||||
)
|
||||
self.logger = get_contextual_logger(f'{__name__}.DraftAdminGroup')
|
||||
|
||||
@app_commands.command(name="info", description="View current draft configuration")
|
||||
@app_commands.checks.has_permissions(administrator=True)
|
||||
@logged_command("/draft-admin info")
|
||||
async def draft_admin_info(self, interaction: discord.Interaction):
|
||||
"""Display current draft configuration and state."""
|
||||
await interaction.response.defer()
|
||||
|
||||
# Get draft data
|
||||
draft_data = await draft_service.get_draft_data()
|
||||
if not draft_data:
|
||||
embed = EmbedTemplate.error(
|
||||
"Draft Not Found",
|
||||
"Could not retrieve draft configuration."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Get current pick
|
||||
config = get_config()
|
||||
current_pick = await draft_pick_service.get_pick(
|
||||
config.sba_current_season,
|
||||
draft_data.currentpick
|
||||
)
|
||||
|
||||
# Create admin info embed
|
||||
embed = await create_admin_draft_info_embed(draft_data, current_pick)
|
||||
await interaction.followup.send(embed=embed)
|
||||
|
||||
@app_commands.command(name="timer", description="Enable or disable draft timer")
|
||||
@app_commands.describe(
|
||||
enabled="Turn timer on or off",
|
||||
minutes="Minutes per pick (optional, default uses current setting)"
|
||||
)
|
||||
@app_commands.checks.has_permissions(administrator=True)
|
||||
@logged_command("/draft-admin timer")
|
||||
async def draft_admin_timer(
|
||||
self,
|
||||
interaction: discord.Interaction,
|
||||
enabled: bool,
|
||||
minutes: Optional[int] = None
|
||||
):
|
||||
"""Enable or disable the draft timer."""
|
||||
await interaction.response.defer()
|
||||
|
||||
# Get draft data
|
||||
draft_data = await draft_service.get_draft_data()
|
||||
if not draft_data:
|
||||
embed = EmbedTemplate.error(
|
||||
"Draft Not Found",
|
||||
"Could not retrieve draft configuration."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Update timer
|
||||
updated = await draft_service.set_timer(draft_data.id, enabled, minutes)
|
||||
|
||||
if not updated:
|
||||
embed = EmbedTemplate.error(
|
||||
"Update Failed",
|
||||
"Failed to update draft timer."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Success message
|
||||
status = "enabled" if enabled else "disabled"
|
||||
description = f"Draft timer has been **{status}**."
|
||||
|
||||
if enabled and minutes:
|
||||
description += f"\n\nPick duration: **{minutes} minutes**"
|
||||
elif enabled:
|
||||
description += f"\n\nPick duration: **{updated.pick_minutes} minutes**"
|
||||
|
||||
embed = EmbedTemplate.success("Timer Updated", description)
|
||||
await interaction.followup.send(embed=embed)
|
||||
|
||||
@app_commands.command(name="set-pick", description="Set current pick number")
|
||||
@app_commands.describe(
|
||||
pick_number="Overall pick number to jump to (1-512)"
|
||||
)
|
||||
@app_commands.checks.has_permissions(administrator=True)
|
||||
@logged_command("/draft-admin set-pick")
|
||||
async def draft_admin_set_pick(
|
||||
self,
|
||||
interaction: discord.Interaction,
|
||||
pick_number: int
|
||||
):
|
||||
"""Set the current pick number (admin operation)."""
|
||||
await interaction.response.defer()
|
||||
|
||||
config = get_config()
|
||||
|
||||
# Validate pick number
|
||||
if pick_number < 1 or pick_number > config.draft_total_picks:
|
||||
embed = EmbedTemplate.error(
|
||||
"Invalid Pick Number",
|
||||
f"Pick number must be between 1 and {config.draft_total_picks}."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Get draft data
|
||||
draft_data = await draft_service.get_draft_data()
|
||||
if not draft_data:
|
||||
embed = EmbedTemplate.error(
|
||||
"Draft Not Found",
|
||||
"Could not retrieve draft configuration."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Verify pick exists
|
||||
pick = await draft_pick_service.get_pick(config.sba_current_season, pick_number)
|
||||
if not pick:
|
||||
embed = EmbedTemplate.error(
|
||||
"Pick Not Found",
|
||||
f"Pick #{pick_number} does not exist in the database."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Update current pick
|
||||
updated = await draft_service.set_current_pick(
|
||||
draft_data.id,
|
||||
pick_number,
|
||||
reset_timer=True
|
||||
)
|
||||
|
||||
if not updated:
|
||||
embed = EmbedTemplate.error(
|
||||
"Update Failed",
|
||||
"Failed to update current pick."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Success message
|
||||
from utils.draft_helpers import format_pick_display
|
||||
|
||||
description = f"Current pick set to **{format_pick_display(pick_number)}**."
|
||||
if pick.owner:
|
||||
description += f"\n\n{pick.owner.abbrev} {pick.owner.sname} is now on the clock."
|
||||
|
||||
embed = EmbedTemplate.success("Pick Updated", description)
|
||||
await interaction.followup.send(embed=embed)
|
||||
|
||||
@app_commands.command(name="channels", description="Configure draft Discord channels")
|
||||
@app_commands.describe(
|
||||
ping_channel="Channel for 'on the clock' pings",
|
||||
result_channel="Channel for draft results"
|
||||
)
|
||||
@app_commands.checks.has_permissions(administrator=True)
|
||||
@logged_command("/draft-admin channels")
|
||||
async def draft_admin_channels(
|
||||
self,
|
||||
interaction: discord.Interaction,
|
||||
ping_channel: Optional[discord.TextChannel] = None,
|
||||
result_channel: Optional[discord.TextChannel] = None
|
||||
):
|
||||
"""Configure draft Discord channels."""
|
||||
await interaction.response.defer()
|
||||
|
||||
if not ping_channel and not result_channel:
|
||||
embed = EmbedTemplate.error(
|
||||
"No Channels Provided",
|
||||
"Please specify at least one channel to update."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Get draft data
|
||||
draft_data = await draft_service.get_draft_data()
|
||||
if not draft_data:
|
||||
embed = EmbedTemplate.error(
|
||||
"Draft Not Found",
|
||||
"Could not retrieve draft configuration."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Update channels
|
||||
updated = await draft_service.update_channels(
|
||||
draft_data.id,
|
||||
ping_channel_id=ping_channel.id if ping_channel else None,
|
||||
result_channel_id=result_channel.id if result_channel else None
|
||||
)
|
||||
|
||||
if not updated:
|
||||
embed = EmbedTemplate.error(
|
||||
"Update Failed",
|
||||
"Failed to update draft channels."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Success message
|
||||
description = "Draft channels updated:\n\n"
|
||||
if ping_channel:
|
||||
description += f"**Ping Channel:** {ping_channel.mention}\n"
|
||||
if result_channel:
|
||||
description += f"**Result Channel:** {result_channel.mention}\n"
|
||||
|
||||
embed = EmbedTemplate.success("Channels Updated", description)
|
||||
await interaction.followup.send(embed=embed)
|
||||
|
||||
@app_commands.command(name="reset-deadline", description="Reset current pick deadline")
|
||||
@app_commands.describe(
|
||||
minutes="Minutes to add (uses default if not provided)"
|
||||
)
|
||||
@app_commands.checks.has_permissions(administrator=True)
|
||||
@logged_command("/draft-admin reset-deadline")
|
||||
async def draft_admin_reset_deadline(
|
||||
self,
|
||||
interaction: discord.Interaction,
|
||||
minutes: Optional[int] = None
|
||||
):
|
||||
"""Reset the current pick deadline."""
|
||||
await interaction.response.defer()
|
||||
|
||||
# Get draft data
|
||||
draft_data = await draft_service.get_draft_data()
|
||||
if not draft_data:
|
||||
embed = EmbedTemplate.error(
|
||||
"Draft Not Found",
|
||||
"Could not retrieve draft configuration."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
if not draft_data.timer:
|
||||
embed = EmbedTemplate.warning(
|
||||
"Timer Inactive",
|
||||
"Draft timer is currently disabled. Enable it with `/draft-admin timer on` first."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Reset deadline
|
||||
updated = await draft_service.reset_draft_deadline(draft_data.id, minutes)
|
||||
|
||||
if not updated:
|
||||
embed = EmbedTemplate.error(
|
||||
"Update Failed",
|
||||
"Failed to reset draft deadline."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Success message
|
||||
deadline_timestamp = int(updated.pick_deadline.timestamp())
|
||||
minutes_used = minutes if minutes else updated.pick_minutes
|
||||
|
||||
description = f"Pick deadline reset: **{minutes_used} minutes** added.\n\n"
|
||||
description += f"New deadline: <t:{deadline_timestamp}:F> (<t:{deadline_timestamp}:R>)"
|
||||
|
||||
embed = EmbedTemplate.success("Deadline Reset", description)
|
||||
await interaction.followup.send(embed=embed)
|
||||
|
||||
|
||||
async def setup(bot: commands.Bot):
|
||||
"""Setup function for loading the draft admin commands."""
|
||||
bot.tree.add_command(DraftAdminGroup())
|
||||
79
commands/draft/board.py
Normal file
79
commands/draft/board.py
Normal file
@ -0,0 +1,79 @@
|
||||
"""
|
||||
Draft Board Commands
|
||||
|
||||
View draft picks by round with pagination.
|
||||
"""
|
||||
from typing import Optional
|
||||
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
|
||||
from config import get_config
|
||||
from services.draft_pick_service import draft_pick_service
|
||||
from utils.logging import get_contextual_logger
|
||||
from utils.decorators import logged_command
|
||||
from views.draft_views import create_draft_board_embed
|
||||
from views.embeds import EmbedTemplate
|
||||
|
||||
|
||||
class DraftBoardCommands(commands.Cog):
|
||||
"""Draft board viewing command handlers."""
|
||||
|
||||
def __init__(self, bot: commands.Bot):
|
||||
self.bot = bot
|
||||
self.logger = get_contextual_logger(f'{__name__}.DraftBoardCommands')
|
||||
|
||||
@discord.app_commands.command(
|
||||
name="draft-board",
|
||||
description="View draft picks by round"
|
||||
)
|
||||
@discord.app_commands.describe(
|
||||
round_number="Round number to view (1-32)"
|
||||
)
|
||||
@logged_command("/draft-board")
|
||||
async def draft_board(
|
||||
self,
|
||||
interaction: discord.Interaction,
|
||||
round_number: Optional[int] = None
|
||||
):
|
||||
"""Display draft board for a specific round."""
|
||||
await interaction.response.defer()
|
||||
|
||||
config = get_config()
|
||||
|
||||
# Default to round 1 if not specified
|
||||
if round_number is None:
|
||||
round_number = 1
|
||||
|
||||
# Validate round number
|
||||
if round_number < 1 or round_number > config.draft_rounds:
|
||||
embed = EmbedTemplate.error(
|
||||
"Invalid Round",
|
||||
f"Round number must be between 1 and {config.draft_rounds}."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Get picks for this round
|
||||
picks = await draft_pick_service.get_picks_by_round(
|
||||
config.sba_current_season,
|
||||
round_number,
|
||||
include_taken=True
|
||||
)
|
||||
|
||||
if not picks:
|
||||
embed = EmbedTemplate.error(
|
||||
"No Picks Found",
|
||||
f"Could not retrieve picks for round {round_number}."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Create draft board embed
|
||||
embed = await create_draft_board_embed(round_number, picks)
|
||||
await interaction.followup.send(embed=embed)
|
||||
|
||||
|
||||
async def setup(bot: commands.Bot):
|
||||
"""Load the draft board commands cog."""
|
||||
await bot.add_cog(DraftBoardCommands(bot))
|
||||
324
commands/draft/list.py
Normal file
324
commands/draft/list.py
Normal file
@ -0,0 +1,324 @@
|
||||
"""
|
||||
Draft List Commands
|
||||
|
||||
Manage team auto-draft queue (draft board).
|
||||
"""
|
||||
from typing import List, Optional
|
||||
|
||||
import discord
|
||||
from discord import app_commands
|
||||
from discord.ext import commands
|
||||
|
||||
from config import get_config
|
||||
from services.draft_list_service import draft_list_service
|
||||
from services.player_service import player_service
|
||||
from services.team_service import team_service
|
||||
from utils.logging import get_contextual_logger
|
||||
from utils.decorators import logged_command
|
||||
from views.draft_views import create_draft_list_embed
|
||||
from views.embeds import EmbedTemplate
|
||||
|
||||
|
||||
async def fa_player_autocomplete(
|
||||
interaction: discord.Interaction,
|
||||
current: str,
|
||||
) -> List[discord.app_commands.Choice[str]]:
|
||||
"""Autocomplete for FA players only."""
|
||||
if len(current) < 2:
|
||||
return []
|
||||
|
||||
try:
|
||||
config = get_config()
|
||||
players = await player_service.search_players(
|
||||
current,
|
||||
limit=25,
|
||||
season=config.sba_current_season
|
||||
)
|
||||
|
||||
# Filter to FA team
|
||||
fa_players = [p for p in players if p.team_id == config.free_agent_team_id]
|
||||
|
||||
return [
|
||||
discord.app_commands.Choice(
|
||||
name=f"{p.name} ({p.primary_position}) - {p.wara:.2f} sWAR",
|
||||
value=p.name
|
||||
)
|
||||
for p in fa_players[:25]
|
||||
]
|
||||
|
||||
except Exception:
|
||||
return []
|
||||
|
||||
|
||||
class DraftListCommands(commands.Cog):
|
||||
"""Draft list management command handlers."""
|
||||
|
||||
def __init__(self, bot: commands.Bot):
|
||||
self.bot = bot
|
||||
self.logger = get_contextual_logger(f'{__name__}.DraftListCommands')
|
||||
|
||||
@discord.app_commands.command(
|
||||
name="draft-list",
|
||||
description="View your team's auto-draft queue"
|
||||
)
|
||||
@logged_command("/draft-list")
|
||||
async def draft_list_view(self, interaction: discord.Interaction):
|
||||
"""Display team's draft list."""
|
||||
await interaction.response.defer()
|
||||
|
||||
config = get_config()
|
||||
|
||||
# Get user's team
|
||||
team = await team_service.get_team_by_owner(
|
||||
interaction.user.id,
|
||||
config.sba_current_season
|
||||
)
|
||||
|
||||
if not team:
|
||||
embed = EmbedTemplate.error(
|
||||
"Not a GM",
|
||||
"You are not registered as a team owner."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Get draft list
|
||||
draft_list = await draft_list_service.get_team_list(
|
||||
config.sba_current_season,
|
||||
team.id
|
||||
)
|
||||
|
||||
# Create embed
|
||||
embed = await create_draft_list_embed(team, draft_list)
|
||||
await interaction.followup.send(embed=embed)
|
||||
|
||||
@discord.app_commands.command(
|
||||
name="draft-list-add",
|
||||
description="Add player to your auto-draft queue"
|
||||
)
|
||||
@discord.app_commands.describe(
|
||||
player="Player name to add (autocomplete shows FA players)",
|
||||
rank="Position in queue (optional, adds to end if not specified)"
|
||||
)
|
||||
@discord.app_commands.autocomplete(player=fa_player_autocomplete)
|
||||
@logged_command("/draft-list-add")
|
||||
async def draft_list_add(
|
||||
self,
|
||||
interaction: discord.Interaction,
|
||||
player: str,
|
||||
rank: Optional[int] = None
|
||||
):
|
||||
"""Add player to draft list."""
|
||||
await interaction.response.defer()
|
||||
|
||||
config = get_config()
|
||||
|
||||
# Get user's team
|
||||
team = await team_service.get_team_by_owner(
|
||||
interaction.user.id,
|
||||
config.sba_current_season
|
||||
)
|
||||
|
||||
if not team:
|
||||
embed = EmbedTemplate.error(
|
||||
"Not a GM",
|
||||
"You are not registered as a team owner."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Get player
|
||||
players = await player_service.get_players_by_name(player, config.sba_current_season)
|
||||
if not players:
|
||||
embed = EmbedTemplate.error(
|
||||
"Player Not Found",
|
||||
f"Could not find player '{player}'."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
player_obj = players[0]
|
||||
|
||||
# Validate player is FA
|
||||
if player_obj.team_id != config.free_agent_team_id:
|
||||
embed = EmbedTemplate.error(
|
||||
"Player Not Available",
|
||||
f"{player_obj.name} is not a free agent."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Check if player already in list
|
||||
current_list = await draft_list_service.get_team_list(
|
||||
config.sba_current_season,
|
||||
team.id
|
||||
)
|
||||
|
||||
if any(entry.player_id == player_obj.id for entry in current_list):
|
||||
embed = EmbedTemplate.error(
|
||||
"Already in Queue",
|
||||
f"{player_obj.name} is already in your draft queue."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Validate rank
|
||||
if rank is not None:
|
||||
if rank < 1 or rank > len(current_list) + 1:
|
||||
embed = EmbedTemplate.error(
|
||||
"Invalid Rank",
|
||||
f"Rank must be between 1 and {len(current_list) + 1}."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Add to list
|
||||
entry = await draft_list_service.add_to_list(
|
||||
config.sba_current_season,
|
||||
team.id,
|
||||
player_obj.id,
|
||||
rank
|
||||
)
|
||||
|
||||
if not entry:
|
||||
embed = EmbedTemplate.error(
|
||||
"Add Failed",
|
||||
f"Failed to add {player_obj.name} to draft queue."
|
||||
)
|
||||
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}**."
|
||||
|
||||
embed = EmbedTemplate.success("Player Added", description)
|
||||
await interaction.followup.send(embed=embed)
|
||||
|
||||
@discord.app_commands.command(
|
||||
name="draft-list-remove",
|
||||
description="Remove player from your auto-draft queue"
|
||||
)
|
||||
@discord.app_commands.describe(
|
||||
player="Player name to remove"
|
||||
)
|
||||
@discord.app_commands.autocomplete(player=fa_player_autocomplete)
|
||||
@logged_command("/draft-list-remove")
|
||||
async def draft_list_remove(
|
||||
self,
|
||||
interaction: discord.Interaction,
|
||||
player: str
|
||||
):
|
||||
"""Remove player from draft list."""
|
||||
await interaction.response.defer()
|
||||
|
||||
config = get_config()
|
||||
|
||||
# Get user's team
|
||||
team = await team_service.get_team_by_owner(
|
||||
interaction.user.id,
|
||||
config.sba_current_season
|
||||
)
|
||||
|
||||
if not team:
|
||||
embed = EmbedTemplate.error(
|
||||
"Not a GM",
|
||||
"You are not registered as a team owner."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Get player
|
||||
players = await player_service.get_players_by_name(player, config.sba_current_season)
|
||||
if not players:
|
||||
embed = EmbedTemplate.error(
|
||||
"Player Not Found",
|
||||
f"Could not find player '{player}'."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
player_obj = players[0]
|
||||
|
||||
# Remove from list
|
||||
success = await draft_list_service.remove_player_from_list(
|
||||
config.sba_current_season,
|
||||
team.id,
|
||||
player_obj.id
|
||||
)
|
||||
|
||||
if not success:
|
||||
embed = EmbedTemplate.error(
|
||||
"Not in Queue",
|
||||
f"{player_obj.name} is not in your draft queue."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Success message
|
||||
description = f"Removed **{player_obj.name}** from your draft queue."
|
||||
embed = EmbedTemplate.success("Player Removed", description)
|
||||
await interaction.followup.send(embed=embed)
|
||||
|
||||
@discord.app_commands.command(
|
||||
name="draft-list-clear",
|
||||
description="Clear your entire auto-draft queue"
|
||||
)
|
||||
@logged_command("/draft-list-clear")
|
||||
async def draft_list_clear(self, interaction: discord.Interaction):
|
||||
"""Clear entire draft list."""
|
||||
await interaction.response.defer()
|
||||
|
||||
config = get_config()
|
||||
|
||||
# Get user's team
|
||||
team = await team_service.get_team_by_owner(
|
||||
interaction.user.id,
|
||||
config.sba_current_season
|
||||
)
|
||||
|
||||
if not team:
|
||||
embed = EmbedTemplate.error(
|
||||
"Not a GM",
|
||||
"You are not registered as a team owner."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Get current list size
|
||||
current_list = await draft_list_service.get_team_list(
|
||||
config.sba_current_season,
|
||||
team.id
|
||||
)
|
||||
|
||||
if not current_list:
|
||||
embed = EmbedTemplate.info(
|
||||
"Queue Empty",
|
||||
"Your draft queue is already empty."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Clear list
|
||||
success = await draft_list_service.clear_list(
|
||||
config.sba_current_season,
|
||||
team.id
|
||||
)
|
||||
|
||||
if not success:
|
||||
embed = EmbedTemplate.error(
|
||||
"Clear Failed",
|
||||
"Failed to clear draft queue."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Success message
|
||||
description = f"Cleared **{len(current_list)} players** from your draft queue."
|
||||
embed = EmbedTemplate.success("Queue Cleared", description)
|
||||
await interaction.followup.send(embed=embed)
|
||||
|
||||
|
||||
async def setup(bot: commands.Bot):
|
||||
"""Load the draft list commands cog."""
|
||||
await bot.add_cog(DraftListCommands(bot))
|
||||
147
commands/draft/status.py
Normal file
147
commands/draft/status.py
Normal file
@ -0,0 +1,147 @@
|
||||
"""
|
||||
Draft Status Commands
|
||||
|
||||
Display current draft state and information.
|
||||
"""
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
|
||||
from config import get_config
|
||||
from services.draft_service import draft_service
|
||||
from services.draft_pick_service import draft_pick_service
|
||||
from utils.logging import get_contextual_logger
|
||||
from utils.decorators import logged_command
|
||||
from views.draft_views import create_draft_status_embed, create_on_the_clock_embed
|
||||
from views.embeds import EmbedTemplate
|
||||
|
||||
|
||||
class DraftStatusCommands(commands.Cog):
|
||||
"""Draft status display command handlers."""
|
||||
|
||||
def __init__(self, bot: commands.Bot):
|
||||
self.bot = bot
|
||||
self.logger = get_contextual_logger(f'{__name__}.DraftStatusCommands')
|
||||
|
||||
@discord.app_commands.command(
|
||||
name="draft-status",
|
||||
description="View current draft state and timer information"
|
||||
)
|
||||
@logged_command("/draft-status")
|
||||
async def draft_status(self, interaction: discord.Interaction):
|
||||
"""Display current draft state."""
|
||||
await interaction.response.defer()
|
||||
|
||||
config = get_config()
|
||||
|
||||
# Get draft data
|
||||
draft_data = await draft_service.get_draft_data()
|
||||
if not draft_data:
|
||||
embed = EmbedTemplate.error(
|
||||
"Draft Not Found",
|
||||
"Could not retrieve draft configuration."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Get current pick
|
||||
current_pick = await draft_pick_service.get_pick(
|
||||
config.sba_current_season,
|
||||
draft_data.currentpick
|
||||
)
|
||||
|
||||
if not current_pick:
|
||||
embed = EmbedTemplate.error(
|
||||
"Pick Not Found",
|
||||
f"Could not retrieve pick #{draft_data.currentpick}."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Check pick lock status
|
||||
draft_picks_cog = self.bot.get_cog('DraftPicksCog')
|
||||
lock_status = "🔓 No pick in progress"
|
||||
|
||||
if draft_picks_cog and draft_picks_cog.pick_lock.locked():
|
||||
if draft_picks_cog.lock_acquired_by:
|
||||
user = self.bot.get_user(draft_picks_cog.lock_acquired_by)
|
||||
user_name = user.name if user else f"User {draft_picks_cog.lock_acquired_by}"
|
||||
lock_status = f"🔒 Pick in progress by {user_name}"
|
||||
else:
|
||||
lock_status = "🔒 Pick in progress (system)"
|
||||
|
||||
# Create status embed
|
||||
embed = await create_draft_status_embed(draft_data, current_pick, lock_status)
|
||||
await interaction.followup.send(embed=embed)
|
||||
|
||||
@discord.app_commands.command(
|
||||
name="draft-on-clock",
|
||||
description="View detailed 'on the clock' information"
|
||||
)
|
||||
@logged_command("/draft-on-clock")
|
||||
async def draft_on_clock(self, interaction: discord.Interaction):
|
||||
"""Display detailed 'on the clock' information with recent and upcoming picks."""
|
||||
await interaction.response.defer()
|
||||
|
||||
config = get_config()
|
||||
|
||||
# Get draft data
|
||||
draft_data = await draft_service.get_draft_data()
|
||||
if not draft_data:
|
||||
embed = EmbedTemplate.error(
|
||||
"Draft Not Found",
|
||||
"Could not retrieve draft configuration."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Get current pick
|
||||
current_pick = await draft_pick_service.get_pick(
|
||||
config.sba_current_season,
|
||||
draft_data.currentpick
|
||||
)
|
||||
|
||||
if not current_pick or not current_pick.owner:
|
||||
embed = EmbedTemplate.error(
|
||||
"Pick Not Found",
|
||||
f"Could not retrieve pick #{draft_data.currentpick}."
|
||||
)
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Get recent picks
|
||||
recent_picks = await draft_pick_service.get_recent_picks(
|
||||
config.sba_current_season,
|
||||
draft_data.currentpick,
|
||||
limit=5
|
||||
)
|
||||
|
||||
# Get upcoming picks
|
||||
upcoming_picks = await draft_pick_service.get_upcoming_picks(
|
||||
config.sba_current_season,
|
||||
draft_data.currentpick,
|
||||
limit=5
|
||||
)
|
||||
|
||||
# Get team roster sWAR (optional)
|
||||
from services.team_service import team_service
|
||||
team_roster_swar = None
|
||||
|
||||
roster = await team_service.get_team_roster(current_pick.owner.id, 'current')
|
||||
if roster and roster.get('active'):
|
||||
team_roster_swar = roster['active'].get('WARa')
|
||||
|
||||
# Create on the clock embed
|
||||
embed = await create_on_the_clock_embed(
|
||||
current_pick,
|
||||
draft_data,
|
||||
recent_picks,
|
||||
upcoming_picks,
|
||||
team_roster_swar
|
||||
)
|
||||
|
||||
await interaction.followup.send(embed=embed)
|
||||
|
||||
|
||||
async def setup(bot: commands.Bot):
|
||||
"""Load the draft status commands cog."""
|
||||
await bot.add_cog(DraftStatusCommands(bot))
|
||||
Loading…
Reference in New Issue
Block a user