From 6c5f40f788ac2117a0b4443dde5cd32d8125463f Mon Sep 17 00:00:00 2001 From: alwayscompiling Date: Wed, 7 Dec 2022 21:37:16 -0500 Subject: [PATCH] Refractor command files into single command files. --- cogs/commands/__init__.py | 10 +- .../{data_management.py => delete.py} | 115 ++++++++++-------- .../{message_management.py => refresh.py} | 110 +++++------------ cogs/commands/update.py | 84 +++++++++++++ 4 files changed, 185 insertions(+), 134 deletions(-) rename cogs/commands/{data_management.py => delete.py} (80%) rename cogs/commands/{message_management.py => refresh.py} (55%) create mode 100644 cogs/commands/update.py diff --git a/cogs/commands/__init__.py b/cogs/commands/__init__.py index 79a9734..b1422cd 100644 --- a/cogs/commands/__init__.py +++ b/cogs/commands/__init__.py @@ -5,9 +5,10 @@ Cog loader. Adds all command cogs to the bot. from nextcord.ext import commands # Command classes -from .data_management import DataManagementCog -from .message_management import MessageManagementCog +from .delete import DeleteCog +from .refresh import RefreshCog from .set import SetCog +from .update import UpdateCog # This function will be called when this extension is loaded. @@ -16,6 +17,7 @@ def setup(bot: commands.Bot): """ Adds all command classes to bot. """ - bot.add_cog(DataManagementCog(bot)) - bot.add_cog(MessageManagementCog(bot)) + bot.add_cog(DeleteCog()) + bot.add_cog(RefreshCog(bot)) bot.add_cog(SetCog()) + bot.add_cog(UpdateCog(bot)) diff --git a/cogs/commands/data_management.py b/cogs/commands/delete.py similarity index 80% rename from cogs/commands/data_management.py rename to cogs/commands/delete.py index 223d809..a96a6ed 100644 --- a/cogs/commands/data_management.py +++ b/cogs/commands/delete.py @@ -1,5 +1,5 @@ """ -Commands for managing the tables/categories/scores for a Guild. +Commands for deleting groups/categories/scores in database and messages in discord.. """ from typing import Optional @@ -10,7 +10,7 @@ from sqlalchemy import distinct, select from sqlalchemy.orm import Session # pylint: disable=import-error -from utilities.sql_data_classes import Category, CategoryGroup, Guild, Score, engine +from utilities.sql_data_classes import Category, CategoryGroup, Score, engine from utilities.utils import ( autofill_categories, autofill_groups, @@ -19,26 +19,16 @@ from utilities.utils import ( send_highscore_message, ) -from .views.update_username_verify import UpdateUsernameVerifyView - -class DataManagementCog(commands.Cog, name="Table Management"): +class DeleteCog(commands.Cog, name="Table Management"): """ - Class holds commands for managing the data storage of the highscores. + Class holds commands for deleting. """ - def __init__(self, bot: commands.Bot): + def __init__(self) -> None: """ - Default constructor for DataManagement class. Sets internal bot variable. + Default constructor for DeleteCog class. Sets internal bot variable. """ - self._bot: commands.Bot = bot - - @commands.Cog.listener() - async def on_ready(self): - """ - Called when cog is loaded. Adds views required for DataManagement commands. - """ - self._bot.add_view(UpdateUsernameVerifyView()) @nextcord.slash_command(default_member_permissions=nextcord.Permissions(administrator=True)) async def delete(self, interaction: nextcord.Interaction): @@ -47,15 +37,60 @@ class DataManagementCog(commands.Cog, name="Table Management"): """ @delete.subcommand() - async def user(self, interaction: nextcord.Interaction): + async def all(self, interaction: nextcord.Interaction): """ - Subcommand parent for deleting user information. Never called. + Subcommand parent for deleting everything in a group. Never called. """ - @user.subcommand( + @all.subcommand(description="Clears highscores channel of all table messages. Does not change data.") + async def channel_messages( + self, + interaction: nextcord.Interaction, + channel: Optional[nextcord.abc.GuildChannel] = nextcord.SlashOption( + description="Channel to clear of messages.", + required=False, + channel_types=[nextcord.ChannelType.text], + default=None, + ), + ) -> None: + """ + Deletes all group messages from channel. Does not change data. + Does not delete highscores channel id. Uses current channel if not supplied a channel. + + Args: + interaction (nextcord.Interaction): Interaction that invoked the command + channel (Optional[nextcord.abc.GuildChannel]): Channel to clear of messages. + Is a SlashOption. Limited to text channels. Defaults to None. + """ + + if not channel: + channel = interaction.channel + + with Session(engine) as session: + stmt = ( + select(CategoryGroup) + .where(CategoryGroup.GuildId == interaction.guild_id) + .where(CategoryGroup.ChannelId == channel.id) + ) + # TODO test when nothing in channel + groups = session.scalars(stmt) + + await interaction.response.defer(ephemeral=True) + + for group in groups: + try: + table_message: nextcord.Message = await channel.fetch_message(group.MessageId) + await table_message.delete() + except nextcord.NotFound: + # silently ignore that messages are not found. They got deleted already. + pass + + await interaction.send("Table messages deleted.", ephemeral=True) + + @all.subcommand( description="Removes all of a user's scores. Warning: data is destroyed, use with case.", ) - async def from_all( + async def users( self, interaction: nextcord.Interaction, user_name: str = nextcord.SlashOption( @@ -89,6 +124,12 @@ class DataManagementCog(commands.Cog, name="Table Management"): await interaction.send(f'User "{user_name}" was removed from all tables.', ephemeral=True) + @delete.subcommand() + async def user(self, interaction: nextcord.Interaction): + """ + Subcommand parent for deleting user information. Never called. + """ + @user.subcommand(description="Deletes a user's scores from a category.") async def from_category( self, @@ -205,39 +246,7 @@ class DataManagementCog(commands.Cog, name="Table Management"): ) ) - @nextcord.slash_command(description="Request a username update. Admins must approve.") - async def update_username( - self, - interaction: nextcord.Interaction, - old_username: str = nextcord.SlashOption(description="Username currently stored in highscores.", required=True), - new_username: str = nextcord.SlashOption(description="Username to update to.", required=True), - ): - """ - Creates a request to send to admins for changing a username. Uses - UpdateUsernameVerifyView to do the work. - - Args: - interaction (nextcord.Interaction): Interaction that invoked the command - old_username (str): Username to replace. - new_username (str): Username to replace old with. - """ - - with Session(engine) as session: - stmt = select(Guild.VerificationChannel).where(Guild.GuildId == interaction.guild_id) - verify_channel = interaction.guild.get_channel(session.scalar(stmt)) - - embed: nextcord.Embed = nextcord.Embed(title="Username change request.") - embed.add_field(name="Old Username", value=old_username) - embed.add_field(name="New Username", value=new_username) - await verify_channel.send( - content=f"Username change request from <@{interaction.user.id}>.", - embed=embed, - view=UpdateUsernameVerifyView(), - ) - await interaction.send("Request sent to admins for verification.", ephemeral=True) - - @update_username.on_autocomplete("old_username") - @from_all.on_autocomplete("user_name") + @users.on_autocomplete("user_name") async def username_autofill(self, interaction: nextcord.Interaction, username: str): """ Sends response from autofill_users_in_guild back to update_username for autocompletion of old_username. diff --git a/cogs/commands/message_management.py b/cogs/commands/refresh.py similarity index 55% rename from cogs/commands/message_management.py rename to cogs/commands/refresh.py index bbbb870..62ea32b 100644 --- a/cogs/commands/message_management.py +++ b/cogs/commands/refresh.py @@ -1,9 +1,7 @@ """ -Commands for managing/displaying the highscores messages. +Commands for refreshing highscore messages. """ -from typing import Optional - import nextcord from nextcord.ext import commands from sqlalchemy import select @@ -15,73 +13,63 @@ from utilities.sql_data_classes import CategoryGroup, engine from utilities.utils import autofill_groups, send_highscore_message -class MessageManagementCog(commands.Cog, name="Message Management"): +class RefreshCog(commands.Cog, name="Refresh Cog"): """ - Class holds commands for managing the messages that display highscores. + Class holds commands for refreshing. """ def __init__(self, bot: commands.Bot) -> None: """ - Default constructor for MessageManagement class + Default constructor for RefreshCog class Args: bot (commands.Bot): Bot object. Required to register submission button view. """ - self.bot = bot + self._bot = bot - @nextcord.slash_command( - description="Clears highscores channel of all table messages. Does not change data.", - default_member_permissions=nextcord.Permissions(administrator=True), - ) - async def delete_channel_messages( + @nextcord.slash_command(default_member_permissions=nextcord.Permissions(administrator=True)) + async def refresh(self, interaction: nextcord.Interaction): + """ + Parent slash command for refreshing things. Never called. + """ + + @refresh.subcommand(description="Manually refresh a table. Use when changing settings or data manually changed.") + async def group( self, interaction: nextcord.Interaction, - channel: Optional[nextcord.abc.GuildChannel] = nextcord.SlashOption( - description="Channel to clear of messages.", - required=False, - channel_types=[nextcord.ChannelType.text], - default=None, - ), + group_id: str = nextcord.SlashOption(name="group", description="Name of Group.", required=True), ) -> None: """ - Deletes all group messages from channel. Does not change data. - Does not delete highscores channel id. Uses current channel if not supplied a channel. + Refreshes a table given by user. Args: - interaction (nextcord.Interaction): Interaction that invoked the command - channel (Optional[nextcord.abc.GuildChannel]): Channel to clear of messages. - Is a SlashOption. Limited to text channels. Defaults to None. + interaction (nextcord.Interaction): Interaction that invoked the command. + group_id (str): Str representation of Group id to refresh. Is SlashOption. """ - if not channel: - channel = interaction.channel - with Session(engine) as session: stmt = ( select(CategoryGroup) .where(CategoryGroup.GuildId == interaction.guild_id) - .where(CategoryGroup.ChannelId == channel.id) + .where(CategoryGroup.GroupId == int(group_id)) ) - # TODO test when nothing in channel - groups = session.scalars(stmt) + group = session.scalar(stmt) - await interaction.response.defer(ephemeral=True) + channel = interaction.guild.get_channel(group.ChannelId) - for group in groups: - try: - table_message: nextcord.Message = await channel.fetch_message(group.MessageId) - await table_message.delete() - except nextcord.NotFound: - # silently ignore that messages are not found. They got deleted already. - pass + message: nextcord.Message = await send_highscore_message(session, channel, group) + await message.edit(view=SubmissionCreateButton(self._bot)) - await interaction.send("Table messages deleted.", ephemeral=True) + await interaction.response.send_message(f"Updated table {group.GroupName}!", ephemeral=True) - @nextcord.slash_command( - description="Triggers post/update of highscores to registered highscore channel.", - default_member_permissions=nextcord.Permissions(administrator=True), - ) - async def post_highscore_groups(self, interaction: nextcord.Interaction) -> None: + @refresh.subcommand() + async def all(self, interaction: nextcord.Interaction): + """ + Subcommand parent for refreshing all things. Never called. + """ + + @all.subcommand(description="Triggers post/update of highscores to registered highscore channels.") + async def groups(self, interaction: nextcord.Interaction) -> None: """ A command which posts the highscore in the registered channel. Sends warning if no channel has been registered. @@ -108,43 +96,11 @@ class MessageManagementCog(commands.Cog, name="Message Management"): assert channel is not None, await interaction.response(error_response, ephemeral=True) message: nextcord.Message = await send_highscore_message(session, channel, group) - await message.edit(view=SubmissionCreateButton(self.bot)) + await message.edit(view=SubmissionCreateButton(self._bot)) await interaction.send(f"Posted all groups in {interaction.guild.name}'s highscores.", ephemeral=True) - @nextcord.slash_command( - description="Manually refresh a table. Use when changing settings or data manually changed.", - default_member_permissions=nextcord.Permissions(administrator=True), - ) - async def refresh_group( - self, - interaction: nextcord.Interaction, - group_id: str = nextcord.SlashOption(name="group", description="Name of Group.", required=True), - ) -> None: - """ - Refreshes a table given by user. - - Args: - interaction (nextcord.Interaction): Interaction that invoked the command. - group_id (str): Str representation of Group id to refresh. Is SlashOption. - """ - - with Session(engine) as session: - stmt = ( - select(CategoryGroup) - .where(CategoryGroup.GuildId == interaction.guild_id) - .where(CategoryGroup.GroupId == int(group_id)) - ) - group = session.scalar(stmt) - - channel = interaction.guild.get_channel(group.ChannelId) - - message: nextcord.Message = await send_highscore_message(session, channel, group) - await message.edit(view=SubmissionCreateButton(self.bot)) - - await interaction.response.send_message(f"Updated table {group.GroupName}!", ephemeral=True) - - @refresh_group.on_autocomplete("group_id") + @group.on_autocomplete("group_id") async def refresh_table_autofill(self, interaction: nextcord.Interaction, group_id: str): """ Collects list of table names and compares to input table name for autocomplete assistance. diff --git a/cogs/commands/update.py b/cogs/commands/update.py new file mode 100644 index 0000000..b1531d0 --- /dev/null +++ b/cogs/commands/update.py @@ -0,0 +1,84 @@ +""" +Commands for updating information/variables held in database. +""" + +import nextcord +from nextcord.ext import commands +from sqlalchemy import select +from sqlalchemy.orm import Session + +# pylint: disable=import-error +from utilities.sql_data_classes import Guild, engine +from utilities.utils import autofill_users_in_guild + +from .views.update_username_verify import UpdateUsernameVerifyView + + +class UpdateCog(commands.Cog, name="Update commands."): + """ + Class holds commands and views needed for updating things in bot. + """ + + def __init__(self, bot: commands.Bot): + """ + Default constructor for Update class. Sets internal bot variable. + + Args: + bot (commands.Bot): Bot object. Required to register update username button view. + """ + self._bot: commands.Bot = bot + + @commands.Cog.listener() + async def on_ready(self): + """ + Called when cog is loaded. Adds views required for DataManagement commands. + """ + self._bot.add_view(UpdateUsernameVerifyView()) + + @nextcord.slash_command() + async def update(self, interaction: nextcord.Interaction): + """ + Parent slash command for updating things. Never called. + """ + + @update.subcommand(description="Request a username update. Admins must approve.") + async def username( + self, + interaction: nextcord.Interaction, + old_username: str = nextcord.SlashOption(description="Username currently stored in highscores.", required=True), + new_username: str = nextcord.SlashOption(description="Username to update to.", required=True), + ): + """ + Creates a request to send to admins for changing a username. Uses + UpdateUsernameVerifyView to do the work. + + Args: + interaction (nextcord.Interaction): Interaction that invoked the command + old_username (str): Username to replace. + new_username (str): Username to replace old with. + """ + + with Session(engine) as session: + stmt = select(Guild.VerificationChannel).where(Guild.GuildId == interaction.guild_id) + verify_channel = interaction.guild.get_channel(session.scalar(stmt)) + + embed: nextcord.Embed = nextcord.Embed(title="Username change request.") + embed.add_field(name="Old Username", value=old_username) + embed.add_field(name="New Username", value=new_username) + await verify_channel.send( + content=f"Username change request from <@{interaction.user.id}>.", + embed=embed, + view=UpdateUsernameVerifyView(), + ) + await interaction.send("Request sent to admins for verification.", ephemeral=True) + + @username.on_autocomplete("old_username") + async def username_autofill(self, interaction: nextcord.Interaction, username: str): + """ + Sends response from autofill_users_in_guild back to update_username for autocompletion of old_username. + + Args: + interaction (nextcord.Interaction): Interaction with command. + old_username (str): String to run autocompletion against. + """ + await interaction.response.send_autocomplete(autofill_users_in_guild(interaction.guild_id, username))