Fixed TypeError: 'Team' object is not subscriptable error occurring at the end of /gauntlet start command when sending completion messages. The get_roster_sheet() function was using dict syntax (team["gsheet"]) but was receiving Team objects from gauntlet commands. Updated the function to handle both dict and Team object formats using isinstance() check. This follows the same pattern as get_context_user() and owner_only() for handling multiple input types gracefully. Fixes: Command 'start' raised an exception: TypeError: 'Team' object is not subscriptable (reported at end of gauntlet draft completion) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
173 lines
5.5 KiB
Python
173 lines
5.5 KiB
Python
"""
|
|
General Utilities
|
|
|
|
This module contains standalone utility functions with minimal dependencies,
|
|
including timestamp conversion, position abbreviations, and simple helpers.
|
|
"""
|
|
import datetime
|
|
import discord
|
|
|
|
|
|
def int_timestamp():
|
|
"""Convert current datetime to integer timestamp."""
|
|
return int(datetime.datetime.now().timestamp())
|
|
|
|
|
|
def get_pos_abbrev(field_pos: str) -> str:
|
|
"""Convert position name to standard abbreviation."""
|
|
if field_pos.lower() == 'catcher':
|
|
return 'C'
|
|
elif field_pos.lower() == 'first baseman':
|
|
return '1B'
|
|
elif field_pos.lower() == 'second baseman':
|
|
return '2B'
|
|
elif field_pos.lower() == 'third baseman':
|
|
return '3B'
|
|
elif field_pos.lower() == 'shortstop':
|
|
return 'SS'
|
|
elif field_pos.lower() == 'left fielder':
|
|
return 'LF'
|
|
elif field_pos.lower() == 'center fielder':
|
|
return 'CF'
|
|
elif field_pos.lower() == 'right fielder':
|
|
return 'RF'
|
|
else:
|
|
return 'P'
|
|
|
|
|
|
def position_name_to_abbrev(position_name):
|
|
"""Convert position name to abbreviation (alternate format)."""
|
|
if position_name == 'Catcher':
|
|
return 'C'
|
|
elif position_name == 'First Base':
|
|
return '1B'
|
|
elif position_name == 'Second Base':
|
|
return '2B'
|
|
elif position_name == 'Third Base':
|
|
return '3B'
|
|
elif position_name == 'Shortstop':
|
|
return 'SS'
|
|
elif position_name == 'Left Field':
|
|
return 'LF'
|
|
elif position_name == 'Center Field':
|
|
return 'CF'
|
|
elif position_name == 'Right Field':
|
|
return 'RF'
|
|
elif position_name == 'Pitcher':
|
|
return 'P'
|
|
else:
|
|
return position_name
|
|
|
|
|
|
def user_has_role(user: discord.User | discord.Member, role_name: str) -> bool:
|
|
"""Check if a Discord user has a specific role."""
|
|
for x in user.roles:
|
|
if x.name == role_name:
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
def get_roster_sheet_legacy(team):
|
|
"""Get legacy roster sheet URL for a team."""
|
|
return f'https://docs.google.com/spreadsheets/d/{team.gsheet}/edit'
|
|
|
|
|
|
def get_roster_sheet(team):
|
|
"""
|
|
Get roster sheet URL for a team.
|
|
|
|
Handles both dict and Team object formats.
|
|
"""
|
|
# Handle both dict (team["gsheet"]) and object (team.gsheet) formats
|
|
gsheet = team.get("gsheet") if isinstance(team, dict) else getattr(team, "gsheet", None)
|
|
return f'https://docs.google.com/spreadsheets/d/{gsheet}/edit'
|
|
|
|
|
|
def get_player_url(team, player) -> str:
|
|
"""Generate player URL for SBA or Baseball Reference."""
|
|
if team.get('league') == 'SBA':
|
|
return f'https://statsplus.net/super-baseball-association/player/{player["player_id"]}'
|
|
else:
|
|
return f'https://www.baseball-reference.com/players/{player["bbref_id"][0]}/{player["bbref_id"]}.shtml'
|
|
|
|
|
|
def owner_only(ctx) -> bool:
|
|
"""Check if user is the bot owner."""
|
|
# ID for discord User Cal
|
|
owners = [287463767924137994, 1087936030899347516]
|
|
|
|
# Handle both Context (has .author) and Interaction (has .user) objects
|
|
user = getattr(ctx, 'user', None) or getattr(ctx, 'author', None)
|
|
|
|
if user and user.id in owners:
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
def get_context_user(ctx):
|
|
"""
|
|
Get the user from either a Context or Interaction object.
|
|
|
|
Hybrid commands can receive either commands.Context (from prefix commands)
|
|
or discord.Interaction (from slash commands). This helper safely extracts
|
|
the user from either type.
|
|
|
|
Returns:
|
|
discord.User or discord.Member: The user who invoked the command
|
|
"""
|
|
# Handle both Context (has .author) and Interaction (has .user) objects
|
|
return getattr(ctx, 'user', None) or getattr(ctx, 'author', None)
|
|
|
|
|
|
def get_cal_user(ctx):
|
|
"""Get the Cal user from context. Always returns an object with .mention attribute."""
|
|
import logging
|
|
logger = logging.getLogger('discord_app')
|
|
|
|
# Define placeholder user class first
|
|
class PlaceholderUser:
|
|
def __init__(self):
|
|
self.mention = "<@287463767924137994>"
|
|
self.id = 287463767924137994
|
|
|
|
# Handle both Context and Interaction objects
|
|
if hasattr(ctx, 'bot'): # Context object
|
|
bot = ctx.bot
|
|
logger.debug("get_cal_user: Using Context object")
|
|
elif hasattr(ctx, 'client'): # Interaction object
|
|
bot = ctx.client
|
|
logger.debug("get_cal_user: Using Interaction object")
|
|
else:
|
|
logger.error("get_cal_user: No bot or client found in context")
|
|
return PlaceholderUser()
|
|
|
|
if not bot:
|
|
logger.error("get_cal_user: bot is None")
|
|
return PlaceholderUser()
|
|
|
|
logger.debug(f"get_cal_user: Searching among members")
|
|
try:
|
|
for user in bot.get_all_members():
|
|
if user.id == 287463767924137994:
|
|
logger.debug("get_cal_user: Found user in get_all_members")
|
|
return user
|
|
except Exception as e:
|
|
logger.error(f"get_cal_user: Exception in get_all_members: {e}")
|
|
|
|
# Fallback: try to get user directly by ID
|
|
logger.debug("get_cal_user: User not found in get_all_members, trying get_user")
|
|
try:
|
|
user = bot.get_user(287463767924137994)
|
|
if user:
|
|
logger.debug("get_cal_user: Found user via get_user")
|
|
return user
|
|
else:
|
|
logger.debug("get_cal_user: get_user returned None")
|
|
except Exception as e:
|
|
logger.error(f"get_cal_user: Exception in get_user: {e}")
|
|
|
|
# Last resort: return a placeholder user object with mention
|
|
logger.debug("get_cal_user: Using placeholder user")
|
|
return PlaceholderUser() |