CLAUDE: Add draft period restriction to interactive draft commands
Restrict interactive draft commands to offseason only (week <= 0) while keeping read-only commands available year-round. Changes: - Add @requires_draft_period decorator to utils/decorators.py - Apply decorator to /draft and all /draft-list-* commands - Keep /draft-board, /draft-status, /draft-on-clock unrestricted - Update commands/draft/CLAUDE.md with restriction documentation Technical details: - Decorator checks league_service.get_current_state().week <= 0 - Shows user-friendly error: "Draft commands are only available in the offseason" - Follows existing @logged_command decorator pattern - No Discord command cache delays - instant restriction 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
d3824d7295
commit
fb78b4b8c6
@ -4,11 +4,40 @@
|
|||||||
|
|
||||||
This directory contains Discord slash commands for draft system operations.
|
This directory contains Discord slash commands for draft system operations.
|
||||||
|
|
||||||
|
## 🚨 Important: Draft Period Restriction
|
||||||
|
|
||||||
|
**Interactive draft commands are restricted to the offseason (week ≤ 0).**
|
||||||
|
|
||||||
|
### Restricted Commands
|
||||||
|
The following commands can **only be used during the offseason** (when league week ≤ 0):
|
||||||
|
- `/draft` - Make draft picks
|
||||||
|
- `/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
|
||||||
|
|
||||||
|
**Implementation:** The `@requires_draft_period` decorator automatically checks the current league week and returns an error message if the league is in-season.
|
||||||
|
|
||||||
|
### Unrestricted Commands
|
||||||
|
These commands remain **available year-round**:
|
||||||
|
- `/draft-board` - View draft picks by round
|
||||||
|
- `/draft-status` - View current draft state
|
||||||
|
- `/draft-on-clock` - View detailed on-the-clock information
|
||||||
|
- All `/draft-admin` commands (administrator only)
|
||||||
|
|
||||||
|
### User Experience
|
||||||
|
When a user tries to run a restricted command during the season, they see:
|
||||||
|
```
|
||||||
|
❌ Not Available
|
||||||
|
Draft commands are only available in the offseason.
|
||||||
|
```
|
||||||
|
|
||||||
## Files
|
## Files
|
||||||
|
|
||||||
### `picks.py`
|
### `picks.py`
|
||||||
- **Command**: `/draft`
|
- **Command**: `/draft`
|
||||||
- **Description**: Make a draft pick with FA player autocomplete
|
- **Description**: Make a draft pick with FA player autocomplete
|
||||||
|
- **Restriction**: Offseason only (week ≤ 0) via `@requires_draft_period` decorator
|
||||||
- **Parameters**:
|
- **Parameters**:
|
||||||
- `player` (required): Player name to draft (autocomplete shows FA players with position and sWAR)
|
- `player` (required): Player name to draft (autocomplete shows FA players with position and sWAR)
|
||||||
- **Service Dependencies**:
|
- **Service Dependencies**:
|
||||||
@ -19,6 +48,7 @@ This directory contains Discord slash commands for draft system operations.
|
|||||||
- `team_service.get_team_roster()`
|
- `team_service.get_team_roster()`
|
||||||
- `player_service.get_players_by_name()`
|
- `player_service.get_players_by_name()`
|
||||||
- `player_service.update_player_team()`
|
- `player_service.update_player_team()`
|
||||||
|
- `league_service.get_current_state()` (for period check)
|
||||||
|
|
||||||
## Key Features
|
## Key Features
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ from services.draft_list_service import draft_list_service
|
|||||||
from services.player_service import player_service
|
from services.player_service import player_service
|
||||||
from services.team_service import team_service
|
from services.team_service import team_service
|
||||||
from utils.logging import get_contextual_logger
|
from utils.logging import get_contextual_logger
|
||||||
from utils.decorators import logged_command
|
from utils.decorators import logged_command, requires_draft_period
|
||||||
from views.draft_views import create_draft_list_embed
|
from views.draft_views import create_draft_list_embed
|
||||||
from views.embeds import EmbedTemplate
|
from views.embeds import EmbedTemplate
|
||||||
|
|
||||||
@ -61,6 +61,7 @@ class DraftListCommands(commands.Cog):
|
|||||||
name="draft-list",
|
name="draft-list",
|
||||||
description="View your team's auto-draft queue"
|
description="View your team's auto-draft queue"
|
||||||
)
|
)
|
||||||
|
@requires_draft_period
|
||||||
@logged_command("/draft-list")
|
@logged_command("/draft-list")
|
||||||
async def draft_list_view(self, interaction: discord.Interaction):
|
async def draft_list_view(self, interaction: discord.Interaction):
|
||||||
"""Display team's draft list."""
|
"""Display team's draft list."""
|
||||||
@ -101,6 +102,7 @@ class DraftListCommands(commands.Cog):
|
|||||||
rank="Position in queue (optional, adds to end if not specified)"
|
rank="Position in queue (optional, adds to end if not specified)"
|
||||||
)
|
)
|
||||||
@discord.app_commands.autocomplete(player=fa_player_autocomplete)
|
@discord.app_commands.autocomplete(player=fa_player_autocomplete)
|
||||||
|
@requires_draft_period
|
||||||
@logged_command("/draft-list-add")
|
@logged_command("/draft-list-add")
|
||||||
async def draft_list_add(
|
async def draft_list_add(
|
||||||
self,
|
self,
|
||||||
@ -207,6 +209,7 @@ class DraftListCommands(commands.Cog):
|
|||||||
player="Player name to remove"
|
player="Player name to remove"
|
||||||
)
|
)
|
||||||
@discord.app_commands.autocomplete(player=fa_player_autocomplete)
|
@discord.app_commands.autocomplete(player=fa_player_autocomplete)
|
||||||
|
@requires_draft_period
|
||||||
@logged_command("/draft-list-remove")
|
@logged_command("/draft-list-remove")
|
||||||
async def draft_list_remove(
|
async def draft_list_remove(
|
||||||
self,
|
self,
|
||||||
@ -268,6 +271,7 @@ class DraftListCommands(commands.Cog):
|
|||||||
name="draft-list-clear",
|
name="draft-list-clear",
|
||||||
description="Clear your entire auto-draft queue"
|
description="Clear your entire auto-draft queue"
|
||||||
)
|
)
|
||||||
|
@requires_draft_period
|
||||||
@logged_command("/draft-list-clear")
|
@logged_command("/draft-list-clear")
|
||||||
async def draft_list_clear(self, interaction: discord.Interaction):
|
async def draft_list_clear(self, interaction: discord.Interaction):
|
||||||
"""Clear entire draft list."""
|
"""Clear entire draft list."""
|
||||||
|
|||||||
@ -16,7 +16,7 @@ from services.draft_pick_service import draft_pick_service
|
|||||||
from services.player_service import player_service
|
from services.player_service import player_service
|
||||||
from services.team_service import team_service
|
from services.team_service import team_service
|
||||||
from utils.logging import get_contextual_logger
|
from utils.logging import get_contextual_logger
|
||||||
from utils.decorators import logged_command
|
from utils.decorators import logged_command, requires_draft_period
|
||||||
from utils.draft_helpers import validate_cap_space, format_pick_display
|
from utils.draft_helpers import validate_cap_space, format_pick_display
|
||||||
from views.draft_views import (
|
from views.draft_views import (
|
||||||
create_player_draft_card,
|
create_player_draft_card,
|
||||||
@ -77,6 +77,7 @@ class DraftPicksCog(commands.Cog):
|
|||||||
player="Player name to draft (autocomplete shows available FA players)"
|
player="Player name to draft (autocomplete shows available FA players)"
|
||||||
)
|
)
|
||||||
@discord.app_commands.autocomplete(player=fa_player_autocomplete)
|
@discord.app_commands.autocomplete(player=fa_player_autocomplete)
|
||||||
|
@requires_draft_period
|
||||||
@logged_command("/draft")
|
@logged_command("/draft")
|
||||||
async def draft_pick(
|
async def draft_pick(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@ -12,6 +12,7 @@ from typing import List, Optional, Callable, Any
|
|||||||
from utils.logging import set_discord_context, get_contextual_logger
|
from utils.logging import set_discord_context, get_contextual_logger
|
||||||
|
|
||||||
cache_logger = logging.getLogger(f'{__name__}.CacheDecorators')
|
cache_logger = logging.getLogger(f'{__name__}.CacheDecorators')
|
||||||
|
period_check_logger = logging.getLogger(f'{__name__}.PeriodCheckDecorators')
|
||||||
|
|
||||||
|
|
||||||
def logged_command(
|
def logged_command(
|
||||||
@ -95,6 +96,89 @@ def logged_command(
|
|||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
|
def requires_draft_period(func):
|
||||||
|
"""
|
||||||
|
Decorator to restrict commands to draft period (week <= 0).
|
||||||
|
|
||||||
|
This decorator checks if the league is in the draft period (offseason)
|
||||||
|
before allowing the command to execute. If the league is in-season,
|
||||||
|
it returns an error message to the user.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
@discord.app_commands.command(name="draft")
|
||||||
|
@requires_draft_period
|
||||||
|
@logged_command("/draft")
|
||||||
|
async def draft_pick(self, interaction, player: str):
|
||||||
|
# Command only runs during draft period (week <= 0)
|
||||||
|
pass
|
||||||
|
|
||||||
|
Side Effects:
|
||||||
|
- Checks league current state via league_service
|
||||||
|
- Returns error embed if check fails
|
||||||
|
- Logs restriction events
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
- Must be applied to async methods with (self, interaction, ...) signature
|
||||||
|
- Should be placed before @logged_command decorator
|
||||||
|
- league_service must be available via import
|
||||||
|
"""
|
||||||
|
@wraps(func)
|
||||||
|
async def wrapper(self, interaction, *args, **kwargs):
|
||||||
|
# Import here to avoid circular imports
|
||||||
|
from services.league_service import league_service
|
||||||
|
from views.embeds import EmbedTemplate
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Check current league state
|
||||||
|
current = await league_service.get_current_state()
|
||||||
|
|
||||||
|
if not current:
|
||||||
|
period_check_logger.error("Could not retrieve league state for draft period check")
|
||||||
|
embed = EmbedTemplate.error(
|
||||||
|
"System Error",
|
||||||
|
"Could not verify draft period status. Please try again later."
|
||||||
|
)
|
||||||
|
await interaction.response.send_message(embed=embed, ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check if in draft period (week <= 0)
|
||||||
|
if current.week > 0:
|
||||||
|
period_check_logger.info(
|
||||||
|
f"Draft command blocked - current week: {current.week}",
|
||||||
|
extra={
|
||||||
|
"user_id": interaction.user.id,
|
||||||
|
"command": func.__name__,
|
||||||
|
"current_week": current.week
|
||||||
|
}
|
||||||
|
)
|
||||||
|
embed = EmbedTemplate.error(
|
||||||
|
"Not Available",
|
||||||
|
"Draft commands are only available in the offseason."
|
||||||
|
)
|
||||||
|
await interaction.response.send_message(embed=embed, ephemeral=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Week <= 0, allow command to proceed
|
||||||
|
period_check_logger.debug(
|
||||||
|
f"Draft period check passed - week {current.week}",
|
||||||
|
extra={"user_id": interaction.user.id, "command": func.__name__}
|
||||||
|
)
|
||||||
|
return await func(self, interaction, *args, **kwargs)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
period_check_logger.error(
|
||||||
|
f"Error in draft period check: {e}",
|
||||||
|
exc_info=True,
|
||||||
|
extra={"user_id": interaction.user.id, "command": func.__name__}
|
||||||
|
)
|
||||||
|
# Re-raise to let error handling in logged_command handle it
|
||||||
|
raise
|
||||||
|
|
||||||
|
# Preserve signature for Discord.py command registration
|
||||||
|
wrapper.__signature__ = inspect.signature(func) # type: ignore
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
def cached_api_call(ttl: Optional[int] = None, cache_key_suffix: str = ""):
|
def cached_api_call(ttl: Optional[int] = None, cache_key_suffix: str = ""):
|
||||||
"""
|
"""
|
||||||
Decorator to add Redis caching to service methods that return List[T].
|
Decorator to add Redis caching to service methods that return List[T].
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user