Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dbd2863aab | ||
|
|
426f009ca7 | ||
|
|
ed07b2e231 | ||
|
|
0caa41cc90 | ||
|
|
e93f37dcf0 | ||
|
|
44c3961c46 | ||
|
|
0dcdd038b8 | ||
|
|
eb5d465ac9 | ||
|
|
eb1c87fbf4 | ||
|
|
cbd73a104e | ||
|
|
95ad47368c | ||
|
|
dea3f7cabf | ||
|
|
6a71e9ab1d | ||
|
|
bc56830396 | ||
|
|
1d14f8171d | ||
|
|
2efd380a7e | ||
|
|
475170025a | ||
|
|
f4f3bfe103 | ||
|
|
6827658b4a | ||
|
|
85a3ea0418 |
@@ -105,6 +105,7 @@ venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
poetry.lock
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
|
||||
+4
-7
@@ -1,22 +1,19 @@
|
||||
FROM python:3.10.6-slim
|
||||
FROM python:3.11.9-slim
|
||||
|
||||
# install dependencies
|
||||
RUN apt-get update && apt-get -y upgrade && apt-get -y install git
|
||||
|
||||
RUN pip install --upgrade pip
|
||||
RUN apt-get update && apt-get -y upgrade && apt-get -y install git sqlite3
|
||||
|
||||
WORKDIR /home
|
||||
|
||||
COPY requirements.txt requirements.txt
|
||||
|
||||
COPY config.py config.py
|
||||
COPY main.py main.py
|
||||
COPY utils.py utils.py
|
||||
COPY pyproject.toml pyproject.toml
|
||||
|
||||
COPY classes classes/
|
||||
COPY cogs cogs/
|
||||
COPY database_setup database_setup/
|
||||
|
||||
RUN pip install -r requirements.txt
|
||||
RUN pip install --upgrade pip && pip install poetry && poetry export -f requirements.txt --output requirements.txt && pip install -r requirements.txt
|
||||
|
||||
CMD ["python3", "-u", "./main.py"]
|
||||
+20
-10
@@ -22,12 +22,11 @@ from database_setup.sql_data_classes import (
|
||||
)
|
||||
from utils import (
|
||||
TEMPLATES_DIR,
|
||||
VoteType,
|
||||
build_highcouncil_votes_str,
|
||||
build_votes_str,
|
||||
edit_clan_council_info,
|
||||
get_cl_election_name,
|
||||
get_datetime,
|
||||
get_dm_election_name,
|
||||
get_election_name,
|
||||
)
|
||||
|
||||
@@ -294,7 +293,11 @@ class ElectionCycle:
|
||||
session.commit()
|
||||
|
||||
# add the highcouncil role to everyone with 3 or more votes. set elected to true in database
|
||||
stmt = select(Votes.VotedForId).where(Votes.ElectionCycle == election_name)
|
||||
stmt = (
|
||||
select(Votes.VotedForId)
|
||||
.where(Votes.ElectionCycle == election_name)
|
||||
.where(Votes.Type == VoteType.COUNCIL)
|
||||
)
|
||||
vote_count = collections.Counter(session.scalars(stmt))
|
||||
|
||||
for user_id, votes in vote_count.items():
|
||||
@@ -358,11 +361,13 @@ class ElectionCycle:
|
||||
self.config.params.clan_council_role_id
|
||||
)
|
||||
|
||||
election_cycle = get_election_name(self.config)
|
||||
|
||||
with Session(engine) as session:
|
||||
# role management
|
||||
stmt = (
|
||||
select(CouncilMembers.MemberId)
|
||||
.where(CouncilMembers.ElectionCycle == get_election_name(self.config))
|
||||
.where(CouncilMembers.ElectionCycle == election_cycle)
|
||||
.where(CouncilMembers.Elected == true())
|
||||
)
|
||||
|
||||
@@ -379,14 +384,19 @@ class ElectionCycle:
|
||||
|
||||
# announce high council members
|
||||
# ties are undefined behavior.
|
||||
dm_election = get_dm_election_name(self.config)
|
||||
cl_election = get_cl_election_name(self.config)
|
||||
stmt = select(Votes.VotedForId).where(Votes.ElectionCycle == dm_election)
|
||||
stmt = (
|
||||
select(Votes.VotedForId)
|
||||
.where(Votes.ElectionCycle == election_cycle)
|
||||
.where(Votes.Type == VoteType.DISCORDMANAGER)
|
||||
)
|
||||
dm_votes = collections.Counter(session.scalars(stmt))
|
||||
stmt = select(Votes.VotedForId).where(Votes.ElectionCycle == cl_election)
|
||||
stmt = (
|
||||
select(Votes.VotedForId)
|
||||
.where(Votes.ElectionCycle == election_cycle)
|
||||
.where(Votes.Type == VoteType.CLANLEADER)
|
||||
)
|
||||
cl_votes = collections.Counter(session.scalars(stmt))
|
||||
|
||||
election_cycle = get_election_name(self.config)
|
||||
try:
|
||||
dm_winner = max(dm_votes, key=dm_votes.get)
|
||||
stmt = (
|
||||
@@ -425,7 +435,7 @@ class ElectionCycle:
|
||||
await vote_msg.edit(view=None)
|
||||
|
||||
highcouncil_msg: str = (
|
||||
f"Congratulations for our high council members!\n Clan Leader: <@{cl_winner}>\n"
|
||||
f"Congratulations for our high council members!\nClan Leader: <@{cl_winner}>\n"
|
||||
)
|
||||
highcouncil_msg += f"Discord Manager: <@{dm_winner}>"
|
||||
await election_thread.send(highcouncil_msg)
|
||||
|
||||
@@ -17,12 +17,7 @@ from database_setup.sql_data_classes import (
|
||||
Votes,
|
||||
engine,
|
||||
)
|
||||
from utils import (
|
||||
build_highcouncil_votes_str,
|
||||
get_cl_election_name,
|
||||
get_dm_election_name,
|
||||
get_election_name,
|
||||
)
|
||||
from utils import VoteType, build_highcouncil_votes_str, get_election_name
|
||||
|
||||
|
||||
class VoteSelect(nextcord.ui.StringSelect):
|
||||
@@ -39,20 +34,10 @@ class VoteSelect(nextcord.ui.StringSelect):
|
||||
self.election_type = election_type
|
||||
|
||||
async def callback(self, interaction: Interaction):
|
||||
# decide on election type
|
||||
match self.election_type:
|
||||
case "cl":
|
||||
election_name: str = get_cl_election_name(self.config)
|
||||
case "dm":
|
||||
election_name: str = get_dm_election_name(self.config)
|
||||
case _:
|
||||
# should never happen
|
||||
raise ValueError('election type was not "cl" or "dm"')
|
||||
|
||||
cycle: str = get_election_name(self.config)
|
||||
election_name: str = get_election_name(self.config)
|
||||
with Session(engine) as session:
|
||||
stmt = select(ElectionInformation.HighCouncilVoteMsgId).where(
|
||||
ElectionInformation.ElectionCycle == cycle
|
||||
ElectionInformation.ElectionCycle == election_name
|
||||
)
|
||||
vote_msg_id = session.scalar(stmt)
|
||||
|
||||
@@ -65,6 +50,7 @@ class VoteSelect(nextcord.ui.StringSelect):
|
||||
ElectionCycle=election_name,
|
||||
VoterId=interaction.user.id,
|
||||
VotedForId=voted_for,
|
||||
Type=self.election_type,
|
||||
)
|
||||
|
||||
try:
|
||||
@@ -72,11 +58,13 @@ class VoteSelect(nextcord.ui.StringSelect):
|
||||
session.commit()
|
||||
|
||||
except exc.IntegrityError:
|
||||
# user already has a vote in the election and election type
|
||||
session.rollback()
|
||||
stmt = (
|
||||
update(Votes)
|
||||
.where(Votes.ElectionCycle == election_name)
|
||||
.where(Votes.VoterId == interaction.user.id)
|
||||
.where(Votes.Type == self.election_type)
|
||||
.values(VotedForId=voted_for)
|
||||
)
|
||||
session.execute(stmt)
|
||||
@@ -135,20 +123,20 @@ class VoteHighcouncilView(nextcord.ui.View):
|
||||
)
|
||||
return
|
||||
|
||||
cycle: str = get_election_name(self.config)
|
||||
election: str = get_cl_election_name(self.config)
|
||||
election_name: str = get_election_name(self.config)
|
||||
|
||||
with Session(engine) as session:
|
||||
stmt = (
|
||||
select(Votes.VotedForId)
|
||||
.where(Votes.ElectionCycle == election)
|
||||
.where(Votes.ElectionCycle == election_name)
|
||||
.where(Votes.VoterId == interaction.user.id)
|
||||
.where(Votes.Type == VoteType.CLANLEADER)
|
||||
)
|
||||
voted_for = session.scalar(stmt)
|
||||
|
||||
stmt = (
|
||||
select(CouncilMembers.MemberId)
|
||||
.where(CouncilMembers.ElectionCycle == cycle)
|
||||
.where(CouncilMembers.ElectionCycle == election_name)
|
||||
.filter(CouncilMembers.ClanLeaderSpeechId.is_not(None))
|
||||
)
|
||||
|
||||
@@ -175,7 +163,9 @@ class VoteHighcouncilView(nextcord.ui.View):
|
||||
|
||||
view = nextcord.ui.View()
|
||||
view.add_item(
|
||||
VoteSelect(options=options, config=self.config, election_type="cl")
|
||||
VoteSelect(
|
||||
options=options, config=self.config, election_type=VoteType.CLANLEADER
|
||||
)
|
||||
)
|
||||
|
||||
await interaction.response.send_message(
|
||||
@@ -213,20 +203,20 @@ class VoteHighcouncilView(nextcord.ui.View):
|
||||
)
|
||||
return
|
||||
|
||||
cycle: str = get_election_name(self.config)
|
||||
election: str = get_dm_election_name(self.config)
|
||||
election_name: str = get_election_name(self.config)
|
||||
|
||||
with Session(engine) as session:
|
||||
stmt = (
|
||||
select(Votes.VotedForId)
|
||||
.where(Votes.ElectionCycle == election)
|
||||
.where(Votes.ElectionCycle == election_name)
|
||||
.where(Votes.VoterId == interaction.user.id)
|
||||
.where(Votes.Type == VoteType.DISCORDMANAGER)
|
||||
)
|
||||
voted_for = session.scalar(stmt)
|
||||
|
||||
stmt = (
|
||||
select(CouncilMembers.MemberId)
|
||||
.where(CouncilMembers.ElectionCycle == cycle)
|
||||
.where(CouncilMembers.ElectionCycle == election_name)
|
||||
.filter(CouncilMembers.DiscordManagerSpeechId.is_not(None))
|
||||
)
|
||||
|
||||
@@ -253,7 +243,11 @@ class VoteHighcouncilView(nextcord.ui.View):
|
||||
|
||||
view = nextcord.ui.View()
|
||||
view.add_item(
|
||||
VoteSelect(options=options, config=self.config, election_type="dm")
|
||||
VoteSelect(
|
||||
options=options,
|
||||
config=self.config,
|
||||
election_type=VoteType.DISCORDMANAGER,
|
||||
)
|
||||
)
|
||||
|
||||
await interaction.response.send_message(
|
||||
|
||||
@@ -17,7 +17,7 @@ from database_setup.sql_data_classes import (
|
||||
Votes,
|
||||
engine,
|
||||
)
|
||||
from utils import build_votes_str, get_election_name
|
||||
from utils import VoteType, build_votes_str, get_election_name
|
||||
|
||||
|
||||
class VoteSelect(nextcord.ui.StringSelect):
|
||||
@@ -47,6 +47,7 @@ class VoteSelect(nextcord.ui.StringSelect):
|
||||
ElectionCycle=election_name,
|
||||
VoterId=interaction.user.id,
|
||||
VotedForId=voted_for,
|
||||
Type=VoteType.COUNCIL,
|
||||
)
|
||||
|
||||
try:
|
||||
@@ -59,6 +60,7 @@ class VoteSelect(nextcord.ui.StringSelect):
|
||||
update(Votes)
|
||||
.where(Votes.ElectionCycle == election_name)
|
||||
.where(Votes.VoterId == interaction.user.id)
|
||||
.where(Votes.Type == VoteType.COUNCIL)
|
||||
.values(VotedForId=voted_for)
|
||||
)
|
||||
session.execute(stmt)
|
||||
@@ -121,6 +123,7 @@ class VoteView(nextcord.ui.View):
|
||||
select(Votes.VotedForId)
|
||||
.where(Votes.ElectionCycle == election)
|
||||
.where(Votes.VoterId == interaction.user.id)
|
||||
.where(Votes.Type == VoteType.COUNCIL)
|
||||
)
|
||||
voted_for = session.scalar(stmt)
|
||||
|
||||
|
||||
+11
-1
@@ -14,6 +14,7 @@ from database_setup.sql_data_classes import (
|
||||
Votes,
|
||||
engine,
|
||||
)
|
||||
from utils import VoteType
|
||||
|
||||
|
||||
class ViewCog(commands.Cog, name="View Commands"):
|
||||
@@ -148,6 +149,11 @@ class ViewCog(commands.Cog, name="View Commands"):
|
||||
election_name: str = nextcord.SlashOption(
|
||||
required=True, description="The election you want to view votes for."
|
||||
),
|
||||
election_type: str = nextcord.SlashOption(
|
||||
required=True,
|
||||
description="The election type. Council, Discord Manager, or Clan Leader.",
|
||||
choices=VoteType,
|
||||
),
|
||||
):
|
||||
"""
|
||||
Takes in an election name and sends a response message to the user with a list of people who voted in that
|
||||
@@ -159,7 +165,11 @@ class ViewCog(commands.Cog, name="View Commands"):
|
||||
election_name (str): Is SlashOption. The name of the election to view votes for.
|
||||
"""
|
||||
|
||||
stmt = select(Votes).where(Votes.ElectionCycle == election_name)
|
||||
stmt = (
|
||||
select(Votes)
|
||||
.where(Votes.ElectionCycle == election_name)
|
||||
.where(Votes.Type == election_type)
|
||||
)
|
||||
|
||||
with Session(engine) as session:
|
||||
# Check if election exists.
|
||||
|
||||
@@ -25,8 +25,9 @@ CREATE TABLE Votes(
|
||||
ElectionCycle varchar(30) not null,
|
||||
VoterId bigint unsigned not null,
|
||||
VotedForId bigint unsigned,
|
||||
Type varchar(14) not null DEFAULT 'council' check("Type" in ('council', 'discordmanager', 'clanleader')),
|
||||
FOREIGN KEY (ElectionCycle) REFERENCES ElectionInformation(ElectionCycle),
|
||||
PRIMARY KEY (ElectionCycle, VoterId)
|
||||
PRIMARY KEY (ElectionCycle, VoterId, Type)
|
||||
);
|
||||
|
||||
CREATE TABLE UserBirthday (
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
[tool.poetry]
|
||||
name = "dakiny-bot"
|
||||
version = "0.1.0"
|
||||
description = "Dakiny's Discord Bot."
|
||||
authors = ["imcompiling <[email protected]>"]
|
||||
readme = "README.md"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.11"
|
||||
gitpython = "3.1.43"
|
||||
fastapi = "0.111.0"
|
||||
hydra-core = "1.3.2"
|
||||
nextcord = "2.4.2"
|
||||
pandas = "1.5.2"
|
||||
python-dotenv = "1.0.0"
|
||||
pytz = "2022.7.1"
|
||||
sqlalchemy = "1.4.46"
|
||||
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
@@ -1,8 +0,0 @@
|
||||
nextcord==2.4.2
|
||||
python-dotenv==1.0.0
|
||||
pytz==2022.7.1
|
||||
hydra-core==1.3.2
|
||||
sqlalchemy<2.0
|
||||
pandas==1.5.2
|
||||
fastapi==0.111.0
|
||||
GitPython==3.1.43
|
||||
@@ -4,6 +4,7 @@ File contains util functions.
|
||||
|
||||
import os
|
||||
from datetime import datetime
|
||||
from enum import StrEnum
|
||||
from typing import Iterable
|
||||
|
||||
import nextcord
|
||||
@@ -24,6 +25,8 @@ REPO_DIR = "./dakiny-messages"
|
||||
MESSAGES_DIR = f"{REPO_DIR}/messages"
|
||||
TEMPLATES_DIR = f"{REPO_DIR}/message_templates"
|
||||
|
||||
VoteType = StrEnum("VoteType", ["COUNCIL", "DISCORDMANAGER", "CLANLEADER"])
|
||||
|
||||
|
||||
def get_datetime(day: str) -> datetime:
|
||||
"""
|
||||
@@ -82,34 +85,6 @@ def get_quarter_name(config: DakinyConfig) -> str:
|
||||
return f"{get_datetime(current_cycle.term_start).year}-{current_cycle.name}"
|
||||
|
||||
|
||||
def get_dm_election_name(config: DakinyConfig) -> str:
|
||||
"""
|
||||
creates the name of the discord manager election
|
||||
|
||||
Args:
|
||||
config (DakinyConfig): Config sent to get_election_cycle_name
|
||||
|
||||
Returns:
|
||||
str: the name of the election
|
||||
"""
|
||||
|
||||
return f"{get_election_name(config)}-dm"
|
||||
|
||||
|
||||
def get_cl_election_name(config: DakinyConfig) -> str:
|
||||
"""
|
||||
creates the name of the clan leader election
|
||||
|
||||
Args:
|
||||
config (DakinyConfig): Config sent to get_election_cycle_name
|
||||
|
||||
Returns:
|
||||
str: the name of the election
|
||||
"""
|
||||
|
||||
return f"{get_election_name(config)}-cl"
|
||||
|
||||
|
||||
def get_current_election_cycle(config: DakinyConfig) -> int:
|
||||
"""
|
||||
Returns index for active election. An election is considered active between the election start and the term start.
|
||||
@@ -170,9 +145,11 @@ def build_votes_str(config: DakinyConfig, guild: nextcord.Guild) -> str:
|
||||
|
||||
votes: dict[int, int] = {}
|
||||
|
||||
election_name = get_election_name(config)
|
||||
|
||||
with Session(engine) as session:
|
||||
stmt = select(CouncilMembers).where(
|
||||
CouncilMembers.ElectionCycle == get_election_name(config)
|
||||
CouncilMembers.ElectionCycle == election_name
|
||||
)
|
||||
|
||||
for nominee in sorted(
|
||||
@@ -181,7 +158,11 @@ def build_votes_str(config: DakinyConfig, guild: nextcord.Guild) -> str:
|
||||
):
|
||||
votes[nominee.MemberId] = 0
|
||||
|
||||
stmt = select(Votes).where(Votes.ElectionCycle == get_election_name(config))
|
||||
stmt = (
|
||||
select(Votes)
|
||||
.where(Votes.ElectionCycle == election_name)
|
||||
.where(Votes.Type == VoteType.COUNCIL)
|
||||
)
|
||||
|
||||
for vote in session.scalars(stmt):
|
||||
if vote.VotedForId is not None:
|
||||
@@ -208,10 +189,12 @@ def build_highcouncil_votes_str(config: DakinyConfig, guild: nextcord.Guild) ->
|
||||
cl_votes: dict[int, int] = {}
|
||||
dm_votes: dict[int, int] = {}
|
||||
|
||||
election_name = get_election_name(config)
|
||||
|
||||
with Session(engine) as session:
|
||||
stmt = (
|
||||
select(CouncilMembers)
|
||||
.where(CouncilMembers.ElectionCycle == get_election_name(config))
|
||||
.where(CouncilMembers.ElectionCycle == election_name)
|
||||
.filter(CouncilMembers.ClanLeaderSpeechId.is_not(None))
|
||||
)
|
||||
|
||||
@@ -221,7 +204,11 @@ def build_highcouncil_votes_str(config: DakinyConfig, guild: nextcord.Guild) ->
|
||||
):
|
||||
cl_votes[nominee.MemberId] = 0
|
||||
|
||||
stmt = select(Votes).where(Votes.ElectionCycle == get_cl_election_name(config))
|
||||
stmt = (
|
||||
select(Votes)
|
||||
.where(Votes.ElectionCycle == election_name)
|
||||
.where(Votes.Type == VoteType.CLANLEADER)
|
||||
)
|
||||
|
||||
for vote in session.scalars(stmt):
|
||||
if vote.VotedForId is not None:
|
||||
@@ -229,7 +216,7 @@ def build_highcouncil_votes_str(config: DakinyConfig, guild: nextcord.Guild) ->
|
||||
|
||||
stmt = (
|
||||
select(CouncilMembers)
|
||||
.where(CouncilMembers.ElectionCycle == get_election_name(config))
|
||||
.where(CouncilMembers.ElectionCycle == election_name)
|
||||
.filter(CouncilMembers.DiscordManagerSpeechId.is_not(None))
|
||||
)
|
||||
|
||||
@@ -239,7 +226,11 @@ def build_highcouncil_votes_str(config: DakinyConfig, guild: nextcord.Guild) ->
|
||||
):
|
||||
dm_votes[nominee.MemberId] = 0
|
||||
|
||||
stmt = select(Votes).where(Votes.ElectionCycle == get_dm_election_name(config))
|
||||
stmt = (
|
||||
select(Votes)
|
||||
.where(Votes.ElectionCycle == election_name)
|
||||
.where(Votes.Type == VoteType.DISCORDMANAGER)
|
||||
)
|
||||
|
||||
for vote in session.scalars(stmt):
|
||||
if vote.VotedForId is not None:
|
||||
|
||||
Reference in New Issue
Block a user