295 lines
13 KiB
Python
295 lines
13 KiB
Python
# Players Lookup Module - Fixed Functions
|
|
# Contains corrected functions that don't meet business requirements from the original players.py
|
|
|
|
from discord.ext import commands
|
|
from discord import app_commands
|
|
import discord
|
|
from typing import Optional
|
|
|
|
# Import specific utilities needed by this module
|
|
import logging
|
|
from discord.ext import tasks
|
|
from api_calls import db_get
|
|
from helpers.constants import ALL_CARDSET_NAMES
|
|
from helpers import (
|
|
PD_PLAYERS_ROLE_NAME, IMAGES, PD_SEASON, get_card_embeds,
|
|
get_blank_team_card, get_team_by_owner,
|
|
legal_channel, embed_pagination, Confirm, player_desc,
|
|
is_ephemeral_channel, is_restricted_channel, can_send_message
|
|
)
|
|
from helpers.search_utils import fuzzy_search, cardset_search
|
|
from discord_ui import SelectUpdatePlayerTeam, SelectView
|
|
|
|
logger = logging.getLogger('discord_app')
|
|
|
|
|
|
class PlayerLookup(commands.Cog):
|
|
"""Player card display and lookup functionality for Paper Dynasty."""
|
|
|
|
def __init__(self, bot):
|
|
self.bot = bot
|
|
self.player_list = []
|
|
self.cardset_list = []
|
|
|
|
@tasks.loop(hours=18) # Match old frequency
|
|
async def build_player_list(self):
|
|
"""Background task to build fuzzy player search list."""
|
|
logger.debug('Rebuilding player list for fuzzy searching')
|
|
|
|
# Get players with flat=True parameter like original
|
|
all_players = await db_get('players', params=[('flat', True), ('inc_dex', False)], timeout=25)
|
|
all_cardsets = await db_get('cardsets', params=[('flat', True)])
|
|
|
|
if not all_players:
|
|
logger.error('Failed to get players for fuzzy list')
|
|
return
|
|
|
|
self.player_list = []
|
|
# Build list using p_name.lower() like original, avoiding duplicates
|
|
[self.player_list.append(x['p_name'].lower()) for x in all_players['players']
|
|
if x['p_name'] and x['p_name'].lower() not in self.player_list]
|
|
|
|
logger.info(f'There are now {len(self.player_list)} player names in the fuzzy search list.')
|
|
|
|
# Build cardset list
|
|
if all_cardsets:
|
|
self.cardset_list = [x['name'].lower() for x in all_cardsets['cardsets']]
|
|
logger.info(f'There are now {len(self.cardset_list)} cardsets in the fuzzy search list.')
|
|
|
|
@build_player_list.before_loop
|
|
async def before_build_player_list(self):
|
|
"""Wait for bot to be ready before starting task."""
|
|
await self.bot.wait_until_ready()
|
|
|
|
async def cog_load(self):
|
|
"""Start background tasks when cog loads."""
|
|
logger.info(f'Building player list')
|
|
self.build_player_list.start()
|
|
|
|
async def cog_unload(self):
|
|
"""Stop background tasks when cog unloads."""
|
|
self.build_player_list.cancel()
|
|
|
|
@commands.command(name='player', help='For specific cardset, run /player', aliases=['show', 'card'])
|
|
@commands.has_any_role(PD_PLAYERS_ROLE_NAME)
|
|
@commands.check(legal_channel)
|
|
async def player_command(self, ctx, *, _name_or_id):
|
|
"""Legacy player lookup command."""
|
|
await ctx.send('This command has been replaced by the `/player` slash command. Please use that instead!')
|
|
|
|
@app_commands.command(name='player', description='Display one or more of the player\'s cards')
|
|
@app_commands.checks.has_any_role(PD_PLAYERS_ROLE_NAME)
|
|
async def player_slash_command(
|
|
self, interaction: discord.Interaction, player_name: str, # Changed from name_or_id to match original
|
|
cardset: ALL_CARDSET_NAMES = 'All',
|
|
player_team: Optional[str] = None):
|
|
"""Display player cards with filtering options."""
|
|
ephemeral = is_ephemeral_channel(interaction.channel)
|
|
|
|
await interaction.response.defer(ephemeral=ephemeral)
|
|
|
|
# Use fuzzy_search like the original instead of get_close_matches
|
|
this_player = fuzzy_search(player_name, self.player_list)
|
|
if not this_player:
|
|
await interaction.edit_original_response(content=f'No clue who that is.')
|
|
return
|
|
|
|
# Build params like original
|
|
if cardset and cardset != 'All':
|
|
this_cardset = await cardset_search(cardset, self.cardset_list)
|
|
if this_cardset:
|
|
all_params = [('name', this_player), ('cardset_id', this_cardset['id'])]
|
|
else:
|
|
await interaction.edit_original_response(content=f'I couldn\'t find {cardset} cardset.')
|
|
return
|
|
else:
|
|
all_params = [('name', this_player)]
|
|
|
|
all_players = await db_get('players', params=all_params)
|
|
if not all_players or all_players.get('count', 0) == 0:
|
|
await interaction.edit_original_response(content='No players found')
|
|
return
|
|
|
|
# Apply player_team filter if provided
|
|
if player_team and all_players:
|
|
filtered_players = [p for p in all_players.get('players', [])
|
|
if p.get('franchise', '').upper() == player_team.upper()]
|
|
all_players['players'] = filtered_players
|
|
if not filtered_players:
|
|
await interaction.edit_original_response(content='No players found matching your filters.')
|
|
return
|
|
|
|
# Create cards with blank team like original
|
|
if not all_players:
|
|
await interaction.edit_original_response(content='No players found')
|
|
return
|
|
all_cards = [get_blank_team_card(x) for x in all_players.get('players', [])]
|
|
all_cards.sort(key=lambda x: x['player']['rarity']['value'], reverse=True)
|
|
|
|
all_embeds = []
|
|
for x in all_cards:
|
|
all_embeds.extend(await get_card_embeds(x, include_stats=True))
|
|
logger.debug(f'embeds: {all_embeds}')
|
|
|
|
if len(all_embeds) > 1 and all_players and all_players.get('players'):
|
|
await interaction.edit_original_response(content=f'# {all_players["players"][0]["p_name"]}')
|
|
|
|
# Handle User | Member type for embed_pagination
|
|
if isinstance(interaction.user, discord.Member):
|
|
await embed_pagination(all_embeds, interaction.channel, interaction.user, timeout=20, start_page=0)
|
|
elif interaction.guild:
|
|
member = interaction.guild.get_member(interaction.user.id)
|
|
if member:
|
|
await embed_pagination(all_embeds, interaction.channel, member, timeout=20, start_page=0)
|
|
else:
|
|
# Fallback: send embeds one by one if we can't get member
|
|
for embed in all_embeds[:5]: # Limit to prevent spam
|
|
await interaction.followup.send(embed=embed)
|
|
else:
|
|
# DM context - send embeds one by one
|
|
for embed in all_embeds[:5]: # Limit to prevent spam
|
|
await interaction.followup.send(embed=embed)
|
|
else:
|
|
await interaction.edit_original_response(content=None, embed=all_embeds[0])
|
|
|
|
@app_commands.command(name='update-player', description='Update a player\'s card to a specific MLB team')
|
|
@app_commands.checks.has_any_role(PD_PLAYERS_ROLE_NAME)
|
|
async def update_player_team(self, interaction: discord.Interaction, player_id: int):
|
|
"""Update a player's MLB team affiliation."""
|
|
|
|
owner_team = await get_team_by_owner(interaction.user.id)
|
|
if not owner_team:
|
|
await interaction.response.send_message(
|
|
'Thank you for offering to help - if you sign up for a team with /newteam I can let you post updates.',
|
|
ephemeral=True
|
|
)
|
|
return
|
|
|
|
if is_restricted_channel(interaction.channel):
|
|
await interaction.response.send_message(
|
|
f'Slide on down to #pd-bot-hole to run updates - thanks!',
|
|
ephemeral=True
|
|
)
|
|
return # Missing return in original causes issue
|
|
|
|
await interaction.response.defer()
|
|
|
|
# Use object_id parameter like original
|
|
this_player = await db_get('players', object_id=player_id)
|
|
if not this_player:
|
|
await interaction.edit_original_response(content=f'No clue who that is.') # Use edit instead of response
|
|
return
|
|
|
|
# Show player card for confirmation
|
|
embeds = await get_card_embeds(get_blank_team_card(this_player))
|
|
await interaction.edit_original_response(content=None, embed=embeds[0])
|
|
|
|
# Confirm this is the right player - use channel.send like original
|
|
view = Confirm(responders=[interaction.user])
|
|
if can_send_message(interaction.channel):
|
|
question = await interaction.channel.send(
|
|
content='Is this the player you want to update?',
|
|
view=view
|
|
)
|
|
else:
|
|
question = await interaction.followup.send(
|
|
content='Is this the player you want to update?',
|
|
view=view
|
|
)
|
|
await view.wait()
|
|
|
|
if not view.value:
|
|
if question:
|
|
await question.edit(content='Okay, we\'ll leave it be.', view=None)
|
|
return
|
|
else:
|
|
if question:
|
|
await question.delete()
|
|
|
|
# Show team selection dropdowns - use channel.send like original
|
|
view = SelectView([
|
|
SelectUpdatePlayerTeam('AL', this_player, owner_team, self.bot),
|
|
SelectUpdatePlayerTeam('NL', this_player, owner_team, self.bot)
|
|
])
|
|
if can_send_message(interaction.channel):
|
|
await interaction.channel.send(content='Select the new team:', view=view)
|
|
else:
|
|
await interaction.followup.send(content='Select the new team:', view=view)
|
|
|
|
group_lookup = app_commands.Group(name='lookup', description='Lookup commands for cards and players')
|
|
|
|
@group_lookup.command(name='card-id', description='Look up individual card by ID')
|
|
@app_commands.checks.has_any_role(PD_PLAYERS_ROLE_NAME)
|
|
async def lookup_card_by_id(self, interaction: discord.Interaction, card_id: int):
|
|
"""Look up a specific card by its ID."""
|
|
|
|
await interaction.response.defer()
|
|
|
|
# Use object_id parameter like original
|
|
c_query = await db_get('cards', object_id=card_id)
|
|
if c_query:
|
|
# Include ownership and pack information like original
|
|
c_string = f'Card ID {card_id} is a {player_desc(c_query["player"])}'
|
|
if c_query['team'] is not None:
|
|
c_string += f' owned by the {c_query["team"]["sname"]}'
|
|
if c_query["pack"] is not None:
|
|
c_string += f' pulled from a {c_query["pack"]["pack_type"]["name"]} pack.'
|
|
else:
|
|
c_query['team'] = c_query["pack"]["team"]
|
|
c_string += f' used by the {c_query["pack"]["team"]["sname"]} in a gauntlet'
|
|
|
|
await interaction.edit_original_response(
|
|
content=c_string,
|
|
embeds=await get_card_embeds(c_query) # Pass card directly, not wrapped
|
|
)
|
|
return
|
|
|
|
await interaction.edit_original_response(content=f'There is no card with ID {card_id}')
|
|
|
|
@group_lookup.command(name='player-id', description='Look up an individual player by ID')
|
|
@app_commands.checks.has_any_role(PD_PLAYERS_ROLE_NAME)
|
|
async def lookup_player_by_id(self, interaction: discord.Interaction, player_id: int):
|
|
"""Look up a player by their ID."""
|
|
|
|
await interaction.response.defer()
|
|
|
|
# Use object_id parameter like original
|
|
p_query = await db_get('players', object_id=player_id)
|
|
if p_query:
|
|
p_card = get_blank_team_card(p_query)
|
|
embeds = await get_card_embeds(p_card)
|
|
|
|
if embeds:
|
|
# Original doesn't handle multiple embeds for single player lookup
|
|
await interaction.edit_original_response(
|
|
content=None,
|
|
embeds=embeds # Pass all embeds like original
|
|
)
|
|
else:
|
|
await interaction.edit_original_response(content='Could not generate card display for this player')
|
|
return
|
|
|
|
await interaction.edit_original_response(content=f'There is no player with ID {player_id}.')
|
|
|
|
@commands.hybrid_command(name='random', help='Check out a random card') # Use hybrid_command like original
|
|
@commands.has_any_role(PD_PLAYERS_ROLE_NAME)
|
|
@commands.check(legal_channel)
|
|
async def random_card_command(self, ctx: commands.Context): # Use Context instead of Interaction
|
|
"""Display a random player card."""
|
|
|
|
p_query = await db_get('players/random', params=[('limit', 1)])
|
|
if not p_query or not p_query.get('count'):
|
|
await ctx.send('Could not find any random players')
|
|
return
|
|
|
|
this_player = p_query['players'][0]
|
|
# Use blank team card structure like original
|
|
this_embed = await get_card_embeds(
|
|
{'player': this_player, 'team': {'lname': 'Paper Dynasty', 'logo': IMAGES['logo'], 'season': PD_SEASON}}
|
|
)
|
|
await ctx.send(content=None, embeds=this_embed)
|
|
|
|
|
|
async def setup(bot):
|
|
"""Setup function for the PlayerLookup cog."""
|
|
await bot.add_cog(PlayerLookup(bot)) |