"""View command hierarchy.""" import nextcord import pandas as pd from nextcord.ext import commands from sqlalchemy import select from sqlalchemy.orm import Session from sqlmodel import col from database.db import engine from database.models import Category, CategoryGroup, Score 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(col(CategoryGroup.id) == int(group_id)) group = session.scalar(stmt) stmt = select(Category).where(col(Category.id) == int(category_id)) category = session.scalar(stmt) d_f = pd.read_sql_query( sql=session.query(Score).where(col(Score.category_id) == category_id).statement, con=engine ) scores = d_f.sort_values("Score", ascending=category.is_ascending).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.is_time_record, i + 1, # type: ignore[reportOperatorIssue] MAX_LINE_LENGTH, ) ) message_str: str = f"**{group.name} {category.name} 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) )