"""View command hierarchy.""" import nextcord import pandas as pd from nextcord.ext import commands from sqlalchemy import select from sqlalchemy.orm import Session # pylint: disable=import-error from database.db import Category, CategoryGroup, Score, engine from utilities.utils import MAX_LINE_LENGTH, autofill_categories, autofill_groups, format_score_string class ViewCog(commands.Cog, name="View Command"): """Class holds commands for viewing data.""" def __init__(self) -> None: """Default constructor for ViewCog class. Does nothing.""" @nextcord.slash_command() async def view(self, interaction: nextcord.Interaction) -> None: """Parent slash command for view. Never called.""" @view.subcommand(description="Lists all scores for a given category.") async def leaderboard( self, interaction: nextcord.Interaction, group_id: str = nextcord.SlashOption( name="group", description="Group to show leaderboard from.", required=True ), category_id: str = nextcord.SlashOption( name="category", description="Category to show leaderboard.", required=True ), ) -> None: """ Create message with leaderboard of a group and category. Gathers all users that have a submission in the group/category combo and returns a message with them in ranked order. Args: interaction (nextcord.Interaction): Interaction that invoked the command. group_id (str): String representation of Group id to search from. Is SlashOption. category_id (str): String representation of Category id to show leaderboard. Is SlashOption. """ str_list: list[str] = [] # get group, category, and all scores sorted correctly. with Session(engine) as session: stmt = select(CategoryGroup).where(CategoryGroup.GroupId == int(group_id)) group = session.scalar(stmt) stmt = select(Category).where(Category.CategoryId == int(category_id)) category = session.scalar(stmt) d_f = pd.read_sql_query( sql=session.query(Score).where(Score.CategoryId == category_id).statement, con=engine ) scores = d_f.sort_values("Score", ascending=category.IsAscending).reset_index() # get the longest string longest_str: int = scores.UserName.map(len).max() for i, row in scores.iterrows(): str_list.append( format_score_string( row["UserName"], row["Score"], longest_str, category.IsTimeRecord, i + 1, # type: ignore[reportOperatorIssue] MAX_LINE_LENGTH, ) ) message_str: str = f"**{group.GroupName} {category.CategoryName} Leaderboard!**\n```" if len(str_list) == 0: message_str += "No Submissions!" else: for line in str_list: message_str += f"{line}\n" message_str += "```" await interaction.response.send_message(content=message_str) @leaderboard.on_autocomplete("group_id") async def group_autocomplete(self, interaction: nextcord.Interaction, group_id: str) -> None: """ Autocomplete function for group names. Args: interaction (nextcord.Interaction): Interaction that invoked the command. group_id (str): String to be autocompleted with Group name. """ await interaction.response.send_autocomplete(autofill_groups(interaction.guild_id, group_id)) @leaderboard.on_autocomplete("category_id") async def category_autocomplete(self, interaction: nextcord.Interaction, category_id: str, group_id: str) -> None: """ Autocomplete function for category names. Args: interaction (nextcord.Interaction): Interaction that invoked the command. category_id (str): String to be autocompleted with Category name. group_id (str): Group to find Category from. """ await interaction.response.send_autocomplete( autofill_categories(interaction.guild_id, int(group_id), category_id) )