Compare commits

..
Author SHA1 Message Date
imcompiling b0e3162123 Change bot to use update query.
build_latest / build (push) Successful in 48s
build_develop / build (push) Successful in 50s
2023-11-07 14:59:07 -05:00
imcompiling 8c1eb8d11f Filled out a docstring.
For some reason, file wasn't formatted.
2023-11-07 14:52:22 -05:00
imcompiling 40d220e2bb Merge branch '32-view-votes-command'
build_develop / build (push) Successful in 50s
2023-11-07 14:44:33 -05:00
imcompiling 4e8032823d Fix check if election exists.
build_develop / build (push) Successful in 1m35s
Scalars doesn't return None if the thing doesn't exists while scalar does.
2023-11-07 14:44:07 -05:00
imcompiling 678fcd37e1 Add command to init.
Correctly set autocomplete.
Put newlines where I forgot to.
2023-11-07 14:12:42 -05:00
imcompiling 7530c59a94 Update function header.
build_develop / build (push) Successful in 1m25s
2023-11-06 20:27:36 -05:00
imcompiling 6abab5c4e5 Remove missedd code snippet.
build_develop / build (push) Successful in 1m26s
2023-11-06 20:26:24 -05:00
imcompiling 088de263cc Created initial view votes command.
build_develop / build (push) Successful in 1m26s
2023-11-06 20:20:58 -05:00
4 changed files with 142 additions and 18 deletions
+3 -4
View File
@@ -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))
@@ -115,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
+41 -14
View File
@@ -7,11 +7,16 @@ from typing import List
import nextcord
from nextcord import SelectOption
from nextcord.interactions import Interaction
from sqlalchemy import exc, select
from sqlalchemy import exc, select, update
from sqlalchemy.orm import Session
from config import DakinyConfig
from database_setup.sql_data_classes import CouncilMembers, ElectionInformation, Votes, engine
from database_setup.sql_data_classes import (
CouncilMembers,
ElectionInformation,
Votes,
engine,
)
from utils import build_votes_str, get_election_cycle_name
@@ -38,7 +43,11 @@ class VoteSelect(nextcord.ui.StringSelect):
else:
voted_for = int(self.values[0])
new_vote = Votes(ElectionCycle=election_name, VoterId=interaction.user.id, VotedForId=voted_for)
new_vote = Votes(
ElectionCycle=election_name,
VoterId=interaction.user.id,
VotedForId=voted_for,
)
try:
session.add(new_vote)
@@ -47,16 +56,18 @@ class VoteSelect(nextcord.ui.StringSelect):
except exc.IntegrityError:
session.rollback()
stmt = (
select(Votes)
update(Votes)
.where(Votes.ElectionCycle == election_name)
.where(Votes.VoterId == interaction.user.id)
.values(VotedForId=voted_for)
)
vote = session.scalar(stmt)
vote.VotedForId = voted_for
session.execute(stmt)
session.commit()
vote_message_str = build_votes_str(self.config)
vote_msg: nextcord.Message = await interaction.channel.fetch_message(vote_msg_id)
vote_msg: nextcord.Message = await interaction.channel.fetch_message(
vote_msg_id
)
await vote_msg.edit(content=vote_message_str)
if voted_for is not None:
@@ -77,10 +88,15 @@ class VoteView(nextcord.ui.View):
self.config = config
self.guild = guild
@nextcord.ui.button(label="Vote", style=nextcord.ButtonStyle.primary, custom_id="vote")
async def vote(self, button: nextcord.ui.Button, interaction: nextcord.Interaction) -> None:
@nextcord.ui.button(
label="Vote", style=nextcord.ButtonStyle.primary, custom_id="vote"
)
async def vote(
self, button: nextcord.ui.Button, interaction: nextcord.Interaction
) -> None:
"""
TODO
Enforces only members vote. Gets election cycle, creates voting options (checking if user has voted already),
then sends the voting view.
Args:
button (nextcord.ui.Button): Unused. idk why its needed in the decorator
@@ -88,9 +104,13 @@ class VoteView(nextcord.ui.View):
"""
# enforce members only
if self.guild.get_role(self.config.params.clan_member_role_id) not in interaction.user.roles:
if (
self.guild.get_role(self.config.params.clan_member_role_id)
not in interaction.user.roles
):
await interaction.response.send_message(
f"You must have the <@&{self.config.params.clan_member_role_id}> role to vote.", ephemeral=True
f"You must have the <@&{self.config.params.clan_member_role_id}> role to vote.",
ephemeral=True,
)
return
@@ -104,7 +124,9 @@ class VoteView(nextcord.ui.View):
)
voted_for = session.scalar(stmt)
stmt = select(CouncilMembers.MemberId).where(CouncilMembers.ElectionCycle == election)
stmt = select(CouncilMembers.MemberId).where(
CouncilMembers.ElectionCycle == election
)
options = [
SelectOption(
@@ -115,7 +137,12 @@ class VoteView(nextcord.ui.View):
)
for nominee in session.scalars(stmt)
]
options.append(SelectOption(label="Abstain ☑️" if voted_for is None else "Abstain", value="Abstain"))
options.append(
SelectOption(
label="Abstain ☑️" if voted_for is None else "Abstain",
value="Abstain",
)
)
view = nextcord.ui.View()
view.add_item(VoteSelect(options=options, config=self.config))
+2
View File
@@ -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())
+96
View File
@@ -0,0 +1,96 @@
"""
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:
# 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(
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])