From c253ae90a3ae278ab0d514e198e3ddfd95f60ea4 Mon Sep 17 00:00:00 2001 From: Cal Corum Date: Mon, 14 Oct 2024 01:17:09 -0500 Subject: [PATCH] Migrate Confirm class to utilities --- cogs/admins.py | 3 +- cogs/gameplay.py | 42 +++++++++- in_game/gameplay_models.py | 102 ++++++++++++----------- tests/gameplay_models/test_game_model.py | 8 ++ utilities/confirm.py | 35 ++++++++ 5 files changed, 135 insertions(+), 55 deletions(-) create mode 100644 utilities/confirm.py diff --git a/cogs/admins.py b/cogs/admins.py index c16792b..5518d91 100644 --- a/cogs/admins.py +++ b/cogs/admins.py @@ -569,8 +569,7 @@ class Admins(commands.Cog): cardsets = session.exec(select(Cardset.id)).all() lineups = session.exec(select(Lineup.id)).all() teams = session.exec(select(Team.id)).all() - # players = session.exec(select(Player.id)).all() - players = [] + players = session.exec(select(Player.id)).all() output = f'## Database Counts\nGames: {len(games)}\nCardsets: {len(cardsets)}\nLineups: {len(lineups)}\nTeams: {len(teams)}\nPlayers: {len(players)}' diff --git a/cogs/gameplay.py b/cogs/gameplay.py index ba82484..ae18431 100644 --- a/cogs/gameplay.py +++ b/cogs/gameplay.py @@ -9,13 +9,15 @@ from discord.app_commands import Choice from discord.ext import commands from api_calls import db_get -from helpers import PD_PLAYERS_ROLE_NAME, team_role, user_has_role +from helpers import PD_PLAYERS_ROLE_NAME, team_role, user_has_role, random_gif, random_from_list + from in_game import ai_manager from in_game.game_helpers import PUBLIC_FIELDS_CATEGORY_NAME, legal_check -from in_game.data_cache import get_pd_team -from in_game.gameplay_models import Lineup, Session, engine, get_card_or_none, get_player_or_none, player_description, select, Game, get_team_or_none +from in_game.gameplay_models import Lineup, Session, engine, get_card_or_none, player_description, select, Game, get_team_or_none from in_game.gameplay_queries import get_channel_game_or_none, get_active_games_by_team +from utilities.confirm import Confirm + class Gameplay(commands.Cog): def __init__(self, bot): @@ -203,9 +205,41 @@ class Gameplay(commands.Cog): await final_message.edit( content=f'{away_role.mention} @ {home_role.mention} is set!\n\n' f'Go ahead and set lineups with the `/read-lineup` command!', - # embed=this_game.get_scorebug(full_length=False) + embed=this_game.get_scorebug(full_length=False) ) + @commands.command(name='force-endgame', help='Mod: Force a game to end without stats') + async def force_end_game_command(self, ctx: commands.Context): + with Session(engine) as session: + this_game = get_channel_game_or_none(session, ctx.channel.id) + + if this_game is None: + await ctx.send(f'I do not see a game here - are you in the right place?') + return + + await ctx.send( + content=None, + embed=this_game.get_scorebug(full_length=True) + ) + + view = Confirm(responders=[ctx.author], timeout=60, label_type='confirm') + question = await ctx.send(f'Is this the game I should nuke?', view=view) + await view.wait() + + if view.value: + session.delete(this_game) + session.commit() + await question.edit( + content=random_gif(random_from_list([ + 'i killed it', 'deed is done', 'gone forever' + ])), + view=None + ) + else: + await question.edit( + content=f'~~Is this the game I should nuke?~~\n\nIt stays.', + view=None + ) async def setup(bot): diff --git a/in_game/gameplay_models.py b/in_game/gameplay_models.py index 9152d81..a5a700f 100644 --- a/in_game/gameplay_models.py +++ b/in_game/gameplay_models.py @@ -22,55 +22,6 @@ class GameCardsetLink(SQLModel, table=True): cardset: 'Cardset' = Relationship(back_populates='game_links') -class Game(SQLModel, table=True): - id: int | None = Field(default=None, primary_key=True) - away_team_id: int - home_team_id: int - channel_id: int = Field(index=True) - season: int - active: bool | None = Field(default=True) - is_pd: bool | None = Field(default=True) - ranked: bool | None = Field(default=False) - short_game: bool | None = Field(default=False) - week_num: int | None = Field(default=None) - game_num: int | None = Field(default=None) - away_roster_id: int | None = Field(default=None) - home_roster_id: int | None = Field(default=None) - first_message: str | None = Field(default=None) - ai_team: str | None = Field(default=None) - game_type: str | None = Field(default=None) - - cardset_links: list[GameCardsetLink] = Relationship(back_populates='game', cascade_delete=True) - lineups: list['Lineup'] = Relationship(back_populates='game', cascade_delete=True) - - @property - def cardset_param_string(self) -> str: - pri_cardsets = '' - back_cardsets = '' - for link in self.cardset_links: - if link.priority == 1: - pri_cardsets += f'&cardset_id={link.cardset_id}' - else: - back_cardsets += f'&backup_cardset_id={link.cardset_id}' - return f'{pri_cardsets}{back_cardsets}' - - # @property - # def game_prop(self) -> str: - # return f'Game {self.id} / Week {self.week_num} / Type {self.game_type}' - - - -class CardsetBase(SQLModel): - id: int | None = Field(default=None, primary_key=True) - name: str - ranked_legal: bool | None = Field(default=False) - - -class Cardset(CardsetBase, table=True): - game_links: list[GameCardsetLink] = Relationship(back_populates='cardset', cascade_delete=True) - players: list['Player'] = Relationship(back_populates='cardset') - - class TeamBase(SQLModel): id: int = Field(primary_key=True) abbrev: str = Field(index=True) @@ -159,6 +110,59 @@ async def get_team_or_none( return None +class Game(SQLModel, table=True): + id: int | None = Field(default=None, primary_key=True) + away_team_id: int + home_team_id: int + channel_id: int = Field(index=True) + season: int + active: bool | None = Field(default=True) + is_pd: bool | None = Field(default=True) + ranked: bool | None = Field(default=False) + short_game: bool | None = Field(default=False) + week_num: int | None = Field(default=None) + game_num: int | None = Field(default=None) + away_roster_id: int | None = Field(default=None) + home_roster_id: int | None = Field(default=None) + first_message: str | None = Field(default=None) + ai_team: str | None = Field(default=None) + game_type: str | None = Field(default=None) + + cardset_links: list[GameCardsetLink] = Relationship(back_populates='game', cascade_delete=True) + lineups: list['Lineup'] = Relationship(back_populates='game', cascade_delete=True) + + @property + def cardset_param_string(self) -> str: + pri_cardsets = '' + back_cardsets = '' + for link in self.cardset_links: + if link.priority == 1: + pri_cardsets += f'&cardset_id={link.cardset_id}' + else: + back_cardsets += f'&backup_cardset_id={link.cardset_id}' + return f'{pri_cardsets}{back_cardsets}' + + def get_scorebug(self, full_length: bool = True) -> discord.Embed: + return discord.Embed( + title=f'{self.away_team_id} @ {self.home_team_id}', + color=int('a6ce39', 16) + ) + # @property + # def game_prop(self) -> str: + # return f'Game {self.id} / Week {self.week_num} / Type {self.game_type}' + + +class CardsetBase(SQLModel): + id: int | None = Field(default=None, primary_key=True) + name: str + ranked_legal: bool | None = Field(default=False) + + +class Cardset(CardsetBase, table=True): + game_links: list[GameCardsetLink] = Relationship(back_populates='cardset', cascade_delete=True) + players: list['Player'] = Relationship(back_populates='cardset') + + class PlayerBase(SQLModel): id: int | None = Field(primary_key=True) name: str diff --git a/tests/gameplay_models/test_game_model.py b/tests/gameplay_models/test_game_model.py index 3563140..4ee53f7 100644 --- a/tests/gameplay_models/test_game_model.py +++ b/tests/gameplay_models/test_game_model.py @@ -104,3 +104,11 @@ def test_delete_game(session: Session): assert len(bad_lineups) == 0 assert len(bad_links) == 0 + + +def test_get_scorebug(session: Session): + game_1 = session.get(Game, 1) + scorebug = game_1.get_scorebug() + + assert scorebug.title == '31 @ 400' + assert scorebug.color.value == int('a6ce39', 16) diff --git a/utilities/confirm.py b/utilities/confirm.py new file mode 100644 index 0000000..4ddd479 --- /dev/null +++ b/utilities/confirm.py @@ -0,0 +1,35 @@ +import discord +from typing import Literal + +class Confirm(discord.ui.View): + def __init__(self, responders: list, timeout: float = 300.0, label_type: Literal['yes', 'confirm'] = 'confirm'): + super().__init__(timeout=timeout) + if not isinstance(responders, list): + raise TypeError('responders must be a list') + self.value = None + self.responders = responders + if label_type == 'yes': + self.confirm.label = 'Yes' + self.cancel.label = 'No' + + # When the confirm button is pressed, set the inner value to `True` and + # stop the View from listening to more input. + # We also send the user an ephemeral message that we're confirming their choice. + @discord.ui.button(label='Confirm', style=discord.ButtonStyle.green) + async def confirm(self, interaction: discord.Interaction, button: discord.ui.Button): + if interaction.user not in self.responders: + return + + self.value = True + self.clear_items() + self.stop() + + # This one is similar to the confirmation button except sets the inner value to `False` + @discord.ui.button(label='Cancel', style=discord.ButtonStyle.grey) + async def cancel(self, interaction: discord.Interaction, button: discord.ui.Button): + if interaction.user not in self.responders: + return + + self.value = False + self.clear_items() + self.stop()