Compare commits

...
9 changed files with 543 additions and 914 deletions
+23 -12
View File
@@ -5,8 +5,10 @@ Defines cog for on message listener.
from nextcord.ext import commands from nextcord.ext import commands
import nextcord import nextcord
from highscores import submission_messages # pylint: disable=import-error from cogs.submission.submission_views import SubmissionState # pylint: disable=import-error
from cogs.submission.submission_views import get_submission_embed # pylint: disable=import-error
from highscores import highscores_data # pylint: disable=import-error from highscores import highscores_data # pylint: disable=import-error
from highscores import submission_objects # pylint: disable=import-error
class SubmissionListener(commands.Cog, name="Message Listener"): class SubmissionListener(commands.Cog, name="Message Listener"):
@@ -16,29 +18,38 @@ class SubmissionListener(commands.Cog, name="Message Listener"):
self.bot = bot self.bot = bot
@commands.Cog.listener() @commands.Cog.listener()
async def on_message(self, proof_message: nextcord.Message): async def on_message(self, message: nextcord.Message):
"""Listener for message creation. Adds score and attachments to submission.""" """Listener for message creation. Adds score and attachments to submission."""
if proof_message.author.id in submission_messages: if message.author.id in submission_objects:
message_id = submission_messages[proof_message.author.id] message_id = submission_objects[message.author.id]["message_id"]
submission_message: nextcord.Message = await self.bot.get_channel( submission_message: nextcord.Message = await self.bot.get_channel(
highscores_data["submission_channel_id"] highscores_data["submission_channel_id"]
).fetch_message(message_id) ).fetch_message(message_id)
# need check if correct user and correct channel # TODO want to regex score to ensure it is correct.
if proof_message.channel.id == highscores_data["submission_channel_id"]: # # here is also where score can be standardized in look
embed = submission_message.embeds[0] # need check if correct user and correct channel
if proof_message.content: if message.channel.id == highscores_data["submission_channel_id"]:
embed.add_field(name="Score", value=proof_message.content, inline=False) state = submission_objects[message.author.id]["submission_state"]
if state == SubmissionState.SCORE and message.content:
submission_objects[message.author.id]["score"] = message.content
embed = get_submission_embed(message.author.id)
await submission_message.edit( await submission_message.edit(
embed=embed, embed=embed,
) )
if len(proof_message.attachments) > 0: elif state == SubmissionState.PROOF and len(message.attachments) > 0:
await submission_message.edit( await submission_message.edit(
files=[await attch.to_file() for attch in proof_message.attachments], files=[await attch.to_file() for attch in message.attachments],
)
elif state == SubmissionState.NAME and message.content:
submission_objects[message.author.id]["username"] = message.content[:12]
embed = get_submission_embed(message.author.id)
await submission_message.edit(
embed=embed,
) )
await proof_message.delete() await message.delete()
# This function will be called when this extension is loaded. # This function will be called when this extension is loaded.
+2 -2
View File
@@ -5,7 +5,7 @@ Bot command to post the highscores
from nextcord.ext import commands from nextcord.ext import commands
import nextcord import nextcord
from cogs.submission.submission_views import SubmissionButton # pylint: disable=import-error from cogs.submission.submission_views import SubmissionCreateButton # pylint: disable=import-error
from highscores import highscores_config # pylint: disable=import-error from highscores import highscores_config # pylint: disable=import-error
from highscores import highscores_data # pylint: disable=import-error from highscores import highscores_data # pylint: disable=import-error
from utilities.data_storage import save_highscores_data # pylint: disable=import-error from utilities.data_storage import save_highscores_data # pylint: disable=import-error
@@ -41,7 +41,7 @@ class PostHighscores(commands.Cog, name="Post Highscores"):
"highscore_table" "highscore_table"
].items(): ].items():
message: nextcord.Message = await send_highscore_message(channel, boss) message: nextcord.Message = await send_highscore_message(channel, boss)
await message.edit(view=SubmissionButton(self.bot)) await message.edit(view=SubmissionCreateButton(self.bot))
save_highscores_data(highscores_data) save_highscores_data(highscores_data)
+4 -2
View File
@@ -4,7 +4,8 @@ Cog for creating submission process.
from nextcord.ext import commands from nextcord.ext import commands
from .submission_views import SubmissionButton from .submission_views import SubmissionCreateButton
from .verification_view import VerificationView
class SubmissionCog(commands.Cog, name="Submission Cog"): class SubmissionCog(commands.Cog, name="Submission Cog"):
@@ -16,7 +17,8 @@ class SubmissionCog(commands.Cog, name="Submission Cog"):
@commands.Cog.listener() @commands.Cog.listener()
async def on_ready(self): async def on_ready(self):
"""Called when cog is loaded""" """Called when cog is loaded"""
self.bot.add_view(SubmissionButton(self.bot)) self.bot.add_view(SubmissionCreateButton(self.bot))
self.bot.add_view(VerificationView())
# This function will be called when this extension is loaded. # This function will be called when this extension is loaded.
+198 -65
View File
@@ -1,52 +1,68 @@
"""Views used for submission process.""" """Views used for submission process."""
from typing import Optional from typing import Optional
from enum import Enum
import nextcord import nextcord
from nextcord import Embed
from nextcord.ext import commands from nextcord.ext import commands
from utilities.data_storage import open_message_map # pylint: disable=import-error from utilities.data_storage import open_message_map # pylint: disable=import-error
from highscores import highscores_data # pylint: disable=import-error from highscores import highscores_data # pylint: disable=import-error
from highscores import submission_messages # pylint: disable=import-error from highscores import submission_objects # pylint: disable=import-error
from .verification_view import VerificationView from .verification_view import VerificationView
class SubmissionButton(nextcord.ui.View): class SubmissionState(Enum):
"""Defines view for score submission button.""" """Enum for which state a submission is in"""
def __init__(self, bot: commands.Bot): CATEGORY = 1
super().__init__(timeout=None) SCORE = 2
self._bot = bot PROOF = 3
NAME = 4
SUBMIT = 5
VERIFY = 6
@nextcord.ui.button(label="Submit", style=nextcord.ButtonStyle.primary, custom_id="submit")
async def submit_button(
self, button: nextcord.ui.Button, interaction: nextcord.Interaction
): # pylint: disable=unused-argument
"""Button for score submission."""
highscores_message_map = open_message_map()
boss_name = highscores_message_map[str(interaction.message.id)]
embed = nextcord.Embed(title="Highscores Submission")
embed.add_field(name="Boss", value=boss_name, inline=False)
embed.add_field(name="User", value=interaction.user.display_name, inline=False)
channel = self._bot.get_channel(highscores_data["submission_channel_id"])
submission_message = await channel.send(
f"<@{interaction.user.id}>",
view=SubmissionDropdownView(
self._bot, interaction, await self._category_select_options(boss_name)
),
embed=embed,
)
# a user should only have 1 submission active at once. def get_submission_embed(userid: int) -> nextcord.Embed:
submission_messages[interaction.user.id] = submission_message.id """Creates an embed based off of the submission state and fields filled out."""
usersubmission: dict = submission_objects[userid]
state: SubmissionState = usersubmission["submission_state"]
async def _category_select_options(self, boss_name: str) -> "list[nextcord.SelectOption]": if state is SubmissionState.CATEGORY:
options: list[nextcord.SelectOption] = [] # pylint: disable=unsubscriptable-object description = "Step 1: Choose your category!"
boss_dict = highscores_data[boss_name] elif state is SubmissionState.SCORE:
for category in boss_dict["categories"].items(): description = "Step 2: Input your score!"
options.append(nextcord.SelectOption(label=category[0])) elif state is SubmissionState.PROOF:
description = "Step 3: Submit your proof!"
elif state is SubmissionState.NAME:
description = "Step 4 (Optional): Change name on submission! (proceed to next if skipping)"
elif state is SubmissionState.SUBMIT:
description = "Step 5: Submit if everything looks correct!"
elif state is SubmissionState.VERIFY:
description = "Review fields and accept."
return options embed = Embed(title="Highscores Submission", description=description)
embed.add_field(name="User Name", value=usersubmission["username"], inline=False)
embed.add_field(name="Boss", value=usersubmission["boss_name"], inline=False)
if usersubmission["category"]:
embed.add_field(name="Category", value=usersubmission["category"], inline=False)
if usersubmission["score"]:
embed.add_field(name="Score", value=usersubmission["score"], inline=False)
return embed
def category_select_options(boss_name: str) -> "list[nextcord.SelectOption]":
"""Returns list of categories for a given boss."""
options: "list[nextcord.SelectOption]" = []
boss_dict = highscores_data[boss_name]
for category in boss_dict["categories"].items():
options.append(nextcord.SelectOption(label=category[0]))
return options
############ Items used in submission process ############
class SubmissionDropdown(nextcord.ui.Select): class SubmissionDropdown(nextcord.ui.Select):
@@ -63,60 +79,177 @@ class SubmissionDropdown(nextcord.ui.Select):
self._bot = bot self._bot = bot
async def callback(self, interaction: nextcord.Interaction): async def callback(self, interaction: nextcord.Interaction):
embed = interaction.message.embeds[0] submission_objects[interaction.user.id]["category"] = self.values[0]
embed.add_field(name="Category", value=self.values[0], inline=False) embed = get_submission_embed(interaction.user.id)
await interaction.message.edit( await interaction.message.edit(
embed=embed, embed=embed,
) )
class SubmissionDropdownView(nextcord.ui.View): class BackButton(nextcord.ui.Button):
"""Defines submission dropdown process view""" """Defines view for back button."""
def __init__( def __init__(self, bot: commands.Bot):
self, super().__init__(label="Back", style=nextcord.ButtonStyle.primary, custom_id="back")
bot: commands.Bot, self._bot = bot
prev_interaction: nextcord.Interaction,
options: "list[nextcord.SelectOption]",
*,
timeout: Optional[float] = 180,
):
super().__init__(timeout=timeout)
self.add_item(SubmissionDropdown(bot, options))
self._prev_interaction = prev_interaction
self.bot = bot
async def interaction_check(self, interaction: nextcord.Interaction) -> bool: async def callback(self, interaction: nextcord.Interaction):
return self._prev_interaction.user == interaction.user state: SubmissionState = submission_objects[interaction.user.id]["submission_state"]
state = SubmissionState(state.value - 1)
submission_objects[interaction.user.id]["submission_state"] = state
embed = get_submission_embed(interaction.user.id)
await interaction.edit(embed=embed, view=SubmissionView(self._bot, interaction.user.id))
@nextcord.ui.button(
label="Submit Score", style=nextcord.ButtonStyle.green, custom_id="submit-score" class CancelButton(nextcord.ui.Button):
) """Deletes message to cancel interaction.."""
async def submit_button(
self, button: nextcord.ui.Button, interaction: nextcord.Interaction def __init__(self):
): # pylint: disable=unused-argument super().__init__(label="Cancel", style=nextcord.ButtonStyle.red, custom_id="cancel")
"""Defines button to submit a user's score."""
async def callback(self, interaction: nextcord.Interaction):
submission_objects.pop(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
state: SubmissionState = submission_objects[interaction.user.id]["submission_state"]
if (
state == SubmissionState.CATEGORY
and not submission_objects[interaction.user.id]["category"]
):
await interaction.send("Please choose a category.", ephemeral=True)
elif (
state == SubmissionState.SCORE and not submission_objects[interaction.user.id]["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_objects[interaction.user.id]["submission_state"] = state
embed = get_submission_embed(interaction.user.id)
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["verification_channel_id"] verification_channel_id = highscores_data["verification_channel_id"]
channel = self.bot.get_channel(verification_channel_id) channel = self._bot.get_channel(verification_channel_id)
error_response = "Registered Verification channel does not exist or was never registered. \ error_response = "Registered Verification channel does not exist or was never registered. \
Contact server admins." Contact server admins."
assert channel is not None, await channel.send(error_response) assert channel is not None, await channel.send(error_response)
submission_objects[interaction.user.id]["submission_state"] = SubmissionState.VERIFY
embed = get_submission_embed(interaction.user.id)
await channel.send( await channel.send(
files=[await attch.to_file() for attch in interaction.message.attachments], files=[await attch.to_file() for attch in interaction.message.attachments],
view=VerificationView(), view=VerificationView(),
embed=interaction.message.embeds[0], embed=embed,
content=f"Submission from {interaction.user.display_name}",
) )
await interaction.message.edit(content=f"<@{interaction.user.id}> Submitted!", view=None) await interaction.message.edit(content=f"<@{interaction.user.id}> Submitted!", view=None)
submission_messages.pop(interaction.user.id) submission_objects.pop(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( @nextcord.ui.button(
label="Cancel", style=nextcord.ButtonStyle.red, custom_id="cancel-submission" label="Submit", style=nextcord.ButtonStyle.primary, custom_id="submitcreate"
) )
async def cancel_button( async def submitcreate_button(
self, button: nextcord.ui.Button, interaction: nextcord.Interaction self, button: nextcord.ui.Button, interaction: nextcord.Interaction
): # pylint: disable=unused-argument ): # pylint: disable=unused-argument
"""Deletes message to cancel interaction.""" """Button for score submission."""
submission_messages.pop(interaction.user.id) highscores_message_map = open_message_map()
await interaction.message.delete() boss_name = highscores_message_map[str(interaction.message.id)]
# embed = nextcord.Embed(title="Highscores Submission")
# embed.add_field(name="Boss", value=boss_name, inline=False)
# embed.add_field(name="User", value=interaction.user.display_name, inline=False)
channel = self._bot.get_channel(highscores_data["submission_channel_id"])
# a user should only have 1 submission active at once.
# submitting with dummy message_id until message created
submission_objects[interaction.user.id] = {
"message_id": 0,
"submission_state": SubmissionState.CATEGORY,
"boss_name": boss_name,
"score": "",
"category": "",
"username": interaction.user.display_name.split("|")[0][:12],
}
embed = get_submission_embed(interaction.user.id)
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_objects[interaction.user.id]["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] = 180,
):
super().__init__(timeout=timeout)
self._submission_user = submission_user
self._bot = bot
self._state = submission_objects[self._submission_user]["submission_state"]
self._boss_name = submission_objects[self._submission_user]["boss_name"]
# add items depending on given state
if self._state is SubmissionState.CATEGORY:
self.add_item(SubmissionDropdown(bot, category_select_options(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:
return self._submission_user == interaction.user.id
+1 -1
View File
@@ -26,7 +26,7 @@ class VerificationView(nextcord.ui.View):
category = field["value"] category = field["value"]
elif field["name"] == "Score": elif field["name"] == "Score":
score = field["value"] score = field["value"]
elif field["name"] == "User": elif field["name"] == "User Name":
user = field["value"] user = field["value"]
try: try:
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -24,7 +24,7 @@ highscores_config = open_highscores_config()
highscores_data = open_highscores_data() highscores_data = open_highscores_data()
highscores_message_map = open_message_map() highscores_message_map = open_message_map()
submission_messages: dict = {} submission_objects: dict = {}
def main(): def main():
+1 -1
View File
@@ -33,7 +33,7 @@ def open_highscores_data():
for boss, categories in config["highscore_table"].items(): for boss, categories in config["highscore_table"].items():
data[boss] = {"message_id": 0} data[boss] = {"message_id": 0}
boss_categories = {} boss_categories = {}
for category, category_config in categories.items(): # pylint: disable=unused-variable for category in categories: # pylint: disable=unused-variable
rank_list = [] rank_list = []
boss_categories[category] = rank_list boss_categories[category] = rank_list
data[boss]["categories"] = boss_categories data[boss]["categories"] = boss_categories
+1 -1
View File
@@ -75,7 +75,7 @@ async def submit_score(
@param score: score to add @param score: score to add
""" """
boss_category_config = highscores_config["highscore_table"][boss_name][category] boss_category_config = highscores_config["categories"][category]
# capping to 12 characters because runescape names are 12 characters long. # capping to 12 characters because runescape names are 12 characters long.
# Splitting on pipe. My discord has multiple names on account split by pipe. # Splitting on pipe. My discord has multiple names on account split by pipe.