Files
agon/cogs/submission/submission_views.py
T

237 lines
9.3 KiB
Python

"""Views used for submission process."""
from typing import Optional
import nextcord
from nextcord.ext import commands
from sqlalchemy import select
from sqlalchemy.orm import Session, aliased
# pylint: disable=import-error
from classes.submission import Submission, SubmissionState
from highscores import submission_objects
from utilities.sql_data_classes import Category, CategoryGroup, Guild, engine
from .verification_view import VerificationView
def category_select_options(group_id: int) -> "list[nextcord.SelectOption]":
"""Returns list of categories for a given boss."""
options: "list[nextcord.SelectOption]" = []
with Session(engine) as session:
subq = select(CategoryGroup).where(CategoryGroup.GroupId == group_id).subquery()
cat_group_alias = aliased(CategoryGroup, subq)
stmt = select(Category).where(Category.GroupId == cat_group_alias.GroupId)
categories_list = session.scalars(stmt)
for category in categories_list:
options.append(nextcord.SelectOption(label=category.CategoryName, value=str(category.CategoryId)))
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_id = self.values[0]
embeds = submission.get_embeds()
await interaction.message.edit(
embeds=embeds,
)
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
embeds = submission.get_embeds()
await interaction.edit(embeds=embeds, 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_id:
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
embeds = submission.get_embeds()
await interaction.edit(embeds=embeds, 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):
with Session(engine) as session:
stmt = select(Guild.VerificationChannel).where(Guild.GuildId == interaction.guild_id)
verification_channel_id = session.scalar(stmt)
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
embeds = submission.get_embeds()
await channel.send(
files=[await attch.to_file() for attch in interaction.message.attachments],
view=VerificationView(),
embeds=embeds,
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
with Session(engine) as session:
stmt = (
select(CategoryGroup.GroupId)
.where(CategoryGroup.GuildId == interaction.guild_id)
.where(CategoryGroup.MessageId == interaction.message.id)
)
group_id = session.scalar(stmt)
stmt = select(Guild.SubmissionChannel).where(Guild.GuildId == interaction.guild_id)
channel = interaction.guild.get_channel(session.scalar(stmt))
# a user should only have 1 submission active at once.
# split username on pipe. Decided to store whole username...
username: str = interaction.user.display_name.split("|")[0]
submission: Submission = Submission(interaction.guild_id, group_id, username)
submission_objects.add_submission(interaction.user.id, submission)
embeds = submission.get_embeds()
submission_message = await channel.send(
f"<@{interaction.user.id}>",
view=SubmissionView(
self._bot,
interaction.user.id,
),
embeds=embeds,
)
# 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._group_id = submission_objects.get_user_submission(self._submission_user).group_id
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._group_id)))
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)