Compare commits

..
Author SHA1 Message Date
imcompiling 1c8e8c4d5a Merge branch 'main' into mock-election
build_develop / build (push) Successful in 1m29s
2023-11-07 14:44:40 -05:00
imcompiling 0b5423a62b Merge branch 'main' into mock-election
build_develop / build (push) Successful in 1m22s
2023-11-06 19:47:39 -05:00
imcompiling dbbb7c1c62 Change votes to 2 for mock test
build_develop / build (push) Successful in 1m26s
2023-11-04 09:20:19 -04:00
5 changed files with 64 additions and 180 deletions
+44 -95
View File
@@ -12,12 +12,7 @@ from sqlalchemy.orm import Session
from classes.nominate_views import NominateView from classes.nominate_views import NominateView
from classes.voting_views import VoteView from classes.voting_views import VoteView
from config import DakinyConfig from config import DakinyConfig
from database_setup.sql_data_classes import ( from database_setup.sql_data_classes import CouncilMembers, ElectionInformation, Votes, engine
CouncilMembers,
ElectionInformation,
Votes,
engine,
)
from utils import build_votes_str, get_datetime, get_election_cycle_name from utils import build_votes_str, get_datetime, get_election_cycle_name
@@ -45,15 +40,9 @@ class ElectionCycle:
self.term_end: datetime = get_datetime(self.election_cycle.term_end) self.term_end: datetime = get_datetime(self.election_cycle.term_end)
self.voting_start: datetime = get_datetime(self.election_cycle.voting_start) self.voting_start: datetime = get_datetime(self.election_cycle.voting_start)
self.voting_end: datetime = get_datetime(self.election_cycle.voting_end) self.voting_end: datetime = get_datetime(self.election_cycle.voting_end)
self.highcouncil_election_announce: datetime = get_datetime( self.highcouncil_election_announce: datetime = get_datetime(self.election_cycle.highcouncil_election_announce)
self.election_cycle.highcouncil_election_announce self.highcouncil_election_start: datetime = get_datetime(self.election_cycle.highcouncil_election_start)
) self.highcouncil_election_end: datetime = get_datetime(self.election_cycle.highcouncil_election_end)
self.highcouncil_election_start: datetime = get_datetime(
self.election_cycle.highcouncil_election_start
)
self.highcouncil_election_end: datetime = get_datetime(
self.election_cycle.highcouncil_election_end
)
self.guild: nextcord.Guild = guild self.guild: nextcord.Guild = guild
self.election_over: bool = False self.election_over: bool = False
@@ -66,15 +55,11 @@ class ElectionCycle:
long. long.
""" """
with open( with open("bot_messages/election_announcement.txt", mode="r", encoding="utf8") as file:
"bot_messages/election_announcement.txt", mode="r", encoding="utf8"
) as file:
message = file.read() message = file.read()
next_election = get_datetime( next_election = get_datetime(
self.config.election_cycles[ self.config.election_cycles[(self.cycle + 1) % len(self.config.election_cycles)].election_start
(self.cycle + 1) % len(self.config.election_cycles)
].election_start
) )
message = message.format( message = message.format(
@@ -99,22 +84,14 @@ class ElectionCycle:
str: Message to send. str: Message to send.
""" """
with open( with open("bot_messages/highcouncil_election.txt", mode="r", encoding="utf8") as file:
"bot_messages/highcouncil_election.txt", mode="r", encoding="utf8"
) as file:
message = file.read() message = file.read()
return message.format( return message.format(
clan_council_elect_role_id=self.config.params.clan_council_elect_role_id, clan_council_elect_role_id=self.config.params.clan_council_elect_role_id,
highcouncil_election_announce=self.highcouncil_election_announce.strftime( highcouncil_election_announce=self.highcouncil_election_announce.strftime("%B %d"),
"%B %d" highcouncil_election_start=self.highcouncil_election_start.strftime("%B %d"),
), highcouncil_election_end=self.highcouncil_election_end.strftime("%B %d"),
highcouncil_election_start=self.highcouncil_election_start.strftime(
"%B %d"
),
highcouncil_election_end=self.highcouncil_election_end.strftime(
"%B %d"
),
term_start=self.term_start.strftime("%B %d"), term_start=self.term_start.strftime("%B %d"),
) )
@@ -126,9 +103,7 @@ class ElectionCycle:
str: Message to send. str: Message to send.
""" """
with open( with open("bot_messages/highcouncil_vote.txt", mode="r", encoding="utf8") as file:
"bot_messages/highcouncil_vote.txt", mode="r", encoding="utf8"
) as file:
message = file.read() message = file.read()
return message.format( return message.format(
@@ -146,9 +121,7 @@ class ElectionCycle:
with open("bot_messages/vote_start.txt", mode="r", encoding="utf8") as file: with open("bot_messages/vote_start.txt", mode="r", encoding="utf8") as file:
message = file.read() message = file.read()
vote_end: datetime = get_datetime( vote_end: datetime = get_datetime(self.config.election_cycles[self.cycle].voting_end)
self.config.election_cycles[self.cycle].voting_end
)
return message.format( return message.format(
clan_member_id=self.config.params.clan_member_role_id, clan_member_id=self.config.params.clan_member_role_id,
@@ -167,11 +140,7 @@ class ElectionCycle:
await self.election_start_action() await self.election_start_action()
elif today.date() == self.voting_start.date(): elif today.date() == self.voting_start.date():
await self.voting_start_action() await self.voting_start_action()
elif ( elif (self.voting_end - timedelta(3)).date() <= today.date() < self.voting_end.date():
(self.voting_end - timedelta(3)).date()
<= today.date()
< self.voting_end.date()
):
await self.election_reminder() await self.election_reminder()
elif today.date() == self.voting_end.date(): elif today.date() == self.voting_end.date():
await self.voting_end_action() await self.voting_end_action()
@@ -185,21 +154,15 @@ class ElectionCycle:
Performs required actions for when the election cycle starts. Performs required actions for when the election cycle starts.
""" """
# create new channel for election # create new channel for election
parent: nextcord.TextChannel = self.guild.get_channel( category: nextcord.CategoryChannel = self.guild.get_channel(self.config.params.active_category_id)
self.config.params.voting_parent_id
)
quarter_name: str = get_election_cycle_name(self.config) quarter_name: str = get_election_cycle_name(self.config)
thread_msg: nextcord.Message = await parent.send(content=quarter_name)
# create new entry into database. # create new entry into database.
thread: nextcord.Thread = await parent.create_thread( election_channel: nextcord.TextChannel = await category.create_text_channel(quarter_name)
name=quarter_name, message=thread_msg clan_member_role: nextcord.Role = self.guild.get_role(self.config.params.clan_member_role_id)
) await election_channel.set_permissions(clan_member_role, add_reactions=True)
with Session(engine) as session: with Session(engine) as session:
new_cycle = ElectionInformation( new_cycle = ElectionInformation(ElectionCycle=quarter_name, ElectionChannel=election_channel.id)
ElectionCycle=quarter_name, ThreadId=thread.id
)
session.add(new_cycle) session.add(new_cycle)
session.commit() session.commit()
@@ -210,9 +173,9 @@ class ElectionCycle:
for index, message in enumerate(messages): for index, message in enumerate(messages):
# if last item, add the nominate button # if last item, add the nominate button
if index + 1 == len(messages): if index + 1 == len(messages):
await thread.send(message, view=NominateView(self.config)) await election_channel.send(message, view=NominateView(self.config))
else: else:
await thread.send(message) await election_channel.send(message)
async def voting_start_action(self) -> None: async def voting_start_action(self) -> None:
""" """
@@ -220,35 +183,30 @@ class ElectionCycle:
Removes write permission from the general clan member role. Removes write permission from the general clan member role.
""" """
message = self.build_vote_start() message = self.build_vote_start()
election_thread: nextcord.Thread = self.guild.get_thread( clan_member_role: nextcord.Role = self.guild.get_role(self.config.params.clan_member_role_id)
self.get_election_info().ThreadId election_channel: nextcord.TextChannel = self.guild.get_channel(self.get_election_info().ElectionChannel)
) await election_channel.send(message)
await election_thread.send(message) vote_msg = await election_channel.send(build_votes_str(self.config), view=VoteView(self.config, self.guild))
vote_msg = await election_thread.send(
build_votes_str(self.config), view=VoteView(self.config, self.guild)
)
with Session(engine) as session: with Session(engine) as session:
stmt = select(ElectionInformation).where( stmt = select(ElectionInformation).where(
ElectionInformation.ElectionCycle ElectionInformation.ElectionCycle == get_election_cycle_name(self.config)
== get_election_cycle_name(self.config)
) )
info = session.scalar(stmt) info = session.scalar(stmt)
info.CouncilVoteMsgId = vote_msg.id info.CouncilVoteMsgId = vote_msg.id
session.commit() session.commit()
await election_channel.set_permissions(clan_member_role, send_messages=False)
async def voting_end_action(self) -> None: async def voting_end_action(self) -> None:
""" """
Performs required actions for when voting time has ended. Performs required actions for when voting time has ended.
""" """
message = self.build_highcouncil_election_announce() message = self.build_highcouncil_election_announce()
council_elect_role: nextcord.Role = self.guild.get_role( council_elect_role: nextcord.Role = self.guild.get_role(self.config.params.clan_council_elect_role_id)
self.config.params.clan_council_elect_role_id election_channel: nextcord.TextChannel = self.guild.get_channel(self.get_election_info().ElectionChannel)
) clan_member_role: nextcord.Role = self.guild.get_role(self.config.params.clan_member_role_id)
election_thread: nextcord.Thread = self.guild.get_thread(
self.get_election_info().ThreadId
)
# remove vote button from vote message # remove vote button from vote message
election_name = get_election_cycle_name(self.config) election_name = get_election_cycle_name(self.config)
@@ -257,7 +215,7 @@ class ElectionCycle:
ElectionInformation.ElectionCycle == election_name ElectionInformation.ElectionCycle == election_name
) )
vote_msg_id = session.scalar(stmt) vote_msg_id = session.scalar(stmt)
vote_msg: nextcord.Message = await election_thread.fetch_message(vote_msg_id) vote_msg: nextcord.Message = await election_channel.fetch_message(vote_msg_id)
await vote_msg.edit(view=None) await vote_msg.edit(view=None)
# add the highcouncil role to everyone with 3 or more votes. set elected to true in database # add the highcouncil role to everyone with 3 or more votes. set elected to true in database
@@ -266,7 +224,7 @@ class ElectionCycle:
vote_count = collections.Counter(session.scalars(stmt)) vote_count = collections.Counter(session.scalars(stmt))
for user_id, votes in vote_count.items(): for user_id, votes in vote_count.items():
if votes >= 3: if votes >= 2:
stmt = ( stmt = (
select(CouncilMembers) select(CouncilMembers)
.where(CouncilMembers.ElectionCycle == election_name) .where(CouncilMembers.ElectionCycle == election_name)
@@ -280,7 +238,9 @@ class ElectionCycle:
await user.add_roles(council_elect_role) await user.add_roles(council_elect_role)
await election_thread.send(message) await election_channel.send(message)
await election_channel.set_permissions(council_elect_role, send_messages=True, add_reactions=True)
await election_channel.set_permissions(clan_member_role, add_reactions=False)
async def highcouncil_election_start_action(self) -> None: async def highcouncil_election_start_action(self) -> None:
""" """
@@ -288,27 +248,19 @@ class ElectionCycle:
""" """
message = self.build_highcouncil_vote_start() message = self.build_highcouncil_vote_start()
election_thread: nextcord.Thread = self.guild.get_thread( election_channel: nextcord.TextChannel = self.guild.get_channel(self.get_election_info().ElectionChannel)
self.get_election_info().ThreadId await election_channel.send(message)
)
await election_thread.send(message)
async def term_start_action(self) -> None: async def term_start_action(self) -> None:
""" """
Marks the election as over. Moves the election channel into the archive category.
""" """
self.election_over = True self.election_over = True
election_channel: nextcord.TextChannel = self.guild.get_channel(self.get_election_info().ElectionChannel)
archive: nextcord.CategoryChannel = self.guild.get_channel(self.config.params.archive_channel_group_id)
election_thread: nextcord.Thread = self.guild.get_thread( await election_channel.move(beginning=True, category=archive)
self.get_election_info().ThreadId
)
await election_thread.send(
"This election cycle is now over. Thank you everyone for participating!"
)
await election_thread.edit(archived=True, locked=True)
def get_election_info(self) -> ElectionInformation: def get_election_info(self) -> ElectionInformation:
""" """
@@ -320,8 +272,7 @@ class ElectionCycle:
with Session(engine) as session: with Session(engine) as session:
stmt = select(ElectionInformation).where( stmt = select(ElectionInformation).where(
ElectionInformation.ElectionCycle ElectionInformation.ElectionCycle == get_election_cycle_name(self.config)
== get_election_cycle_name(self.config)
) )
return session.scalar(stmt) return session.scalar(stmt)
@@ -330,11 +281,9 @@ class ElectionCycle:
Sends a message to general chat reminder clan about election. Sends a message to general chat reminder clan about election.
""" """
general: nextcord.TextChannel = self.guild.get_channel( general: nextcord.TextChannel = self.guild.get_channel(self.config.params.general_channel_id)
self.config.params.general_channel_id
)
message = f"Reminder to <@&{self.config.params.clan_member_role_id}>! Clan elections are happening! Head over " message = f"Reminder to <@&{self.config.params.clan_member_role_id}>! Clan elections are happening! Head over "
message += f"to <#{self.get_election_info().ThreadId}> to cast your vote!" message += f"to <#{self.get_election_info().ElectionChannel}> to cast your vote!"
await general.send(content=message) await general.send(content=message)
+14 -41
View File
@@ -7,16 +7,11 @@ from typing import List
import nextcord import nextcord
from nextcord import SelectOption from nextcord import SelectOption
from nextcord.interactions import Interaction from nextcord.interactions import Interaction
from sqlalchemy import exc, select, update from sqlalchemy import exc, select
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from config import DakinyConfig from config import DakinyConfig
from database_setup.sql_data_classes import ( from database_setup.sql_data_classes import CouncilMembers, ElectionInformation, Votes, engine
CouncilMembers,
ElectionInformation,
Votes,
engine,
)
from utils import build_votes_str, get_election_cycle_name from utils import build_votes_str, get_election_cycle_name
@@ -43,11 +38,7 @@ class VoteSelect(nextcord.ui.StringSelect):
else: else:
voted_for = int(self.values[0]) voted_for = int(self.values[0])
new_vote = Votes( new_vote = Votes(ElectionCycle=election_name, VoterId=interaction.user.id, VotedForId=voted_for)
ElectionCycle=election_name,
VoterId=interaction.user.id,
VotedForId=voted_for,
)
try: try:
session.add(new_vote) session.add(new_vote)
@@ -56,18 +47,16 @@ class VoteSelect(nextcord.ui.StringSelect):
except exc.IntegrityError: except exc.IntegrityError:
session.rollback() session.rollback()
stmt = ( stmt = (
update(Votes) select(Votes)
.where(Votes.ElectionCycle == election_name) .where(Votes.ElectionCycle == election_name)
.where(Votes.VoterId == interaction.user.id) .where(Votes.VoterId == interaction.user.id)
.values(VotedForId=voted_for)
) )
session.execute(stmt) vote = session.scalar(stmt)
vote.VotedForId = voted_for
session.commit() session.commit()
vote_message_str = build_votes_str(self.config) vote_message_str = build_votes_str(self.config)
vote_msg: nextcord.Message = await interaction.channel.fetch_message( vote_msg: nextcord.Message = await interaction.channel.fetch_message(vote_msg_id)
vote_msg_id
)
await vote_msg.edit(content=vote_message_str) await vote_msg.edit(content=vote_message_str)
if voted_for is not None: if voted_for is not None:
@@ -88,15 +77,10 @@ class VoteView(nextcord.ui.View):
self.config = config self.config = config
self.guild = guild self.guild = guild
@nextcord.ui.button( @nextcord.ui.button(label="Vote", style=nextcord.ButtonStyle.primary, custom_id="vote")
label="Vote", style=nextcord.ButtonStyle.primary, custom_id="vote" async def vote(self, button: nextcord.ui.Button, interaction: nextcord.Interaction) -> None:
)
async def vote(
self, button: nextcord.ui.Button, interaction: nextcord.Interaction
) -> None:
""" """
Enforces only members vote. Gets election cycle, creates voting options (checking if user has voted already), TODO
then sends the voting view.
Args: Args:
button (nextcord.ui.Button): Unused. idk why its needed in the decorator button (nextcord.ui.Button): Unused. idk why its needed in the decorator
@@ -104,13 +88,9 @@ class VoteView(nextcord.ui.View):
""" """
# enforce members only # enforce members only
if ( if self.guild.get_role(self.config.params.clan_member_role_id) not in interaction.user.roles:
self.guild.get_role(self.config.params.clan_member_role_id)
not in interaction.user.roles
):
await interaction.response.send_message( await interaction.response.send_message(
f"You must have the <@&{self.config.params.clan_member_role_id}> role to vote.", f"You must have the <@&{self.config.params.clan_member_role_id}> role to vote.", ephemeral=True
ephemeral=True,
) )
return return
@@ -124,9 +104,7 @@ class VoteView(nextcord.ui.View):
) )
voted_for = session.scalar(stmt) voted_for = session.scalar(stmt)
stmt = select(CouncilMembers.MemberId).where( stmt = select(CouncilMembers.MemberId).where(CouncilMembers.ElectionCycle == election)
CouncilMembers.ElectionCycle == election
)
options = [ options = [
SelectOption( SelectOption(
@@ -137,12 +115,7 @@ class VoteView(nextcord.ui.View):
) )
for nominee in session.scalars(stmt) for nominee in session.scalars(stmt)
] ]
options.append( options.append(SelectOption(label="Abstain ☑️" if voted_for is None else "Abstain", value="Abstain"))
SelectOption(
label="Abstain ☑️" if voted_for is None else "Abstain",
value="Abstain",
)
)
view = nextcord.ui.View() view = nextcord.ui.View()
view.add_item(VoteSelect(options=options, config=self.config)) view.add_item(VoteSelect(options=options, config=self.config))
+5 -42
View File
@@ -35,7 +35,6 @@ class TestCog(commands.Cog, name="Test commands."):
""" """
@test.subcommand() @test.subcommand()
@is_me()
async def msg_builder(self, interaction: nextcord.Interaction): async def msg_builder(self, interaction: nextcord.Interaction):
""" """
Tests the message builder. Tests the message builder.
@@ -53,7 +52,6 @@ class TestCog(commands.Cog, name="Test commands."):
await interaction.channel.send(content=m) await interaction.channel.send(content=m)
@test.subcommand() @test.subcommand()
@is_me()
async def election_start(self, interaction: nextcord.Interaction): async def election_start(self, interaction: nextcord.Interaction):
""" """
idc idc
@@ -63,15 +61,10 @@ class TestCog(commands.Cog, name="Test commands."):
""" """
config: DakinyConfig = self.bot.config config: DakinyConfig = self.bot.config
cycle = ElectionCycle( cycle = ElectionCycle(get_current_cycle(config), config, self.bot.get_guild(config.params.guild_id))
get_current_cycle(config),
config,
self.bot.get_guild(config.params.guild_id),
)
await cycle.election_start_action() await cycle.election_start_action()
@test.subcommand() @test.subcommand()
@is_me()
async def voting_start(self, interaction: nextcord.Interaction): async def voting_start(self, interaction: nextcord.Interaction):
""" """
tests the voting start action tests the voting start action
@@ -80,15 +73,10 @@ class TestCog(commands.Cog, name="Test commands."):
interaction (nextcord.Interaction): _description_ interaction (nextcord.Interaction): _description_
""" """
config: DakinyConfig = self.bot.config config: DakinyConfig = self.bot.config
cycle = ElectionCycle( cycle = ElectionCycle(get_current_cycle(config), config, self.bot.get_guild(config.params.guild_id))
get_current_cycle(config),
config,
self.bot.get_guild(config.params.guild_id),
)
await cycle.voting_start_action() await cycle.voting_start_action()
@test.subcommand() @test.subcommand()
@is_me()
async def voting_end(self, interaction: nextcord.Interaction): async def voting_end(self, interaction: nextcord.Interaction):
""" """
tests the voting start action tests the voting start action
@@ -97,42 +85,17 @@ class TestCog(commands.Cog, name="Test commands."):
interaction (nextcord.Interaction): _description_ interaction (nextcord.Interaction): _description_
""" """
config: DakinyConfig = self.bot.config config: DakinyConfig = self.bot.config
cycle = ElectionCycle( cycle = ElectionCycle(get_current_cycle(config), config, self.bot.get_guild(config.params.guild_id))
get_current_cycle(config),
config,
self.bot.get_guild(config.params.guild_id),
)
await cycle.voting_end_action() await cycle.voting_end_action()
@test.subcommand() @test.subcommand()
@is_me()
async def election_reminder(self, interaction: nextcord.Interaction): async def election_reminder(self, interaction: nextcord.Interaction):
config: DakinyConfig = self.bot.config config: DakinyConfig = self.bot.config
cycle = ElectionCycle( cycle = ElectionCycle(get_current_cycle(config), config, self.bot.get_guild(config.params.guild_id))
get_current_cycle(config),
config,
self.bot.get_guild(config.params.guild_id),
)
await cycle.election_reminder() await cycle.election_reminder()
@test.subcommand() @test.subcommand()
@is_me()
async def daily(self, interaction: nextcord.Interaction): async def daily(self, interaction: nextcord.Interaction):
config: DakinyConfig = self.bot.config config: DakinyConfig = self.bot.config
cycle = ElectionCycle( cycle = ElectionCycle(get_current_cycle(config), config, self.bot.get_guild(config.params.guild_id))
get_current_cycle(config),
config,
self.bot.get_guild(config.params.guild_id),
)
await cycle.check_date() await cycle.check_date()
@test.subcommand()
@is_me()
async def term_start(self, interaction: nextcord.Interaction):
config: DakinyConfig = self.bot.config
cycle = ElectionCycle(
get_current_cycle(config),
config,
self.bot.get_guild(config.params.guild_id),
)
await cycle.term_start_action()
-1
View File
@@ -22,7 +22,6 @@ class Params:
general_channel_id: int general_channel_id: int
guild_id: int guild_id: int
high_council_role_id: int high_council_role_id: int
voting_parent_id: int
@dataclass @dataclass
+1 -1
View File
@@ -1,6 +1,6 @@
CREATE TABLE ElectionInformation( CREATE TABLE ElectionInformation(
ElectionCycle varchar(30) not null unique, ElectionCycle varchar(30) not null unique,
ThreadId bigint unsigned not null, ElectionChannel bigint unsigned not null,
CouncilVoteMsgId bigint unsigned, CouncilVoteMsgId bigint unsigned,
PRIMARY KEY (ElectionCycle) PRIMARY KEY (ElectionCycle)
); );