Compare commits

..
Author SHA1 Message Date
imcompiling 4c1f41c4c8 Correct date being used for getting the election cycle name.
build_develop / build (push) Successful in 1m39s
2023-12-28 19:28:30 -05:00
14 changed files with 33 additions and 515 deletions
+2 -3
View File
@@ -239,8 +239,7 @@ class ElectionCycle:
) )
await election_thread.send(message) await election_thread.send(message)
vote_msg = await election_thread.send( vote_msg = await election_thread.send(
build_votes_str(self.config, self.guild), build_votes_str(self.config), view=VoteView(self.config, self.guild)
view=VoteView(self.config, self.guild),
) )
with Session(engine) as session: with Session(engine) as session:
@@ -325,7 +324,7 @@ class ElectionCycle:
) )
await election_thread.send(message) await election_thread.send(message)
vote_msg = await election_thread.send( vote_msg = await election_thread.send(
build_highcouncil_votes_str(self.config, self.guild), build_highcouncil_votes_str(self.config),
view=VoteHighcouncilView(self.config, self.guild), view=VoteHighcouncilView(self.config, self.guild),
) )
+3 -9
View File
@@ -82,7 +82,7 @@ class VoteSelect(nextcord.ui.StringSelect):
session.execute(stmt) session.execute(stmt)
session.commit() session.commit()
vote_message_str = build_highcouncil_votes_str(self.config, interaction.guild) vote_message_str = build_highcouncil_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
) )
@@ -159,10 +159,7 @@ class VoteHighcouncilView(nextcord.ui.View):
else f"{self.guild.get_member(nominee).display_name}", else f"{self.guild.get_member(nominee).display_name}",
value=str(nominee), value=str(nominee),
) )
for nominee in sorted( for nominee in session.scalars(stmt)
session.scalars(stmt),
key=lambda nominee: self.guild.get_member(nominee).display_name,
)
] ]
options.append( options.append(
SelectOption( SelectOption(
@@ -235,10 +232,7 @@ class VoteHighcouncilView(nextcord.ui.View):
else f"{self.guild.get_member(nominee).display_name}", else f"{self.guild.get_member(nominee).display_name}",
value=str(nominee), value=str(nominee),
) )
for nominee in sorted( for nominee in session.scalars(stmt)
session.scalars(stmt),
key=lambda nominee: self.guild.get_member(nominee).display_name,
)
] ]
options.append( options.append(
SelectOption( SelectOption(
+2 -5
View File
@@ -64,7 +64,7 @@ class VoteSelect(nextcord.ui.StringSelect):
session.execute(stmt) session.execute(stmt)
session.commit() session.commit()
vote_message_str = build_votes_str(self.config, interaction.guild) 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
) )
@@ -135,10 +135,7 @@ class VoteView(nextcord.ui.View):
else f"{self.guild.get_member(nominee).display_name}", else f"{self.guild.get_member(nominee).display_name}",
value=str(nominee), value=str(nominee),
) )
for nominee in sorted( for nominee in session.scalars(stmt)
session.scalars(stmt),
key=lambda nominee: self.guild.get_member(nominee).display_name,
)
] ]
options.append( options.append(
SelectOption( SelectOption(
-2
View File
@@ -4,7 +4,6 @@ Cog loader. Adds all command cogs to the bot.
from nextcord.ext import commands from nextcord.ext import commands
from cogs.commands.record import RecordCog
from cogs.commands.remove import RemoveCog from cogs.commands.remove import RemoveCog
from cogs.commands.request import RequestCog from cogs.commands.request import RequestCog
from cogs.commands.set import setCog from cogs.commands.set import setCog
@@ -19,7 +18,6 @@ def setup(bot: commands.Bot):
Adds all command classes to bot. Adds all command classes to bot.
""" """
bot.add_cog(RecordCog(bot))
bot.add_cog(RemoveCog()) bot.add_cog(RemoveCog())
bot.add_cog(RequestCog(bot)) bot.add_cog(RequestCog(bot))
bot.add_cog(TestCog(bot)) bot.add_cog(TestCog(bot))
-218
View File
@@ -1,218 +0,0 @@
"""
Contained commands and views for record commands.
"""
import nextcord
from discord import TextInputStyle
from nextcord.ext import commands
from config import DakinyConfig
from utils import record_event_host, record_event_participation
class RecordCog(commands.Cog, name="Record Commands"):
"""
Class holds record commands.
"""
def __init__(self, bot) -> None:
"""
Default constructor for RecordCog class. Does nothing.
"""
super().__init__()
self.bot: commands.Bot = bot
@nextcord.slash_command()
async def record(self, interaction: nextcord.Interaction):
"""
Parent slash command for record. Never called.
"""
@record.subcommand(description="Record an event and its participants.")
async def event(
self,
interaction: nextcord.Interaction,
name: str = nextcord.SlashOption(
required=True, description="Name of the event that was hosted."
),
host: nextcord.Member = nextcord.SlashOption(
required=False,
description="An alternative host if you are recording event for someone else.",
),
):
"""
This command creates the base event recording embed and sends a message with it and the EventView
for gathering more information on the event.
Args:
interaction (nextcord.Interaction): interaction with this command.
name (str): Name of the event.
host (nextcord.Member, optional): Alternative host to user using command.
"""
# check role
if (
interaction.guild.get_role(self.bot.config.params.event_host_role_id)
not in interaction.user.roles
):
await interaction.response.send_message(
f"You must have the <@&{self.bot.config.params.event_host_role_id}> role to record an event.",
ephemeral=True,
)
return
if host is None:
host = interaction.user
embed: nextcord.Embed = nextcord.Embed(title=name, description="")
embed.add_field(name="Participants", value="")
embed.add_field(name="Non-Discord Participants", value="")
embed.add_field(name="Hosted by", value=f"<@{host.id}>", inline=False)
await interaction.response.send_message(
"Fill out event details and select all members who participated!",
view=EventView(name, self.bot.config, host.id),
ephemeral=True,
embed=embed,
)
class EventView(nextcord.ui.View):
"""
Class handles gathering information on an event. Has buttons to edit the information, cancel, and submit.
Also contains a UserSelect object to pick discord members.
"""
def __init__(self, name: str, config: DakinyConfig, host_id: int):
super().__init__()
self.name: str = name
self.config: DakinyConfig = config
self.host_id: int = host_id
self.event_participants = ParticipantSelect()
self.add_item(self.event_participants)
@nextcord.ui.button(label="Cancel", style=nextcord.ButtonStyle.red, row=1)
async def cancel(
self, button: nextcord.ui.Button, interaction: nextcord.Interaction
):
"""
Cancels event submission. Removes embed and view.
"""
await interaction.response.edit_message(
"Canceled", ephemeral=True, embed=None, view=None
)
self.stop()
@nextcord.ui.button(label="Edit", style=nextcord.ButtonStyle.blurple, row=1)
async def edit(self, button: nextcord.ui.Button, interaction: nextcord.Interaction):
"""
Calls modal to update the text input information of the event.
"""
await interaction.response.send_modal(
ParticipantModal(interaction.message.embeds[0])
)
@nextcord.ui.button(label="Confirm", style=nextcord.ButtonStyle.green, row=1)
async def confirm(
self, button: nextcord.ui.Button, interaction: nextcord.Interaction
):
"""
Submits the event embed to the event channel. Removes view and embed from recording message.
Sends point information to database.
"""
discord_users = self.event_participants.values.members
if discord_users:
discord_users_list: list[str] = [
str(user.id) for user in discord_users if user.id is not self.host_id
]
record_event_participation(self.config, discord_users_list, True)
non_discord_users = interaction.message.embeds[0].fields[1].value
if non_discord_users:
non_discord_users_list: list[str] = non_discord_users.split("\n")
record_event_participation(self.config, non_discord_users_list, False)
record_event_host(self.config, self.host_id)
event_channel: nextcord.TextChannel = interaction.guild.get_channel(
self.config.params.event_post_channel_id
)
await event_channel.send(embed=interaction.message.embeds[0])
await interaction.response.edit_message(
content="Event has been submitted.", view=None, embed=None
)
self.stop()
class ParticipantModal(nextcord.ui.Modal):
"""
This modal contains all the text edits for an event. You can change the name, description, and add the usernames
of participants who are not in the discord.
"""
# TODO turn this embed into a dict
def __init__(self, embed):
super().__init__(
"Edit the event.",
timeout=5 * 60,
)
self.embed: nextcord.Embed = embed
self.name: nextcord.ui.TextInput = nextcord.ui.TextInput(
required=True,
label="Event Name",
default_value=self.embed.title,
)
self.description: nextcord.ui.TextInput = nextcord.ui.TextInput(
required=False,
label="Event Description",
default_value=self.embed.description,
style=TextInputStyle.paragraph,
placeholder="Add a description if desired.",
max_length=1000,
)
self.participants: nextcord.ui.TextInput = nextcord.ui.TextInput(
required=False,
label="Non-Discord Usernames",
style=TextInputStyle.paragraph,
placeholder="Please separate usernames with a new line.",
default_value=self.embed.fields[1].value,
)
self.add_item(self.name)
self.add_item(self.description)
self.add_item(self.participants)
async def callback(self, interaction: nextcord.Interaction):
self.embed.title = self.name.value
self.embed.description = self.description.value
self.embed.set_field_at(
index=1, name="Non-Discord Participants", value=self.participants.value
)
await interaction.response.edit_message(embed=self.embed)
class ParticipantSelect(nextcord.ui.UserSelect):
"""
A selection drop down for discord members. Updates the embed with all users selected.
"""
def __init__(self) -> None:
super().__init__(
min_values=1,
max_values=25,
placeholder="Select all participants",
row=0,
)
async def callback(self, interaction: nextcord.Interaction):
embed: nextcord.Embed = interaction.message.embeds[0]
participants: str = "\n".join(
[f"<@{participant.id}>" for participant in self.values.members]
)
embed.set_field_at(0, name="Participants", value=participants)
await interaction.response.edit_message(embed=embed)
+1 -1
View File
@@ -24,7 +24,7 @@ class RequestCog(commands.Cog, name="Request Commands"):
@nextcord.slash_command() @nextcord.slash_command()
async def request(self, interaction: nextcord.Interaction): async def request(self, interaction: nextcord.Interaction):
""" """
Parent slash command for request. Never called. Parent slash command for help. Never called.
""" """
@request.subcommand( @request.subcommand(
+8 -8
View File
@@ -7,7 +7,7 @@ from nextcord.ext import application_checks, commands
from classes.election_cycle import ElectionCycle from classes.election_cycle import ElectionCycle
from config import DakinyConfig from config import DakinyConfig
from utils import get_current_election_cycle from utils import get_current_cycle
def is_me(): def is_me():
@@ -50,7 +50,7 @@ class TestCog(commands.Cog, name="Test commands."):
config: DakinyConfig = self.bot.config config: DakinyConfig = self.bot.config
cycle = ElectionCycle( cycle = ElectionCycle(
get_current_election_cycle(config), get_current_cycle(config),
config, config,
self.bot.get_guild(config.params.guild_id), self.bot.get_guild(config.params.guild_id),
) )
@@ -67,7 +67,7 @@ class TestCog(commands.Cog, name="Test commands."):
""" """
config: DakinyConfig = self.bot.config config: DakinyConfig = self.bot.config
cycle = ElectionCycle( cycle = ElectionCycle(
get_current_election_cycle(config), get_current_cycle(config),
config, config,
self.bot.get_guild(config.params.guild_id), self.bot.get_guild(config.params.guild_id),
) )
@@ -84,7 +84,7 @@ class TestCog(commands.Cog, name="Test commands."):
""" """
config: DakinyConfig = self.bot.config config: DakinyConfig = self.bot.config
cycle = ElectionCycle( cycle = ElectionCycle(
get_current_election_cycle(config), get_current_cycle(config),
config, config,
self.bot.get_guild(config.params.guild_id), self.bot.get_guild(config.params.guild_id),
) )
@@ -101,7 +101,7 @@ class TestCog(commands.Cog, name="Test commands."):
""" """
config: DakinyConfig = self.bot.config config: DakinyConfig = self.bot.config
cycle = ElectionCycle( cycle = ElectionCycle(
get_current_election_cycle(config), get_current_cycle(config),
config, config,
self.bot.get_guild(config.params.guild_id), self.bot.get_guild(config.params.guild_id),
) )
@@ -112,7 +112,7 @@ class TestCog(commands.Cog, name="Test commands."):
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_election_cycle(config), get_current_cycle(config),
config, config,
self.bot.get_guild(config.params.guild_id), self.bot.get_guild(config.params.guild_id),
) )
@@ -123,7 +123,7 @@ class TestCog(commands.Cog, name="Test commands."):
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_election_cycle(config), get_current_cycle(config),
config, config,
self.bot.get_guild(config.params.guild_id), self.bot.get_guild(config.params.guild_id),
) )
@@ -134,7 +134,7 @@ class TestCog(commands.Cog, name="Test commands."):
async def term_start(self, interaction: nextcord.Interaction): async def term_start(self, interaction: nextcord.Interaction):
config: DakinyConfig = self.bot.config config: DakinyConfig = self.bot.config
cycle = ElectionCycle( cycle = ElectionCycle(
get_current_election_cycle(config), get_current_cycle(config),
config, config,
self.bot.get_guild(config.params.guild_id), self.bot.get_guild(config.params.guild_id),
) )
+2 -102
View File
@@ -3,13 +3,12 @@ Commands for viewing information in the database.
""" """
import nextcord import nextcord
import pandas as pd
from nextcord.ext import commands from nextcord.ext import commands
from sqlalchemy import select from sqlalchemy import select
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from database_setup.sql_data_classes import ( from database_setup.sql_data_classes import (
ParticipationPoints, ElectionInformation,
Presences, Presences,
Votes, Votes,
engine, engine,
@@ -32,77 +31,6 @@ class ViewCog(commands.Cog, name="View Commands"):
Parent slash command for set. Never called. Parent slash command for set. Never called.
""" """
@view.subcommand(description="Show event points.")
async def event_points(
self,
interaction: nextcord.Interaction,
quarter_name: str = nextcord.SlashOption(
description="The quarter to view",
required=False,
),
):
# just in case
await interaction.response.defer(ephemeral=True)
with Session(engine) as session:
if quarter_name:
df = pd.read_sql_query(
sql=session.query(ParticipationPoints)
.where(ParticipationPoints.Cycle.startswith(quarter_name))
.statement,
con=engine,
)
else:
df = pd.read_sql_query(
sql=session.query(ParticipationPoints).statement,
con=engine,
)
if df.empty:
await interaction.followup.send(
f'Quarter "{quarter_name}" is invalid.', ephemeral=True
)
return
cycles = df.groupby("Cycle")
content = ""
for cycle in cycles.groups:
content += f"**{cycle}**\n"
unsorted_all = cycles.get_group(cycle).groupby("DiscordMember")
members = unsorted_all.get_group(True)
non_members = unsorted_all.get_group(False)
sorted_members = members.sort_values(
by="UserId",
key=lambda user_ids: (
[
interaction.guild.get_member(int(id)).display_name
for id in user_ids
]
),
)
sorted_non_members = non_members.sort_values(by="UserId")
sorted_all = pd.concat(
[sorted_members, sorted_non_members], ignore_index=True, sort=False
)
for row in sorted_all.itertuples():
userid = row.UserId
points = row.Points
discord_member = row.DiscordMember
content += (
f"<@{userid}>: {points}\n"
if discord_member
else f"{userid}: {points}\n"
)
content += "\n"
if len(content) > 2000:
await interaction.followup.send(
"Message length is too long, please select search to limit results."
)
return
await interaction.followup.send(content=content, ephemeral=True)
@view.subcommand(description="Show all possible presence choices.") @view.subcommand(description="Show all possible presence choices.")
async def presences( async def presences(
self, self,
@@ -193,7 +121,7 @@ class ViewCog(commands.Cog, name="View Commands"):
""" """
with Session(engine) as session: with Session(engine) as session:
stmt = select(Votes.ElectionCycle).distinct() stmt = select(ElectionInformation.ElectionCycle)
elections = session.scalars(stmt) elections = session.scalars(stmt)
# if empty compare string # if empty compare string
@@ -207,31 +135,3 @@ class ViewCog(commands.Cog, name="View Commands"):
if election.lower().startswith(election_name.lower()) if election.lower().startswith(election_name.lower())
] ]
await interaction.response.send_autocomplete(autofilled_elections[:25]) await interaction.response.send_autocomplete(autofilled_elections[:25])
@event_points.on_autocomplete("quarter_name")
async def event_points_autocomplete(
self, interaction: nextcord.Interaction, quarter_name: str
):
"""
Collects all elections that start with the election string.
Args:
interaction (nextcord.Interaction): Interaction with command.
quarter_name (str): String to run autocomplete on.
"""
with Session(engine) as session:
stmt = select(ParticipationPoints.Cycle).distinct()
quarters = session.scalars(stmt)
# if empty compare string
if not quarter_name:
await interaction.response.send_autocomplete(list(quarters)[:25])
return
autofilled_quarters: "list[str]" = [
quarter
for quarter in quarters
if quarter.lower().startswith(quarter_name.lower())
]
await interaction.response.send_autocomplete(autofilled_quarters[:25])
+4 -12
View File
@@ -15,7 +15,7 @@ from classes.election_cycle import ElectionCycle
from config import DakinyConfig from config import DakinyConfig
from dakiny_bot import birthday_list from dakiny_bot import birthday_list
from database_setup.sql_data_classes import UserBirthday, engine from database_setup.sql_data_classes import UserBirthday, engine
from utils import get_current_election_cycle from utils import get_current_cycle
class DailyLoop(commands.Cog, name="Daily Loop"): class DailyLoop(commands.Cog, name="Daily Loop"):
@@ -77,11 +77,7 @@ class DailyLoop(commands.Cog, name="Daily Loop"):
""" """
config: DakinyConfig = self.bot.config config: DakinyConfig = self.bot.config
cycle = get_current_election_cycle(config) cycle = get_current_cycle(config)
# prevent exception from using cycle as an Int in an array
if cycle is None:
return None
return ElectionCycle(cycle, config, self.bot.get_guild(config.params.guild_id)) return ElectionCycle(cycle, config, self.bot.get_guild(config.params.guild_id))
@@ -111,14 +107,10 @@ class DailyLoop(commands.Cog, name="Daily Loop"):
today = datetime.today() today = datetime.today()
guild: nextcord.Guild = self.bot.get_guild(self.bot.config.params.guild_id) guild: nextcord.Guild = self.bot.get_guild(self.bot.config.params.guild_id)
announce_channel: nextcord.TextChannel = guild.get_channel( announce_channel: nextcord.TextChannel = guild.get_channel(self.bot.config.params.general_channel_id)
self.bot.config.params.general_channel_id
)
cakedays: list[nextcord.Member] = [ cakedays: list[nextcord.Member] = [
human human for human in guild.humans if human.joined_at.month == today.month and human.joined_at.day == today.day
for human in guild.humans
if human.joined_at.month == today.month and human.joined_at.day == today.day
] ]
for member in cakedays: for member in cakedays:
-5
View File
@@ -1,7 +1,6 @@
""" """
File contains classes defining the Hydra configuraton structure. File contains classes defining the Hydra configuraton structure.
""" """
from dataclasses import dataclass from dataclasses import dataclass
@@ -18,10 +17,6 @@ class Params:
clan_info_channel_id: int clan_info_channel_id: int
clan_member_role_id: int clan_member_role_id: int
discord_token: str discord_token: str
event_host_points: int
event_host_role_id: int
event_participate_points: int
event_post_channel_id: int
general_channel_id: int general_channel_id: int
guild_id: int guild_id: int
high_council_role_id: int high_council_role_id: int
-8
View File
@@ -39,11 +39,3 @@ CREATE TABLE Presences (
Id integer PRIMARY KEY, Id integer PRIMARY KEY,
Presence varchar(100) not null Presence varchar(100) not null
); );
CREATE TABLE ParticipationPoints (
Cycle varchar(30) not null,
UserId varchar(32) not null,
DiscordMember boolean not null,
Points int unsigned DEFAULT 0,
PRIMARY KEY (Cycle, UserId)
);
-2
View File
@@ -1,7 +1,6 @@
""" """
Simple file to set up the sqlalchemy connection to database. Simple file to set up the sqlalchemy connection to database.
""" """
from sqlalchemy import create_engine from sqlalchemy import create_engine
from sqlalchemy.ext.automap import automap_base from sqlalchemy.ext.automap import automap_base
@@ -17,4 +16,3 @@ CouncilMembers = Base.classes.CouncilMembers
Votes = Base.classes.Votes Votes = Base.classes.Votes
UserBirthday = Base.classes.UserBirthday UserBirthday = Base.classes.UserBirthday
Presences = Base.classes.Presences Presences = Base.classes.Presences
ParticipationPoints = Base.classes.ParticipationPoints
-1
View File
@@ -3,4 +3,3 @@ python-dotenv==1.0.0
pytz==2022.7.1 pytz==2022.7.1
hydra-core==1.3.2 hydra-core==1.3.2
sqlalchemy<2.0 sqlalchemy<2.0
pandas==1.5.2
+10 -138
View File
@@ -4,17 +4,11 @@ File contains util functions.
from datetime import datetime from datetime import datetime
import nextcord
from sqlalchemy import select from sqlalchemy import 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, Votes, engine
CouncilMembers,
ParticipationPoints,
Votes,
engine,
)
NOMINEE_SPLITTER = "========================================\n\n" NOMINEE_SPLITTER = "========================================\n\n"
@@ -37,9 +31,6 @@ def get_datetime(day: str) -> datetime:
if datetime.today().month == 12 and month < 12: if datetime.today().month == 12 and month < 12:
year += 1 year += 1
if datetime.today().month == 1 and month > 1:
year -= 1
return datetime(year, month, day) return datetime(year, month, day)
@@ -53,27 +44,10 @@ def get_election_cycle_name(config: DakinyConfig) -> str:
Returns: Returns:
str: the name of the election cycle str: the name of the election cycle
""" """
cycle = get_current_election_cycle(config)
current_cycle = config.election_cycles[cycle]
return f"vote-{get_datetime(current_cycle.term_start).year}-{current_cycle.name}"
def get_cycle_name(config: DakinyConfig) -> str:
"""
Builds the name of the current cycle/quarter
Args:
config (DakinyConfig): the config used to know the election cycle.
Returns:
str: the name of the cycle.
"""
cycle = get_current_cycle(config) cycle = get_current_cycle(config)
current_cycle = config.election_cycles[cycle] current_cycle = config.election_cycles[cycle]
return f"{get_datetime(current_cycle.term_start).year}-{current_cycle.name}" return f"vote-{get_datetime(current_cycle.term_start).year}-{current_cycle.name}"
def get_dm_election_name(config: DakinyConfig) -> str: def get_dm_election_name(config: DakinyConfig) -> str:
@@ -104,7 +78,7 @@ def get_cl_election_name(config: DakinyConfig) -> str:
return f"{get_election_cycle_name(config)}-cl" return f"{get_election_cycle_name(config)}-cl"
def get_current_election_cycle(config: DakinyConfig) -> int: def get_current_cycle(config: DakinyConfig) -> int:
""" """
Returns index for active election. An election is considered active between the election start and the term start. Returns index for active election. An election is considered active between the election start and the term start.
@@ -112,7 +86,7 @@ def get_current_election_cycle(config: DakinyConfig) -> int:
config (DakinyConfig): Config object to use config (DakinyConfig): Config object to use
Returns: Returns:
int: cycle index for active election. None for no active cycle int: cycle index for active election. -1 for no active cycle
""" """
today = datetime.today() today = datetime.today()
@@ -124,38 +98,15 @@ def get_current_election_cycle(config: DakinyConfig) -> int:
): ):
return cycle return cycle
return None return -1
def get_current_cycle(config: DakinyConfig) -> int: def build_votes_str(config: DakinyConfig) -> str:
"""
Returns the index for the current cycle/quarter. Defined as between term start and end. Shouldn't return none
Args:
config (DakinyConfig): Config object to use
Returns:
int: cycle index for current cycle.
"""
today = datetime.today()
for cycle, election in enumerate(config.election_cycles):
if (
today.date() >= get_datetime(election.term_start).date()
and today.date() <= get_datetime(election.term_end).date()
):
return cycle
return None
def build_votes_str(config: DakinyConfig, guild: nextcord.Guild) -> str:
""" """
Creates a string that contains all nominees and their votes to be sent as a discord message. Creates a string that contains all nominees and their votes to be sent as a discord message.
Args: Args:
config (DakinyConfig): Daking config object config (DakinyConfig): Daking config object
guild (nextcord.Guild): The guild object. Used to get display names for sorting.
Returns: Returns:
str: String that contains all nominees and their votes. str: String that contains all nominees and their votes.
@@ -168,10 +119,7 @@ def build_votes_str(config: DakinyConfig, guild: nextcord.Guild) -> str:
CouncilMembers.ElectionCycle == get_election_cycle_name(config) CouncilMembers.ElectionCycle == get_election_cycle_name(config)
) )
for nominee in sorted( for nominee in session.scalars(stmt):
session.scalars(stmt),
key=lambda nominee: guild.get_member(nominee.MemberId).display_name,
):
votes[nominee.MemberId] = 0 votes[nominee.MemberId] = 0
stmt = select(Votes).where( stmt = select(Votes).where(
@@ -188,7 +136,7 @@ def build_votes_str(config: DakinyConfig, guild: nextcord.Guild) -> str:
return votes_str return votes_str
def build_highcouncil_votes_str(config: DakinyConfig, guild: nextcord.Guild) -> str: def build_highcouncil_votes_str(config: DakinyConfig) -> str:
""" """
Creates a string that contains all high council nominees and their votes to be sent as a discord message. Creates a string that contains all high council nominees and their votes to be sent as a discord message.
@@ -197,7 +145,6 @@ def build_highcouncil_votes_str(config: DakinyConfig, guild: nextcord.Guild) ->
Returns: Returns:
str: String that contains all nominees and their votes. str: String that contains all nominees and their votes.
guild (nextcord.Guild): The guild object. Used to get display names for sorting.
""" """
cl_votes: dict[int, int] = {} cl_votes: dict[int, int] = {}
@@ -210,10 +157,7 @@ def build_highcouncil_votes_str(config: DakinyConfig, guild: nextcord.Guild) ->
.filter(CouncilMembers.ClanLeaderSpeechId.is_not(None)) .filter(CouncilMembers.ClanLeaderSpeechId.is_not(None))
) )
for nominee in sorted( for nominee in session.scalars(stmt):
session.scalars(stmt),
key=lambda nominee: guild.get_member(nominee.MemberId).display_name,
):
cl_votes[nominee.MemberId] = 0 cl_votes[nominee.MemberId] = 0
stmt = select(Votes).where(Votes.ElectionCycle == get_cl_election_name(config)) stmt = select(Votes).where(Votes.ElectionCycle == get_cl_election_name(config))
@@ -228,10 +172,7 @@ def build_highcouncil_votes_str(config: DakinyConfig, guild: nextcord.Guild) ->
.filter(CouncilMembers.DiscordManagerSpeechId.is_not(None)) .filter(CouncilMembers.DiscordManagerSpeechId.is_not(None))
) )
for nominee in sorted( for nominee in session.scalars(stmt):
session.scalars(stmt),
key=lambda nominee: guild.get_member(nominee.MemberId).display_name,
):
dm_votes[nominee.MemberId] = 0 dm_votes[nominee.MemberId] = 0
stmt = select(Votes).where(Votes.ElectionCycle == get_dm_election_name(config)) stmt = select(Votes).where(Votes.ElectionCycle == get_dm_election_name(config))
@@ -319,72 +260,3 @@ def decorate_dm_nomination(user_id: int, speech: str) -> str:
msg += speech msg += speech
return msg return msg
def record_event_participation(config: DakinyConfig, users: list[str], is_member: bool):
"""
Adds participation points to all users listed. Checks if they don't exist in order to make a new entry, otherwise
adds points to the existing value.
Args:
config (DakinyConfig): Dakiny config for getting points
users (list[int]): users that participated and need points.
is_member (bool): whether the users are a discord member or not
"""
cycle = get_cycle_name(config)
participation_point_value = config.params.event_participate_points
with Session(engine) as session:
for user in users:
stmt = (
select(ParticipationPoints)
.where(ParticipationPoints.UserId == user)
.where(ParticipationPoints.Cycle == cycle)
)
points = session.scalar(stmt)
if points is None:
new_points = ParticipationPoints(
Cycle=cycle,
UserId=user,
DiscordMember=is_member,
Points=participation_point_value,
)
session.add(new_points)
else:
points.Points += participation_point_value
session.commit()
def record_event_host(config: DakinyConfig, user: int):
"""
Adds host points to the given user. Checks if they don't exist in order to make a new entry, otherwise adds points
to the existing value.
Args:
config (DakinyConfig): Dakiny config for getting points
user (int): Id of user that hosted.
"""
cycle = get_cycle_name(config)
host_point_value = config.params.event_host_points
with Session(engine) as session:
stmt = (
select(ParticipationPoints)
.where(ParticipationPoints.UserId == str(user))
.where(ParticipationPoints.Cycle == cycle)
)
points = session.scalar(stmt)
if points is None:
new_points = ParticipationPoints(
Cycle=cycle,
UserId=str(user),
DiscordMember=True,
Points=host_point_value,
)
session.add(new_points)
else:
points.Points += host_point_value
session.commit()