major-domo-v2/commands/examples/migration_example.py
Cal Corum 1d6fef51ab Consolidate season config variables to single source (v2.21.0)
Remove redundant sba_current_season and pd_current_season config values.
All code now uses sba_season and pd_season, which properly read from
environment variables. Fixes /team command defaulting to Season 12.

- Remove duplicate *_current_season constants from config.py
- Update 100+ references across commands, services, and utils
- sba_season defaults to 13, pd_season defaults to 10
- Environment variables SBA_SEASON/PD_SEASON now work correctly

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 16:12:16 -06:00

311 lines
11 KiB
Python

"""
Migration Example: Before and After Views v2.0
Shows how to upgrade existing commands to use the modern view system.
This demonstrates the transformation from basic embeds to interactive views.
"""
from typing import Optional, List
import discord
from discord.ext import commands
from config import get_config
from services.team_service import team_service
from models.team import Team
from utils.logging import get_contextual_logger
from views.embeds import EmbedTemplate, EmbedColors
from utils.decorators import logged_command
# Import new view components
from views import (
SBAEmbedTemplate,
EmbedTemplate,
EmbedColors,
TeamSelectionView,
PaginationView,
ConfirmationView,
DetailedInfoView
)
class MigrationExampleCommands(commands.Cog):
"""Example showing before/after migration to Views v2.0."""
def __init__(self, bot: commands.Bot):
self.bot = bot
self.logger = get_contextual_logger(f'{__name__}.MigrationExampleCommands')
# ========================================
# BEFORE: Traditional approach
# ========================================
@discord.app_commands.command(
name="teams-old",
description="List teams (old style - basic embed)"
)
@logged_command("/teams-old")
async def teams_old_style(self, interaction: discord.Interaction, season: Optional[int] = None):
"""Old style team listing - basic embed only."""
await interaction.response.defer()
season = season or get_config().sba_season
teams = await team_service.get_teams_by_season(season)
if not teams:
embed = EmbedTemplate.error(
title="No Teams Found",
description=f"No teams found for season {season}"
)
await interaction.followup.send(embed=embed)
return
# Sort teams by abbreviation
teams.sort(key=lambda t: t.abbrev)
# Create basic embed
embed = EmbedTemplate.create_base_embed(
title=f"SBA Teams - Season {season}",
color=EmbedColors.PRIMARY
)
# Simple list - limited functionality
team_list = "\n".join([f"**{team.abbrev}** - {team.lname}" for team in teams[:20]])
if len(teams) > 20:
team_list += f"\n... and {len(teams) - 20} more teams"
embed.add_field(name="Teams", value=team_list, inline=False)
embed.set_footer(text=f"Total: {len(teams)} teams")
await interaction.followup.send(embed=embed)
# ========================================
# AFTER: Modern Views v2.0 approach
# ========================================
@discord.app_commands.command(
name="teams-new",
description="List teams (new style - interactive with views)"
)
@logged_command("/teams-new")
async def teams_new_style(self, interaction: discord.Interaction, season: Optional[int] = None):
"""New style team listing - interactive with pagination and selection."""
await interaction.response.defer()
season = season or get_config().sba_season
teams = await team_service.get_teams_by_season(season)
if not teams:
embed = EmbedTemplate.warning(
title="No Teams Found",
description=f"No teams found for season {season}"
)
await interaction.followup.send(embed=embed)
return
# Sort teams by abbreviation
teams.sort(key=lambda t: t.abbrev)
# Create paginated view with team selection
await self._create_interactive_team_list(interaction, teams, season)
async def _create_interactive_team_list(
self,
interaction: discord.Interaction,
teams: List[Team],
season: int
):
"""Create interactive team list with pagination and selection."""
teams_per_page = 10
pages = []
# Create pages
for i in range(0, len(teams), teams_per_page):
page_teams = teams[i:i + teams_per_page]
embed = SBAEmbedTemplate.league_status(
season=season,
teams_count=len(teams),
additional_info=f"Showing teams {i + 1}-{min(i + teams_per_page, len(teams))} of {len(teams)}"
)
embed.title = f"🏟️ SBA Teams - Season {season}"
# Group teams by division if available
if any(getattr(team, 'division_id', None) for team in page_teams):
divisions = {}
for team in page_teams:
div_id = getattr(team, 'division_id', 0) or 0
if div_id not in divisions:
divisions[div_id] = []
divisions[div_id].append(team)
for div_id, div_teams in sorted(divisions.items()):
div_name = f"Division {div_id}" if div_id > 0 else "Unassigned"
team_list = "\n".join([
f"**{team.abbrev}** - {team.lname}"
for team in div_teams
])
embed.add_field(name=div_name, value=team_list, inline=True)
else:
# Simple list if no divisions
team_list = "\n".join([
f"**{team.abbrev}** - {team.lname}"
for team in page_teams
])
embed.add_field(name="Teams", value=team_list, inline=False)
pages.append(embed)
# Create pagination view
view = PaginationView(
pages=pages,
user_id=interaction.user.id,
show_page_numbers=True
)
# Add team selection dropdown to first row
if len(teams) <= 25: # Discord limit for select options
team_select = TeamSelectionView(
teams=teams,
user_id=interaction.user.id,
callback=self._handle_team_selection
)
# Combine pagination with selection (would need custom view for this)
# For now, show them separately
await interaction.followup.send(embed=view.get_current_embed(), view=view)
# Also provide team selection if reasonable number
if len(teams) <= 25:
await self._add_team_selection_followup(interaction, teams)
async def _add_team_selection_followup(
self,
interaction: discord.Interaction,
teams: List[Team]
):
"""Add team selection as follow-up message."""
view = TeamSelectionView(
teams=teams,
user_id=interaction.user.id,
callback=self._handle_team_selection
)
embed = EmbedTemplate.info(
title="Team Selection",
description="Select a team below to view detailed information:"
)
await interaction.followup.send(embed=embed, view=view, ephemeral=True)
async def _handle_team_selection(
self,
interaction: discord.Interaction,
team: Team
):
"""Handle team selection from dropdown."""
# Get additional team data
standings_data = await team_service.get_team_standings_position(team.id, team.season)
# Create detailed team embed
embed = SBAEmbedTemplate.team_info(
team_abbrev=team.abbrev,
team_name=team.lname,
season=team.season,
short_name=getattr(team, 'sname', None),
stadium=getattr(team, 'stadium', None),
division=f"Division {team.division_id}" if getattr(team, 'division_id', None) else None,
team_color=getattr(team, 'color', None),
team_thumbnail=getattr(team, 'thumbnail', None)
)
# Add standings info if available
if standings_data:
try:
wins = standings_data.get('wins', 'N/A')
losses = standings_data.get('losses', 'N/A')
pct = standings_data.get('pct', 'N/A')
gb = standings_data.get('gb', 'N/A')
record_text = f"{wins}-{losses}"
if pct != 'N/A':
record_text += f" ({pct:.3f})"
if gb != 'N/A' and gb != 0:
record_text += f"{gb} GB"
embed.add_field(name="Record", value=record_text, inline=False)
except (KeyError, TypeError):
pass
# Create detailed info view with actions
async def refresh_team_data(interaction: discord.Interaction) -> discord.Embed:
"""Refresh team data."""
updated_standings = await team_service.get_team_standings_position(team.id, team.season)
# Recreate embed with updated data
return embed # Simplified for example
async def show_roster(interaction: discord.Interaction):
"""Show team roster."""
roster_embed = EmbedTemplate.info(
title=f"{team.abbrev} Roster",
description="Roster functionality would go here..."
)
await interaction.response.send_message(embed=roster_embed, ephemeral=True)
view = DetailedInfoView(
embed=embed,
user_id=interaction.user.id,
show_refresh=True,
show_details=True,
refresh_callback=refresh_team_data,
details_callback=show_roster
)
await interaction.response.edit_message(embed=embed, view=view)
# ========================================
# Additional Examples
# ========================================
@discord.app_commands.command(
name="confirmation-example",
description="Example of confirmation dialog"
)
@logged_command("/confirmation-example")
async def confirmation_example(self, interaction: discord.Interaction):
"""Example of modern confirmation dialog."""
embed = EmbedTemplate.warning(
title="Confirm Action",
description="This is an example confirmation dialog. Do you want to proceed?"
)
async def handle_confirm(interaction: discord.Interaction):
"""Handle confirmation."""
success_embed = EmbedTemplate.success(
title="Action Confirmed",
description="The action has been completed successfully!"
)
await interaction.response.edit_message(embed=success_embed, view=None)
async def handle_cancel(interaction: discord.Interaction):
"""Handle cancellation."""
cancel_embed = EmbedTemplate.error(
title="Action Cancelled",
description="The action has been cancelled."
)
await interaction.response.edit_message(embed=cancel_embed, view=None)
view = ConfirmationView(
user_id=interaction.user.id,
confirm_callback=handle_confirm,
cancel_callback=handle_cancel,
confirm_label="Yes, Proceed",
cancel_label="No, Cancel"
)
await interaction.response.send_message(embed=embed, view=view)
async def setup(bot: commands.Bot):
"""Load the migration example commands cog."""
await bot.add_cog(MigrationExampleCommands(bot))