""" Commands for creating items in bot. """ from typing import Optional import nextcord from nextcord.ext import commands from sqlalchemy import exc, select from sqlalchemy.orm import Session # pylint: disable=import-error from cogs.submission.submission_views import SubmissionCreateButton from utilities.sql_data_classes import Category, CategoryGroup, engine from utilities.utils import MAX_LINE_LENGTH, autofill_groups, send_highscore_message class CreateCog(commands.Cog, name="Create Cog"): """ Class holds commands for creating things. """ def __init__(self, bot: commands.Bot) -> None: """ Default constructor for CreateCog class. """ self._bot = bot @nextcord.slash_command(default_member_permissions=nextcord.Permissions(administrator=True)) async def create(self, interaction: nextcord.Interaction): """ Parent slash command for creating things. Never called. """ # need all these arguments because discord command. # pylint: disable=too-many-arguments @create.subcommand(description="Create a new Category. Must not exist already in Group.") async def category( self, interaction: nextcord.Interaction, group_id: str = nextcord.SlashOption(name="group", description="Group to add Category to.", required=True), category_name: str = nextcord.SlashOption(description="Name of new Category.", required=True), is_ascending: bool = nextcord.SlashOption(description="If higher value is better score.", required=True), is_time_record: bool = nextcord.SlashOption( description="If the score should be shown in time format. Cannot be changed.", required=True ), is_validated: bool = nextcord.SlashOption( description="If scores need to be validated before posted.", required=True ), size: int = nextcord.SlashOption( description="How many scores to post in Category. Default is 3.", required=False, default=3, min_value=1 ), ) -> None: """ Creates a new category to be placed into group_id group. Fails if the category name already exists within the group. Then calls send_highscore_message(). Args: interaction (nextcord.Interaction): Interaction for the command. group_id (str): Id of group to add category to. Is SlashOption. category_name (str): Name of new category. Is SlashOption. is_ascending (bool): If the scores are sorted ascending or not. Is SlashOption. is_time_record (bool): If the scores are a time record or not. Is SlashOption. is_validated (bool): If the scores should be validated or not. Is SlashOption. size (int): How many sores to show in the category message. Is SlashOption. """ new_category = Category( CategoryName=category_name, GroupId=int(group_id), Size=size, IsAscending=is_ascending, IsTimeRecord=is_time_record, IsValidated=is_validated, ) # Open connection to engine and add new category. with Session(engine) as session: stmt = select(CategoryGroup).where(CategoryGroup.GroupId == int(group_id)) group = session.scalar(stmt) try: session.add(new_category) session.commit() await send_highscore_message(session, interaction.guild, group) await interaction.response.send_message( f'"{category_name}" has been added to "{group.GroupName}"!', ephemeral=True ) except exc.IntegrityError: # Category name already exists in group session.rollback() await interaction.response.send_message( f'"{category_name}" already exists in "{group.GroupName}". Please rename.', ephemeral=True ) # need all these arguments because discord command. # pylint: disable=too-many-arguments @create.subcommand(description="Create a new Category Group. Must not exist already for Guild.") async def group( self, interaction: nextcord.Interaction, group_name: str = nextcord.SlashOption(description="Name of new Group.", required=True), pad_length: int = nextcord.SlashOption( description="Number of characters wide a category is printed. Default is 26.", required=False, default=26, min_value=7, max_value=MAX_LINE_LENGTH, ), username_length: int = nextcord.SlashOption( description="Number of characters of a username to display. Default is 12.", required=False, default=12, min_value=1, max_value=30, ), channel: Optional[nextcord.abc.GuildChannel] = nextcord.SlashOption( description="Channel to post Group in. If left empty, defaults to current channel.", required=False, channel_types=[nextcord.ChannelType.text], default=None, ), ) -> None: """ Creates a new category group to be placed into the database with the guild's id. Fails if the category group name already exists within the guild. Then calls send_highscore_message(). Args: interaction (nextcord.Interaction): Interaction for the command. group_name (str): Name of new Group. Is SlashOption. pad_length (int): Number of characters wide a category is printed. Is SlashOption. username_length (int): Number of characters of a username to display. Is SlashOption. channel (Optional[nextcord.abc.GuildChannel]): Channel to post group in. If None, defaults to current channel. Is SlashOption. """ # if no channel provided, use current channel. if channel is None: channel = interaction.channel new_group = CategoryGroup( GroupName=group_name, ChannelId=channel.id, GuildId=interaction.guild_id, PadLength=pad_length, UsernameLength=username_length, ) with Session(engine) as session: try: session.add(new_group) session.commit() message: nextcord.Message = await send_highscore_message(session, interaction.guild, new_group) await message.edit(view=SubmissionCreateButton(self._bot)) await interaction.response.send_message(f'"{group_name}" has been created!', ephemeral=True) except exc.IntegrityError: # Category Group already exists in guild session.rollback() await interaction.response.send_message( f'"{group_name}" already exists in "{interaction.guild.name}". Please rename.', ephemeral=True ) @category.on_autocomplete("group_id") async def group_autocomplete(self, interaction: nextcord.Interaction, group_id: str): """ Collects list of table names and compares to input table name for autocomplete assistance. Args: interaction (nextcord.Interaction): Interaction with command. group_id (str): String to run autocomplete compared to. """ await interaction.response.send_autocomplete(autofill_groups(interaction.guild_id, group_id))