major-domo-v2/utils/discord_helpers.py
Cal Corum 858663cd27 refactor: move 42 unnecessary lazy imports to top-level across codebase
Codebase audit identified ~50 lazy imports. Moved 42 unnecessary ones to
top-level imports — only keeping those justified by circular imports,
init-order dependencies, or optional dependency guards. Updated test mock
patch targets where needed. See #57 for remaining DI candidates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 13:35:23 -06:00

163 lines
4.5 KiB
Python

"""
Discord Helper Utilities
Common Discord-related helper functions for channel lookups,
message sending, and formatting.
"""
from typing import Optional, List
import discord
from discord.ext import commands
from config import get_config
from models.play import Play
from models.team import Team
from utils.logging import get_contextual_logger
logger = get_contextual_logger(__name__)
async def get_channel_by_name(
bot: commands.Bot, channel_name: str
) -> Optional[discord.TextChannel]:
"""
Get a text channel by name from the configured guild.
Args:
bot: Discord bot instance
channel_name: Name of the channel to find
Returns:
TextChannel if found, None otherwise
"""
config = get_config()
guild_id = config.guild_id
if not guild_id:
logger.error("GUILD_ID not configured")
return None
guild = bot.get_guild(guild_id)
if not guild:
logger.error(f"Guild {guild_id} not found")
return None
channel = discord.utils.get(guild.text_channels, name=channel_name)
if not channel:
logger.warning(f"Channel '{channel_name}' not found in guild {guild_id}")
return None
return channel
async def send_to_channel(
bot: commands.Bot,
channel_name: str,
content: Optional[str] = None,
embed: Optional[discord.Embed] = None,
) -> bool:
"""
Send a message to a channel by name.
Args:
bot: Discord bot instance
channel_name: Name of the channel
content: Text content to send
embed: Embed to send
Returns:
True if message sent successfully, False otherwise
"""
channel = await get_channel_by_name(bot, channel_name)
if not channel:
logger.error(f"Cannot send to channel '{channel_name}' - not found")
return False
try:
# Build kwargs to avoid passing None for embed
kwargs = {}
if content is not None:
kwargs["content"] = content
if embed is not None:
kwargs["embed"] = embed
await channel.send(**kwargs)
logger.info(f"Sent message to #{channel_name}")
return True
except Exception as e:
logger.error(f"Failed to send message to #{channel_name}: {e}")
return False
def format_key_plays(plays: List[Play], away_team: Team, home_team: Team) -> str:
"""
Format top plays into embed field text.
Args:
plays: List of Play objects (should be sorted by WPA)
away_team: Away team object
home_team: Home team object
Returns:
Formatted string for embed field, or empty string if no plays
"""
if not plays:
return ""
key_plays_text = ""
for play in plays:
# Use the Play.descriptive_text() method (already includes score)
play_description = play.descriptive_text(away_team, home_team)
key_plays_text += f"{play_description}\n"
return key_plays_text
async def set_channel_visibility(
channel: discord.TextChannel, visible: bool, reason: Optional[str] = None
) -> bool:
"""
Set channel visibility for @everyone.
The bot's permissions are based on its role, not @everyone, so the bot
will retain access even when @everyone view permission is removed.
Args:
channel: Discord text channel to modify
visible: If True, grant @everyone view permission; if False, deny it
reason: Optional reason for audit log
Returns:
True if permissions updated successfully, False otherwise
"""
try:
guild = channel.guild
everyone_role = guild.default_role
if visible:
# Grant @everyone permission to view channel
default_reason = "Channel made visible to all members"
await channel.set_permissions(
everyone_role, view_channel=True, reason=reason or default_reason
)
logger.info(f"Set #{channel.name} to VISIBLE for @everyone")
else:
# Remove @everyone view permission
default_reason = "Channel hidden from members"
await channel.set_permissions(
everyone_role, view_channel=False, reason=reason or default_reason
)
logger.info(f"Set #{channel.name} to HIDDEN for @everyone")
return True
except discord.Forbidden:
logger.error(f"Missing permissions to modify #{channel.name} permissions")
return False
except Exception as e:
logger.error(f"Error setting channel visibility for #{channel.name}: {e}")
return False