From 088de263ccfb4df22dda4a3080a60896e3a93385 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Mon, 6 Nov 2023 20:20:58 -0500 Subject: [PATCH 1/5] Created initial view votes command. --- cogs/commands/view.py | 87 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 cogs/commands/view.py diff --git a/cogs/commands/view.py b/cogs/commands/view.py new file mode 100644 index 0000000..c20fdb8 --- /dev/null +++ b/cogs/commands/view.py @@ -0,0 +1,87 @@ +""" +Commands for viewing information in the database. +""" + +import nextcord +from nextcord.ext import commands +from sqlalchemy import select +from sqlalchemy.orm import Session + +from database_setup.sql_data_classes import ElectionInformation, Votes, engine + + +class ViewCog(commands.Cog, name="View Commands"): + """ + Holds the view commands. + """ + + def __init__(self) -> None: + """ + Default constructor for ViewCog class. Does nothing. + """ + + @nextcord.slash_command() + async def view(self, interaction: nextcord.Interaction): + """ + Parent slash command for set. Never called. + """ + + @view.subcommand(description="Shows all voters and who they voted for in a given election.") + async def votes( + self, + interaction: nextcord.Interaction, + election_name: str = nextcord.SlashOption( + required=True, description="The election you want to view votes for." + ), + ): + """ + Takes in an election name and sends a response message to the user with a list of people who voted in that + election and who they voted for. Notes those tho abstained. Tells a user if the election is invalid. Uses + autocompletion to assist with getting elections. + + Args: + interaction (nextcord.Interaction): User's interaction with the command. + election_name (str): Is SlashOption. The name of the election to view votes for. + """ + + stmt = select(Votes).where(Votes.ElectionCycle == election_name) + + with Session(engine) as session: + try: + votes = session.scalars(stmt) + content = "" + + for vote in votes: + content += ( + f"<@{vote.VoterId}> voted for <@{vote.VotedForId}>." + if vote.VotedForId is not None + else f"<@{vote.VoterId}> abstained from voted." + ) + + await interaction.response.send_message(content=content, ephemeral=True) + except: + await interaction.response.send_message(f"Invalid election: {election_name}.", ephemeral=True) + + @view.on_autocomplete("election_name") + async def election_autocomplete(self, interaction: nextcord.Interaction, election_name: str): + """ + Collects all elections that start with the election string. + + Args: + interaction (nextcord.Interaction): Interaction with command. + election_name (str): String to run autocomplete on. + """ + + with Session(engine) as session: + stmt = select(ElectionInformation.ElectionCycle) + elections = session.scalars(stmt) + + # if empty compare string + if not election_name: + await interaction.response.send_autocomplete(elections) + return + + autofilled_elections: "list[str]" = [ + election for election in elections if election.lower().startswith(election_name.lower()) + ] + await interaction.response.send_autocomplete(autofilled_elections[:25]) From 6abab5c4e5958d9af2129ff7b78c70e528611de2 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Mon, 6 Nov 2023 20:26:24 -0500 Subject: [PATCH 2/5] Remove missedd code snippet. --- classes/nominate_views.py | 1 - 1 file changed, 1 deletion(-) diff --git a/classes/nominate_views.py b/classes/nominate_views.py index 5f56963..34fb136 100644 --- a/classes/nominate_views.py +++ b/classes/nominate_views.py @@ -69,7 +69,6 @@ class NominateModal(nextcord.ui.Modal): .where(CouncilMembers.MemberId == self.usr_id) ) obj = session.scalar(stmt) - obj.SpeechMsgContents = self.speech.value msg: nextcord.Message = await interaction.channel.fetch_message(obj.SpeechMsgId) await msg.edit(content=decorate_nomination(interaction.user.id, self.speech.value)) From 7530c59a94398fdafa9aab49d99f1f6c14c82a94 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Mon, 6 Nov 2023 20:27:36 -0500 Subject: [PATCH 3/5] Update function header. --- classes/nominate_views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/classes/nominate_views.py b/classes/nominate_views.py index 34fb136..d51a752 100644 --- a/classes/nominate_views.py +++ b/classes/nominate_views.py @@ -114,13 +114,13 @@ class NominateView(nextcord.ui.View): ) -def decorate_nomination(user_id, speech) -> str: +def decorate_nomination(user_id: int, speech: str) -> str: """ Decorates a nomination speech so that it sits within multiple speeches better. Args: - user_id (_type_): ID of user sending the speech - speech (_type_): Speech from the user + user_id (int): ID of user sending the speech + speech (str): Speech from the user Returns: str: Decorated speech From 678fcd37e1e839387c44da3935b9e032a843ca9c Mon Sep 17 00:00:00 2001 From: imcompiling Date: Tue, 7 Nov 2023 14:12:42 -0500 Subject: [PATCH 4/5] Add command to init. Correctly set autocomplete. Put newlines where I forgot to. --- cogs/commands/__init__.py | 2 ++ cogs/commands/view.py | 22 +++++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/cogs/commands/__init__.py b/cogs/commands/__init__.py index 7232b00..f161699 100644 --- a/cogs/commands/__init__.py +++ b/cogs/commands/__init__.py @@ -7,6 +7,7 @@ from nextcord.ext import commands from cogs.commands.request import RequestCog from cogs.commands.set import setCog from cogs.commands.test import TestCog +from cogs.commands.view import ViewCog # This function will be called when this extension is loaded. @@ -19,3 +20,4 @@ def setup(bot: commands.Bot): bot.add_cog(RequestCog(bot)) bot.add_cog(TestCog(bot)) bot.add_cog(setCog()) + bot.add_cog(ViewCog()) diff --git a/cogs/commands/view.py b/cogs/commands/view.py index c20fdb8..7d6f7ef 100644 --- a/cogs/commands/view.py +++ b/cogs/commands/view.py @@ -26,7 +26,9 @@ class ViewCog(commands.Cog, name="View Commands"): Parent slash command for set. Never called. """ - @view.subcommand(description="Shows all voters and who they voted for in a given election.") + @view.subcommand( + description="Shows all voters and who they voted for in a given election." + ) async def votes( self, interaction: nextcord.Interaction, @@ -53,17 +55,21 @@ class ViewCog(commands.Cog, name="View Commands"): for vote in votes: content += ( - f"<@{vote.VoterId}> voted for <@{vote.VotedForId}>." + f"<@{vote.VoterId}> voted for <@{vote.VotedForId}>.\n" if vote.VotedForId is not None - else f"<@{vote.VoterId}> abstained from voted." + else f"<@{vote.VoterId}> abstained from voted.\n" ) await interaction.response.send_message(content=content, ephemeral=True) except: - await interaction.response.send_message(f"Invalid election: {election_name}.", ephemeral=True) + await interaction.response.send_message( + f"Invalid election: {election_name}.", ephemeral=True + ) - @view.on_autocomplete("election_name") - async def election_autocomplete(self, interaction: nextcord.Interaction, election_name: str): + @votes.on_autocomplete("election_name") + async def election_autocomplete( + self, interaction: nextcord.Interaction, election_name: str + ): """ Collects all elections that start with the election string. @@ -82,6 +88,8 @@ class ViewCog(commands.Cog, name="View Commands"): return autofilled_elections: "list[str]" = [ - election for election in elections if election.lower().startswith(election_name.lower()) + election + for election in elections + if election.lower().startswith(election_name.lower()) ] await interaction.response.send_autocomplete(autofilled_elections[:25]) From 4e8032823de93fcc948d3852649905d32c051c87 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Tue, 7 Nov 2023 14:44:07 -0500 Subject: [PATCH 5/5] Fix check if election exists. Scalars doesn't return None if the thing doesn't exists while scalar does. --- cogs/commands/view.py | 47 ++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/cogs/commands/view.py b/cogs/commands/view.py index 7d6f7ef..2bd9175 100644 --- a/cogs/commands/view.py +++ b/cogs/commands/view.py @@ -49,22 +49,23 @@ class ViewCog(commands.Cog, name="View Commands"): stmt = select(Votes).where(Votes.ElectionCycle == election_name) with Session(engine) as session: - try: - votes = session.scalars(stmt) - content = "" - - for vote in votes: - content += ( - f"<@{vote.VoterId}> voted for <@{vote.VotedForId}>.\n" - if vote.VotedForId is not None - else f"<@{vote.VoterId}> abstained from voted.\n" - ) - - await interaction.response.send_message(content=content, ephemeral=True) - except: + # Check if election exists. + if session.scalar(stmt) is None: await interaction.response.send_message( f"Invalid election: {election_name}.", ephemeral=True ) + return + + votes = session.scalars(stmt) + content = "" + for vote in votes: + content += ( + f"<@{vote.VoterId}> voted for <@{vote.VotedForId}>.\n" + if vote.VotedForId is not None + else f"<@{vote.VoterId}> abstained from voted.\n" + ) + + await interaction.response.send_message(content=content, ephemeral=True) @votes.on_autocomplete("election_name") async def election_autocomplete( @@ -82,14 +83,14 @@ class ViewCog(commands.Cog, name="View Commands"): stmt = select(ElectionInformation.ElectionCycle) elections = session.scalars(stmt) - # if empty compare string - if not election_name: - await interaction.response.send_autocomplete(elections) - return + # if empty compare string + if not election_name: + await interaction.response.send_autocomplete(elections) + return - autofilled_elections: "list[str]" = [ - election - for election in elections - if election.lower().startswith(election_name.lower()) - ] - await interaction.response.send_autocomplete(autofilled_elections[:25]) + autofilled_elections: "list[str]" = [ + election + for election in elections + if election.lower().startswith(election_name.lower()) + ] + await interaction.response.send_autocomplete(autofilled_elections[:25])