"""Views used for submission process.""" from typing import Optional import nextcord from nextcord.ext import commands from classes.submission import Submission, SubmissionState # pylint: disable=import-error from highscores import ( # pylint: disable=import-error highscores_data, highscores_message_map, submission_objects, ) from .verification_view import VerificationView def category_select_options(guild_id: int, boss_name: str) -> "list[nextcord.SelectOption]": """Returns list of categories for a given boss.""" options: "list[nextcord.SelectOption]" = [] category_list = highscores_data.get_guild(guild_id).get_table(boss_name).categories for category in category_list: options.append(nextcord.SelectOption(label=category.name)) return options ############ Items used in submission process ############ class SubmissionDropdown(nextcord.ui.Select): """Defines dropdown menu for submission""" def __init__( self, bot: commands.Bot, options: "list[nextcord.SelectOption]", ): super().__init__( placeholder="Choose submission category.", min_values=1, max_values=1, options=options ) self._bot = bot async def callback(self, interaction: nextcord.Interaction): submission = submission_objects.get_user_submission(interaction.user.id) submission.category = self.values[0] embed = submission.get_embed() await interaction.message.edit( embed=embed, ) class BackButton(nextcord.ui.Button): """Defines view for back button.""" def __init__(self, bot: commands.Bot): super().__init__(label="Back", style=nextcord.ButtonStyle.primary, custom_id="back") self._bot = bot async def callback(self, interaction: nextcord.Interaction): submission = submission_objects.get_user_submission(interaction.user.id) state: SubmissionState = submission.submission_state state = SubmissionState(state.value - 1) submission.submission_state = state embed = submission.get_embed() await interaction.edit(embed=embed, view=SubmissionView(self._bot, interaction.user.id)) class CancelButton(nextcord.ui.Button): """Deletes message to cancel interaction..""" def __init__(self): super().__init__(label="Cancel", style=nextcord.ButtonStyle.red, custom_id="cancel") async def callback(self, interaction: nextcord.Interaction): submission_objects.remove_user_submission(interaction.user.id) await interaction.message.delete() class NextButton(nextcord.ui.Button): """Defines view for next button.""" def __init__(self, bot: commands.Bot): super().__init__(label="Next", style=nextcord.ButtonStyle.primary, custom_id="next") self._bot = bot async def callback(self, interaction: nextcord.Interaction): # check if fields have been filled out for each state submission = submission_objects.get_user_submission(interaction.user.id) state: SubmissionState = submission.submission_state if state == SubmissionState.CATEGORY and not submission.category: await interaction.send("Please choose a category.", ephemeral=True) elif state == SubmissionState.SCORE and not submission.score: await interaction.send("Please send a score.", ephemeral=True) elif state == SubmissionState.PROOF and not len(interaction.message.attachments) > 0: await interaction.send("Please attach picture for proof.", ephemeral=True) else: state = SubmissionState(state.value + 1) submission.submission_state = state embed = submission.get_embed() await interaction.edit(embed=embed, view=SubmissionView(self._bot, interaction.user.id)) class SubmitButton(nextcord.ui.Button): """Defines button to submit a user's score.""" def __init__(self, bot: commands.Bot): super().__init__(label="Submit", style=nextcord.ButtonStyle.green, custom_id="submit") self._bot = bot async def callback(self, interaction: nextcord.Interaction): verification_channel_id = highscores_data.get_guild( interaction.guild_id ).verification_channel channel = interaction.guild.get_channel(verification_channel_id) submission = submission_objects.get_user_submission(interaction.user.id) error_response = "Registered Verification channel does not exist or was never registered. \ Contact server admins." assert channel is not None, await channel.send(error_response) submission.submission_state = SubmissionState.VERIFY embed = submission.get_embed() await channel.send( files=[await attch.to_file() for attch in interaction.message.attachments], view=VerificationView(), embed=embed, content=f"Submission from <@{interaction.user.id}>.", ) await interaction.message.edit(content=f"<@{interaction.user.id}> Submitted!", view=None) submission_objects.remove_user_submission(interaction.user.id) ############ Submission Views ############ class SubmissionCreateButton(nextcord.ui.View): """Defines view for score submission button.""" def __init__(self, bot: commands.Bot): super().__init__(timeout=None) self._bot = bot @nextcord.ui.button( label="Submit", style=nextcord.ButtonStyle.primary, custom_id="submitcreate" ) async def submitcreate_button( self, button: nextcord.ui.Button, interaction: nextcord.Interaction ): # pylint: disable=unused-argument """Button for score submission.""" # Don't allow a user to start a new submission if one already exists if submission_objects.has_user(interaction.user.id): await interaction.send("Please finish in progress submission first.", ephemeral=True) return table = highscores_message_map[interaction.guild.id][interaction.message.id] channel = interaction.guild.get_channel( highscores_data.get_guild(interaction.guild_id).submission_channel ) # a user should only have 1 submission active at once. # split username on pipe then limit length. username: str = interaction.user.display_name.split("|")[0][ : highscores_data.get_guild(interaction.guild_id).username_length ] submission: Submission = Submission(interaction.guild_id, table, username) submission_objects.add_submission(interaction.user.id, submission) embed = submission.get_embed() submission_message = await channel.send( f"<@{interaction.user.id}>", view=SubmissionView( self._bot, interaction.user.id, ), embed=embed, ) # update the message_id once its created submission.message_id = submission_message.id class SubmissionView(nextcord.ui.View): """Defines view submitting. Adjusts to all states.""" def __init__( self, bot: commands.Bot, submission_user: int, *, timeout: Optional[float] = 300, ): super().__init__(timeout=timeout) self._submission_user = submission_user self._bot = bot self._state = submission_objects.get_user_submission(self._submission_user).submission_state self._boss_name = submission_objects.get_user_submission(self._submission_user).table self._guild_id = submission_objects.get_user_submission(self._submission_user).guild_id # add items depending on given state if self._state is SubmissionState.CATEGORY: self.add_item( SubmissionDropdown(bot, category_select_options(self._guild_id, self._boss_name)) ) self.add_item(CancelButton()) self.add_item(NextButton(self._bot)) elif ( self._state is SubmissionState.SCORE or self._state is SubmissionState.PROOF or self._state is SubmissionState.NAME ): self.add_item(BackButton(self._bot)) self.add_item(NextButton(self._bot)) elif self._state is SubmissionState.SUBMIT: self.add_item(BackButton(self._bot)) self.add_item(SubmitButton(self._bot)) async def interaction_check(self, interaction: nextcord.Interaction) -> bool: check = self._submission_user == interaction.user.id if not check: await interaction.send("This is not your submission.", ephemeral=True) return check async def on_timeout(self) -> None: # remove user from submission objects after time out. Allows user to start new submission. submission_objects.remove_user_submission(self._submission_user)