Compare commits
55
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09958c31ad | ||
|
|
0f3596692f | ||
|
|
def9c4aa79 | ||
|
|
af3b8e9e69 | ||
|
|
a5655c4d6b | ||
|
|
a277566654 | ||
|
|
58c167bbe3 | ||
|
|
6adb98111b | ||
|
|
4d96aebeb1 | ||
|
|
d38f56ff41 | ||
|
|
95fb9e289b | ||
|
|
3bcd1a3a01 | ||
|
|
6c57644eb0 | ||
|
|
303e359c32 | ||
|
|
fb460ccc2c | ||
|
|
c5e4a94cd2 | ||
|
|
f95955dc7f | ||
|
|
dfea936aaa | ||
|
|
1df639499c | ||
|
|
be3ec007af | ||
|
|
e8839d2930 | ||
|
|
29eb21b286 | ||
|
|
b7439631d9 | ||
|
|
6b9d8f6ad9 | ||
|
|
c48fba9c85 | ||
|
|
7e3b57f4b6 | ||
|
|
889ba2fd6b | ||
|
|
8b5c954aa5 | ||
|
|
adc44d4466 | ||
|
|
1ab9cdfea3 | ||
|
|
5748159279 | ||
|
|
12b700f340 | ||
|
|
89534ed5b8 | ||
|
|
80dde1e8ed | ||
|
|
969f380b08 | ||
|
|
10d7014c41 | ||
|
|
89e77a6671 | ||
|
|
c2ff656114 | ||
|
|
81e2957fa5 | ||
|
|
ba24a268ec | ||
|
|
70d262d947 | ||
|
|
6199350cca | ||
|
|
c5e2b39648 | ||
|
|
5db2b43d6a | ||
|
|
b9be9e5470 | ||
|
|
6700199a36 | ||
|
|
8f9821e9c9 | ||
|
|
83af20e04c | ||
|
|
f1dd3cbd3b | ||
|
|
d56251c0b9 | ||
|
|
667a600ec6 | ||
|
|
03a94ca6dd | ||
|
|
9da598e4d9 | ||
|
|
3a280696ca | ||
|
|
8825afdb46 |
@@ -0,0 +1,6 @@
|
|||||||
|
.*
|
||||||
|
Dockerfile
|
||||||
|
LICENSE
|
||||||
|
README.md
|
||||||
|
renovate.json
|
||||||
|
permissions_required.txt
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# see https://editorconfig.org/
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.{yml,yaml}]
|
||||||
|
indent_size = 2
|
||||||
@@ -5,19 +5,21 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- '*'
|
- '*'
|
||||||
- '!main'
|
- '!main'
|
||||||
|
paths-ignore:
|
||||||
|
- "README.md"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Code
|
- name: Checkout Code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Install Docker
|
- name: Install Docker
|
||||||
uses: https://github.com/papodaca/install-docker-action@v1
|
uses: https://github.com/papodaca/install-docker-action@v1
|
||||||
- name: Log into container registry
|
- name: Log into container registry
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: gitea.cheezers.org
|
registry: gitea.cheezers.org
|
||||||
username: imcompiling
|
username: imcompiling
|
||||||
@@ -3,19 +3,21 @@ name: build_latest
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
|
paths-ignore:
|
||||||
|
- "README.md"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Code
|
- name: Checkout Code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Install Docker
|
- name: Install Docker
|
||||||
uses: https://github.com/papodaca/install-docker-action@v1
|
uses: https://github.com/papodaca/install-docker-action@v1
|
||||||
- name: Log into container registry
|
- name: Log into container registry
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: gitea.cheezers.org
|
registry: gitea.cheezers.org
|
||||||
username: imcompiling
|
username: imcompiling
|
||||||
@@ -9,13 +9,13 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Code
|
- name: Checkout Code
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
- name: Install Docker
|
- name: Install Docker
|
||||||
uses: https://github.com/papodaca/install-docker-action@v1
|
uses: https://github.com/papodaca/install-docker-action@v1
|
||||||
- name: Log into container registry
|
- name: Log into container registry
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: gitea.cheezers.org
|
registry: gitea.cheezers.org
|
||||||
username: imcompiling
|
username: imcompiling
|
||||||
+2
-3
@@ -105,7 +105,6 @@ venv/
|
|||||||
ENV/
|
ENV/
|
||||||
env.bak/
|
env.bak/
|
||||||
venv.bak/
|
venv.bak/
|
||||||
poetry.lock
|
|
||||||
|
|
||||||
# Spyder project settings
|
# Spyder project settings
|
||||||
.spyderproject
|
.spyderproject
|
||||||
@@ -137,5 +136,5 @@ TODO.txt
|
|||||||
sql_tester.py
|
sql_tester.py
|
||||||
conf
|
conf
|
||||||
outputs
|
outputs
|
||||||
database
|
/database
|
||||||
dakiny-messages/
|
dakiny-messages/
|
||||||
|
|||||||
Vendored
+3
-2
@@ -4,6 +4,7 @@
|
|||||||
"ms-python.python",
|
"ms-python.python",
|
||||||
"ms-python.debugpy",
|
"ms-python.debugpy",
|
||||||
"charliermarsh.ruff",
|
"charliermarsh.ruff",
|
||||||
"alexcvzz.vscode-sqlite"
|
"alexcvzz.vscode-sqlite",
|
||||||
|
"editorconfig.editorconfig"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+2
-2
@@ -8,8 +8,8 @@
|
|||||||
"name": "Python: Module",
|
"name": "Python: Module",
|
||||||
"type": "debugpy",
|
"type": "debugpy",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"module": "main",
|
"module": "dakiny_bot",
|
||||||
"justMyCode": true
|
"justMyCode": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+5
-2
@@ -3,9 +3,12 @@
|
|||||||
"aiofiles",
|
"aiofiles",
|
||||||
"autofilled",
|
"autofilled",
|
||||||
"blurple",
|
"blurple",
|
||||||
|
"CAKEDAY",
|
||||||
|
"cakedays",
|
||||||
"CLANLEADER",
|
"CLANLEADER",
|
||||||
"Dakiny",
|
"Dakiny",
|
||||||
"DISCORDMANAGER",
|
"DISCORDMANAGER",
|
||||||
"highcouncil"
|
"highcouncil",
|
||||||
|
"nextcord"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-13
@@ -1,19 +1,15 @@
|
|||||||
FROM python:3.12.3-slim
|
FROM python:3.13.3-slim
|
||||||
|
|
||||||
# install dependencies
|
# install dependencies
|
||||||
RUN apt-get update && apt-get -y upgrade && apt-get -y install git sqlite3
|
RUN apt-get update && apt-get -y upgrade && apt-get -y install git sqlite3
|
||||||
|
|
||||||
|
# install uv
|
||||||
|
COPY --from=ghcr.io/astral-sh/uv:0.6.14 /uv /uvx /bin/
|
||||||
|
|
||||||
|
COPY . /home
|
||||||
|
|
||||||
|
# Sync the project into a new environment, using the frozen lockfile
|
||||||
WORKDIR /home
|
WORKDIR /home
|
||||||
|
RUN uv sync --frozen --no-dev
|
||||||
|
|
||||||
COPY DakinySettings.py DakinySettings.py
|
CMD ["uv", "run", "--frozen", "--no-dev", "-m", "dakiny_bot"]
|
||||||
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 --upgrade pip && pip install poetry && poetry export -f requirements.txt --output requirements.txt && pip install -r requirements.txt
|
|
||||||
|
|
||||||
CMD ["python3", "-u", "./main.py"]
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
"""Empty init file for dakiny_bot module."""
|
||||||
|
|
||||||
|
from dakiny_bot.dakiny_settings import CONFIG_LOCATION, DakinySettings, settings
|
||||||
|
|
||||||
|
if settings is None:
|
||||||
|
tmp = DakinySettings.from_yaml_file(CONFIG_LOCATION)
|
||||||
|
settings = tmp[0] if isinstance(tmp, list) else tmp
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
"""Starts the app for dakiny_bot."""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from .app import run
|
||||||
|
|
||||||
|
nextcord_logger = logging.getLogger("nextcord")
|
||||||
|
nextcord_logger.setLevel(logging.DEBUG)
|
||||||
|
nextcord_handler = logging.FileHandler(filename="nextcord.log", encoding="utf-8", mode="w")
|
||||||
|
nextcord_handler.setFormatter(logging.Formatter("%(asctime)s:%(levelname)s:%(name)s: %(message)s"))
|
||||||
|
nextcord_logger.addHandler(nextcord_handler)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
run()
|
||||||
+10
-13
@@ -6,12 +6,13 @@ import os
|
|||||||
import nextcord
|
import nextcord
|
||||||
from nextcord.ext import commands
|
from nextcord.ext import commands
|
||||||
|
|
||||||
from classes.nominate_highcouncil_views import NominateHighCouncilView
|
from dakiny_bot.classes.nominate_highcouncil_views import NominateHighCouncilView
|
||||||
from classes.nominate_views import NominateView
|
from dakiny_bot.classes.nominate_views import NominateView
|
||||||
from classes.voting_highcouncil_views import VoteHighcouncilView
|
from dakiny_bot.classes.voting_highcouncil_views import VoteHighcouncilView
|
||||||
from classes.voting_views import VoteView
|
from dakiny_bot.classes.voting_views import VoteView
|
||||||
from DakinySettings import settings
|
from dakiny_bot.database import create_database
|
||||||
from database_setup import create_database
|
|
||||||
|
from .dakiny_settings import settings
|
||||||
|
|
||||||
birthday_list: list[int] = []
|
birthday_list: list[int] = []
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ handler.setFormatter(logging.Formatter("%(asctime)s:%(levelname)s:%(name)s: %(me
|
|||||||
logger.addHandler(handler)
|
logger.addHandler(handler)
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def run() -> None:
|
||||||
"""Builds and runs bot."""
|
"""Builds and runs bot."""
|
||||||
# Allows privileged intents for monitoring members joining, roles editing, and role assignments
|
# Allows privileged intents for monitoring members joining, roles editing, and role assignments
|
||||||
# These need to be enabled in the developer portal as well
|
# These need to be enabled in the developer portal as well
|
||||||
@@ -37,8 +38,8 @@ def main() -> None:
|
|||||||
bot = commands.Bot(intents=intents)
|
bot = commands.Bot(intents=intents)
|
||||||
|
|
||||||
# Get the modules of all cogs whose directory structure is ./cogs/<module_name>
|
# Get the modules of all cogs whose directory structure is ./cogs/<module_name>
|
||||||
for folder in os.listdir("cogs"):
|
for folder in os.listdir("dakiny_bot/cogs"):
|
||||||
bot.load_extension(f"cogs.{folder}")
|
bot.load_extension(f"dakiny_bot.cogs.{folder}")
|
||||||
|
|
||||||
@bot.listen()
|
@bot.listen()
|
||||||
async def on_ready() -> None:
|
async def on_ready() -> None:
|
||||||
@@ -53,7 +54,3 @@ def main() -> None:
|
|||||||
|
|
||||||
# Run Discord bot
|
# Run Discord bot
|
||||||
bot.run(settings.params.discord_token)
|
bot.run(settings.params.discord_token)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -5,28 +5,28 @@ from datetime import UTC, datetime, timedelta
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import nextcord
|
import nextcord
|
||||||
from classes.nominate_highcouncil_views import NominateHighCouncilView
|
from dakiny_bot.classes.nominate_highcouncil_views import NominateHighCouncilView
|
||||||
from classes.nominate_views import NominateView
|
from dakiny_bot.classes.nominate_views import NominateView
|
||||||
from classes.voting_highcouncil_views import VoteHighcouncilView
|
from dakiny_bot.classes.voting_highcouncil_views import VoteHighcouncilView
|
||||||
from classes.voting_views import VoteView
|
from dakiny_bot.classes.voting_views import VoteView
|
||||||
from DakinySettings import settings
|
from dakiny_bot.dakiny_settings import settings
|
||||||
from database_setup.sql_data_classes import (
|
from dakiny_bot.database.sql_data_classes import (
|
||||||
CouncilMembers,
|
CouncilMembers,
|
||||||
ElectionInformation,
|
ElectionInformation,
|
||||||
Votes,
|
Votes,
|
||||||
engine,
|
engine,
|
||||||
)
|
)
|
||||||
from sqlalchemy import select, true, update
|
from dakiny_bot.election_utils import get_datetime
|
||||||
from sqlalchemy.orm import Session
|
from dakiny_bot.utils import (
|
||||||
from utils import (
|
|
||||||
TEMPLATES_DIR,
|
TEMPLATES_DIR,
|
||||||
VoteType,
|
VoteType,
|
||||||
build_highcouncil_votes_str,
|
build_highcouncil_votes_str,
|
||||||
build_votes_str,
|
build_votes_str,
|
||||||
edit_clan_council_info,
|
edit_clan_council_info,
|
||||||
get_datetime,
|
|
||||||
get_election_name,
|
get_election_name,
|
||||||
)
|
)
|
||||||
|
from sqlalchemy import select, true, update
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
REQUIRED_VOTES_TO_BE_ELECTED = 3
|
REQUIRED_VOTES_TO_BE_ELECTED = 3
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ class Election:
|
|||||||
list[str]: A list of message contents in the correct order. Must be a string because the message is too
|
list[str]: A list of message contents in the correct order. Must be a string because the message is too
|
||||||
long.
|
long.
|
||||||
"""
|
"""
|
||||||
with Path(f"{TEMPLATES_DIR}/election_announcement.txt", encoding="utf8").open() as file:
|
with Path(f"{TEMPLATES_DIR}/election_announcement.txt").open() as file:
|
||||||
message = file.read()
|
message = file.read()
|
||||||
|
|
||||||
next_election = get_datetime(
|
next_election = get_datetime(
|
||||||
@@ -97,7 +97,7 @@ class Election:
|
|||||||
Returns:
|
Returns:
|
||||||
str: Message to send.
|
str: Message to send.
|
||||||
"""
|
"""
|
||||||
with Path(f"{TEMPLATES_DIR}/highcouncil_election.txt", encoding="utf8").open() as file:
|
with Path(f"{TEMPLATES_DIR}/highcouncil_election.txt").open() as file:
|
||||||
message = file.read()
|
message = file.read()
|
||||||
|
|
||||||
return message.format(
|
return message.format(
|
||||||
@@ -115,7 +115,7 @@ class Election:
|
|||||||
Returns:
|
Returns:
|
||||||
str: Message to send.
|
str: Message to send.
|
||||||
"""
|
"""
|
||||||
with Path(f"{TEMPLATES_DIR}/highcouncil_vote.txt", encoding="utf8").open() as file:
|
with Path(f"{TEMPLATES_DIR}/highcouncil_vote.txt").open() as file:
|
||||||
message = file.read()
|
message = file.read()
|
||||||
|
|
||||||
return message.format(
|
return message.format(
|
||||||
@@ -130,7 +130,7 @@ class Election:
|
|||||||
Returns:
|
Returns:
|
||||||
str: Message to send
|
str: Message to send
|
||||||
"""
|
"""
|
||||||
with Path(f"{TEMPLATES_DIR}/vote_start.txt", encoding="utf8").open() as file:
|
with Path(f"{TEMPLATES_DIR}/vote_start.txt").open() as file:
|
||||||
message = file.read()
|
message = file.read()
|
||||||
vote_end: datetime = get_datetime(settings.election_cycles[self.cycle].voting_end)
|
vote_end: datetime = get_datetime(settings.election_cycles[self.cycle].voting_end)
|
||||||
|
|
||||||
@@ -200,7 +200,7 @@ class Election:
|
|||||||
election_thread: nextcord.Thread = self.guild.get_thread(self.get_election_info().ThreadId)
|
election_thread: nextcord.Thread = self.guild.get_thread(self.get_election_info().ThreadId)
|
||||||
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(settings, self.guild),
|
build_votes_str(self.guild),
|
||||||
view=VoteView(self.guild),
|
view=VoteView(self.guild),
|
||||||
)
|
)
|
||||||
|
|
||||||
+6
-6
@@ -1,17 +1,17 @@
|
|||||||
"""Contains various views to be used in the high council nomination process."""
|
"""Contains various views to be used in the high council nomination process."""
|
||||||
|
|
||||||
import nextcord
|
import nextcord
|
||||||
from DakinySettings import settings
|
from dakiny_bot.dakiny_settings import settings
|
||||||
from database_setup.sql_data_classes import CouncilMembers, engine
|
from dakiny_bot.database.sql_data_classes import CouncilMembers, engine
|
||||||
from nextcord.interactions import Interaction
|
from dakiny_bot.utils import (
|
||||||
from sqlalchemy import select
|
|
||||||
from sqlalchemy.orm import Session
|
|
||||||
from utils import (
|
|
||||||
NOMINEE_SPLITTER,
|
NOMINEE_SPLITTER,
|
||||||
decorate_cl_nomination,
|
decorate_cl_nomination,
|
||||||
decorate_dm_nomination,
|
decorate_dm_nomination,
|
||||||
get_election_name,
|
get_election_name,
|
||||||
)
|
)
|
||||||
|
from nextcord.interactions import Interaction
|
||||||
|
from sqlalchemy import select
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
|
|
||||||
class NominateDMModal(nextcord.ui.Modal):
|
class NominateDMModal(nextcord.ui.Modal):
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
"""Contains various views to be used in the nomination process."""
|
"""Contains various views to be used in the nomination process."""
|
||||||
|
|
||||||
import nextcord
|
import nextcord
|
||||||
from DakinySettings import settings
|
from dakiny_bot.dakiny_settings import settings
|
||||||
from database_setup.sql_data_classes import CouncilMembers, engine
|
from dakiny_bot.database.sql_data_classes import CouncilMembers, engine
|
||||||
|
from dakiny_bot.utils import NOMINEE_SPLITTER, decorate_nomination, get_election_name
|
||||||
from nextcord.interactions import Interaction
|
from nextcord.interactions import Interaction
|
||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from utils import NOMINEE_SPLITTER, decorate_nomination, get_election_name
|
|
||||||
|
|
||||||
|
|
||||||
class NominateModal(nextcord.ui.Modal):
|
class NominateModal(nextcord.ui.Modal):
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
# Extend the `pyproject.toml` file in the parent directory...
|
# Extend the `pyproject.toml` file in the parent directory...
|
||||||
extend = "../pyproject.toml"
|
extend = "../../pyproject.toml"
|
||||||
|
|
||||||
# Exclude a variety of commonly ignored directories.
|
# Exclude a variety of commonly ignored directories.
|
||||||
exclude = ["gitea_webhook.py"]
|
exclude = ["gitea_webhook.py"]
|
||||||
+3
-3
@@ -1,18 +1,18 @@
|
|||||||
"""Contains various views to be used while voting for high council. Controls the logic when performing the vote."""
|
"""Contains various views to be used while voting for high council. Controls the logic when performing the vote."""
|
||||||
|
|
||||||
import nextcord
|
import nextcord
|
||||||
from DakinySettings import settings
|
from dakiny_bot.dakiny_settings import settings
|
||||||
from database_setup.sql_data_classes import (
|
from dakiny_bot.database.sql_data_classes import (
|
||||||
CouncilMembers,
|
CouncilMembers,
|
||||||
ElectionInformation,
|
ElectionInformation,
|
||||||
Votes,
|
Votes,
|
||||||
engine,
|
engine,
|
||||||
)
|
)
|
||||||
|
from dakiny_bot.utils import VoteType, build_highcouncil_votes_str, get_election_name
|
||||||
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, update
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from utils import VoteType, build_highcouncil_votes_str, get_election_name
|
|
||||||
|
|
||||||
|
|
||||||
class VoteSelect(nextcord.ui.StringSelect):
|
class VoteSelect(nextcord.ui.StringSelect):
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
"""Contains various views to be used while voting. Controls the logic when performing the vote."""
|
"""Contains various views to be used while voting. Controls the logic when performing the vote."""
|
||||||
|
|
||||||
import nextcord
|
import nextcord
|
||||||
from DakinySettings import settings
|
from dakiny_bot.dakiny_settings import settings
|
||||||
from database_setup.sql_data_classes import (
|
from dakiny_bot.database.sql_data_classes import (
|
||||||
CouncilMembers,
|
CouncilMembers,
|
||||||
ElectionInformation,
|
ElectionInformation,
|
||||||
Votes,
|
Votes,
|
||||||
engine,
|
engine,
|
||||||
)
|
)
|
||||||
|
from dakiny_bot.utils import VoteType, build_votes_str, get_election_name
|
||||||
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, update
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from utils import VoteType, build_votes_str, get_election_name
|
|
||||||
|
|
||||||
|
|
||||||
class VoteSelect(nextcord.ui.StringSelect):
|
class VoteSelect(nextcord.ui.StringSelect):
|
||||||
@@ -66,7 +66,7 @@ class VoteSelect(nextcord.ui.StringSelect):
|
|||||||
session.execute(stmt)
|
session.execute(stmt)
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
vote_message_str = build_votes_str(settings, interaction.guild)
|
vote_message_str = build_votes_str(interaction.guild)
|
||||||
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)
|
await vote_msg.edit(content=vote_message_str)
|
||||||
|
|
||||||
@@ -8,9 +8,9 @@ from fastapi import FastAPI
|
|||||||
from git import Repo
|
from git import Repo
|
||||||
from nextcord.ext import commands
|
from nextcord.ext import commands
|
||||||
|
|
||||||
from classes.gitea_webhook import GiteaWebhook
|
from dakiny_bot.classes.gitea_webhook import GiteaWebhook
|
||||||
from DakinySettings import settings
|
from dakiny_bot.dakiny_settings import settings
|
||||||
from utils import REPO_DIR, edit_clan_council_info, update_clan_messages
|
from dakiny_bot.utils import REPO_DIR, edit_clan_council_info, update_clan_messages
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
import nextcord
|
import nextcord
|
||||||
@@ -2,15 +2,15 @@
|
|||||||
|
|
||||||
from nextcord.ext import commands
|
from nextcord.ext import commands
|
||||||
|
|
||||||
from cogs.commands.record import RecordCog
|
from dakiny_bot.cogs.commands.record import RecordCog
|
||||||
from cogs.commands.refresh import RefreshCog
|
from dakiny_bot.cogs.commands.refresh import RefreshCog
|
||||||
from cogs.commands.remove import RemoveCog
|
from dakiny_bot.cogs.commands.remove import RemoveCog
|
||||||
from cogs.commands.request import RequestCog
|
from dakiny_bot.cogs.commands.request import RequestCog
|
||||||
from cogs.commands.set import SetCog
|
from dakiny_bot.cogs.commands.set import SetCog
|
||||||
from cogs.commands.settings import SettingsCog
|
from dakiny_bot.cogs.commands.settings import SettingsCog
|
||||||
from cogs.commands.test import TestCog
|
from dakiny_bot.cogs.commands.test import TestCog
|
||||||
from cogs.commands.time import TimeCog
|
from dakiny_bot.cogs.commands.time import TimeCog
|
||||||
from cogs.commands.view import ViewCog
|
from dakiny_bot.cogs.commands.view import ViewCog
|
||||||
|
|
||||||
|
|
||||||
# This function will be called when this extension is loaded.
|
# This function will be called when this extension is loaded.
|
||||||
@@ -4,8 +4,8 @@ import nextcord
|
|||||||
from discord import TextInputStyle
|
from discord import TextInputStyle
|
||||||
from nextcord.ext import commands
|
from nextcord.ext import commands
|
||||||
|
|
||||||
from DakinySettings import settings
|
from dakiny_bot.dakiny_settings import settings
|
||||||
from utils import GUILDS, MAX_DISCORD_MESSAGE_LENGTH, PointType, record_points
|
from dakiny_bot.utils import GUILDS, MAX_DISCORD_MESSAGE_LENGTH, PointType, record_points
|
||||||
|
|
||||||
|
|
||||||
class RecordCog(commands.Cog, name="Record Commands"):
|
class RecordCog(commands.Cog, name="Record Commands"):
|
||||||
@@ -6,7 +6,7 @@ from pathlib import Path
|
|||||||
import nextcord
|
import nextcord
|
||||||
from nextcord.ext import commands
|
from nextcord.ext import commands
|
||||||
|
|
||||||
from utils import MESSAGES_DIR, edit_clan_council_info, update_clan_messages
|
from dakiny_bot.utils import MESSAGES_DIR, edit_clan_council_info, update_clan_messages
|
||||||
|
|
||||||
|
|
||||||
class RefreshCog(commands.Cog, name="Refresh Commands"):
|
class RefreshCog(commands.Cog, name="Refresh Commands"):
|
||||||
@@ -5,7 +5,7 @@ from nextcord.ext import commands
|
|||||||
from sqlalchemy import delete, select
|
from sqlalchemy import delete, select
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from database_setup.sql_data_classes import Presences, engine
|
from dakiny_bot.database.sql_data_classes import Presences, engine
|
||||||
|
|
||||||
|
|
||||||
class RemoveCog(commands.Cog, name="Remove Commands"):
|
class RemoveCog(commands.Cog, name="Remove Commands"):
|
||||||
@@ -54,14 +54,14 @@ class RemoveCog(commands.Cog, name="Remove Commands"):
|
|||||||
"""
|
"""
|
||||||
with Session(engine) as session:
|
with Session(engine) as session:
|
||||||
stmt = select(Presences)
|
stmt = select(Presences)
|
||||||
presences_dict: dict[str,str] = {pres.Presence: str(pres.Id) for pres in session.scalars(stmt)}
|
presences_dict: dict[str, str] = {pres.Presence: str(pres.Id) for pres in session.scalars(stmt)}
|
||||||
|
|
||||||
# if empty compare string
|
# if empty compare string
|
||||||
if not presence_str:
|
if not presence_str:
|
||||||
await interaction.response.send_autocomplete(dict(list(presences_dict.items())[:25]))
|
await interaction.response.send_autocomplete(dict(list(presences_dict.items())[:25]))
|
||||||
return
|
return
|
||||||
|
|
||||||
autofilled_presences: dict[str,str] = {
|
autofilled_presences: dict[str, str] = {
|
||||||
pres: pres_id for pres, pres_id in presences_dict.items() if presence_str.lower() in pres.lower()
|
pres: pres_id for pres, pres_id in presences_dict.items() if presence_str.lower() in pres.lower()
|
||||||
}
|
}
|
||||||
await interaction.response.send_autocomplete(autofilled_presences[:25])
|
await interaction.response.send_autocomplete(autofilled_presences[:25])
|
||||||
@@ -4,8 +4,8 @@ import nextcord
|
|||||||
from nextcord.ext import commands
|
from nextcord.ext import commands
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from DakinySettings import settings
|
from dakiny_bot.dakiny_settings import settings
|
||||||
from database_setup.sql_data_classes import Presences, engine
|
from dakiny_bot.database.sql_data_classes import Presences, engine
|
||||||
|
|
||||||
|
|
||||||
class RequestCog(commands.Cog, name="Request Commands"):
|
class RequestCog(commands.Cog, name="Request Commands"):
|
||||||
@@ -8,8 +8,8 @@ from sqlalchemy import delete, select
|
|||||||
from sqlalchemy.exc import IntegrityError
|
from sqlalchemy.exc import IntegrityError
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from database_setup.sql_data_classes import UserBirthday, engine
|
from dakiny_bot.app import birthday_list
|
||||||
from main import birthday_list
|
from dakiny_bot.database.sql_data_classes import UserBirthday, engine
|
||||||
|
|
||||||
|
|
||||||
class SetCog(commands.Cog, name="Set Commands"):
|
class SetCog(commands.Cog, name="Set Commands"):
|
||||||
@@ -3,8 +3,8 @@
|
|||||||
import nextcord
|
import nextcord
|
||||||
from nextcord.ext import commands
|
from nextcord.ext import commands
|
||||||
|
|
||||||
from DakinySettings import settings
|
from dakiny_bot.dakiny_settings import settings
|
||||||
from utils import GUILDS
|
from dakiny_bot.utils import GUILDS
|
||||||
|
|
||||||
|
|
||||||
class SettingsCog(commands.Cog, name="Settings Commands"):
|
class SettingsCog(commands.Cog, name="Settings Commands"):
|
||||||
@@ -3,9 +3,9 @@
|
|||||||
import nextcord
|
import nextcord
|
||||||
from nextcord.ext import application_checks, commands
|
from nextcord.ext import application_checks, commands
|
||||||
|
|
||||||
from classes.election import Election
|
from dakiny_bot.classes.election import Election
|
||||||
from DakinySettings import settings
|
from dakiny_bot.dakiny_settings import settings
|
||||||
from utils import GUILDS, get_active_election_cycle, get_quarter_name
|
from dakiny_bot.utils import GUILDS, get_active_election_cycle, get_quarter_name
|
||||||
|
|
||||||
ME = 206602713511886849
|
ME = 206602713511886849
|
||||||
|
|
||||||
@@ -5,7 +5,7 @@ from datetime import MAXYEAR, MINYEAR, UTC, datetime
|
|||||||
import nextcord
|
import nextcord
|
||||||
from nextcord.ext import commands
|
from nextcord.ext import commands
|
||||||
|
|
||||||
from utils import GUILDS
|
from dakiny_bot.utils import GUILDS
|
||||||
|
|
||||||
|
|
||||||
class TimeCog(commands.Cog, name="Time Commands"):
|
class TimeCog(commands.Cog, name="Time Commands"):
|
||||||
@@ -6,13 +6,13 @@ 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 dakiny_bot.database.sql_data_classes import (
|
||||||
Points,
|
Points,
|
||||||
Presences,
|
Presences,
|
||||||
Votes,
|
Votes,
|
||||||
engine,
|
engine,
|
||||||
)
|
)
|
||||||
from utils import GUILDS, MAX_DISCORD_MESSAGE_LENGTH, PointType, VoteType
|
from dakiny_bot.utils import GUILDS, MAX_DISCORD_MESSAGE_LENGTH, PointType, VoteType
|
||||||
|
|
||||||
|
|
||||||
class ViewCog(commands.Cog, name="View Commands"):
|
class ViewCog(commands.Cog, name="View Commands"):
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
from nextcord.ext import commands
|
from nextcord.ext import commands
|
||||||
|
|
||||||
from cogs.loops.bot_presence import BotPresence
|
from dakiny_bot.cogs.loops.bot_presence import BotPresence
|
||||||
from cogs.loops.daily_loop import DailyLoop
|
from dakiny_bot.cogs.loops.daily_loop import DailyLoop
|
||||||
|
|
||||||
|
|
||||||
def setup(bot: commands.Bot) -> None:
|
def setup(bot: commands.Bot) -> None:
|
||||||
@@ -5,7 +5,7 @@ from nextcord.ext import commands, tasks
|
|||||||
from sqlalchemy import func, select
|
from sqlalchemy import func, select
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from database_setup.sql_data_classes import Presences, engine
|
from dakiny_bot.database.sql_data_classes import Presences, engine
|
||||||
|
|
||||||
|
|
||||||
class BotPresence(commands.Cog, name="Bot Presence"):
|
class BotPresence(commands.Cog, name="Bot Presence"):
|
||||||
@@ -9,17 +9,19 @@ from pytz import timezone
|
|||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from classes.election import Election
|
from dakiny_bot.app import birthday_list
|
||||||
from DakinySettings import settings
|
from dakiny_bot.classes.election import Election
|
||||||
from database_setup.sql_data_classes import UserBirthday, engine
|
from dakiny_bot.dakiny_settings import settings
|
||||||
from main import birthday_list
|
from dakiny_bot.database.sql_data_classes import UserBirthday, engine
|
||||||
from utils import get_active_election_cycle
|
from dakiny_bot.utils import get_active_election_cycle
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
import nextcord
|
import nextcord
|
||||||
|
|
||||||
KANDY = 239547993106284544
|
KANDY = 239547993106284544
|
||||||
|
|
||||||
|
IGNORE_CAKEDAY = [266378407682506754]
|
||||||
|
|
||||||
|
|
||||||
class DailyLoop(commands.Cog, name="Daily Loop"):
|
class DailyLoop(commands.Cog, name="Daily Loop"):
|
||||||
"""Class for performing daily functions."""
|
"""Class for performing daily functions."""
|
||||||
@@ -112,7 +114,11 @@ class DailyLoop(commands.Cog, name="Daily Loop"):
|
|||||||
announce_channel: nextcord.TextChannel = guild.get_channel(settings.channel_ids.general)
|
announce_channel: nextcord.TextChannel = guild.get_channel(settings.channel_ids.general)
|
||||||
|
|
||||||
cakedays: list[nextcord.Member] = [
|
cakedays: list[nextcord.Member] = [
|
||||||
human for human in guild.humans if human.joined_at.month == today.month and human.joined_at.day == today.day
|
human
|
||||||
|
for human in guild.humans
|
||||||
|
if human.joined_at.month == today.month
|
||||||
|
and human.joined_at.day == today.day
|
||||||
|
and human.id not in IGNORE_CAKEDAY
|
||||||
]
|
]
|
||||||
|
|
||||||
for member in cakedays:
|
for member in cakedays:
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
import nextcord
|
import nextcord
|
||||||
from nextcord.ext import commands
|
from nextcord.ext import commands
|
||||||
|
|
||||||
from main import birthday_list
|
from dakiny_bot.app import birthday_list
|
||||||
|
|
||||||
|
|
||||||
class SubmissionListener(commands.Cog, name="Message Listener"):
|
class SubmissionListener(commands.Cog, name="Message Listener"):
|
||||||
@@ -83,4 +83,4 @@ class DakinySettings(YAMLWizard):
|
|||||||
self.to_yaml_file(CONFIG_LOCATION)
|
self.to_yaml_file(CONFIG_LOCATION)
|
||||||
|
|
||||||
|
|
||||||
settings = DakinySettings.from_yaml_file(CONFIG_LOCATION)
|
settings: DakinySettings | None = None
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
"""Module controls connection to Dakiny bot database."""
|
||||||
@@ -7,7 +7,7 @@ if not Path("database/dakiny.db").exists():
|
|||||||
with sqlite3.connect("database/dakiny.db") as con:
|
with sqlite3.connect("database/dakiny.db") as con:
|
||||||
cur = con.cursor()
|
cur = con.cursor()
|
||||||
|
|
||||||
with Path("database_setup/database.sql", encoding="utf-8").open() as file:
|
with Path("dakiny_bot/database/database.sql").open() as file:
|
||||||
database_script = file.read()
|
database_script = file.read()
|
||||||
cur.executescript(database_script)
|
cur.executescript(database_script)
|
||||||
con.commit()
|
con.commit()
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
"""Broken out util functions to avoid importing sql during testing."""
|
||||||
|
|
||||||
|
import calendar
|
||||||
|
from datetime import UTC, datetime
|
||||||
|
|
||||||
|
from dakiny_bot.dakiny_settings import settings
|
||||||
|
|
||||||
|
|
||||||
|
def get_datetime(month_day: str) -> datetime:
|
||||||
|
"""
|
||||||
|
Takes in a string month and day and returns a datetime object of that Month/Day this year.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
month_day (str): Month/Day in that format.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
datetime: Datetime representation of Month/Day.
|
||||||
|
"""
|
||||||
|
today = datetime.now(tz=UTC).date()
|
||||||
|
year = today.year
|
||||||
|
month = int(month_day.split("/")[0])
|
||||||
|
day = int(month_day.split("/")[1])
|
||||||
|
|
||||||
|
# ensure that year rolls over if current month is December and the next month is less than 12.
|
||||||
|
if today.month == calendar.DECEMBER and month < calendar.OCTOBER:
|
||||||
|
year += 1
|
||||||
|
|
||||||
|
if today.month == calendar.JANUARY and month > calendar.MARCH:
|
||||||
|
year -= 1
|
||||||
|
|
||||||
|
return datetime(year, month, day, tzinfo=UTC)
|
||||||
|
|
||||||
|
|
||||||
|
def get_quarter_cycle() -> int | None:
|
||||||
|
"""
|
||||||
|
Returns the index for the current cycle/quarter. Defined as between term start and end.
|
||||||
|
|
||||||
|
Can return None if entire year isn't covered by cycles.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: cycle index for current cycle.
|
||||||
|
"""
|
||||||
|
today = datetime.now(tz=UTC)
|
||||||
|
for cycle, election in enumerate(settings.election_cycles):
|
||||||
|
if (
|
||||||
|
today.date() >= get_datetime(election.term_start).date()
|
||||||
|
and today.date() <= get_datetime(election.term_end).date()
|
||||||
|
):
|
||||||
|
return cycle
|
||||||
|
|
||||||
|
return None
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
"""Empty init for testing util functions."""
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
"""Empty init for testing util functions."""
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
"""Tests for get_datetime function."""
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
from freezegun import freeze_time
|
||||||
|
|
||||||
|
from dakiny_bot.election_utils import get_datetime
|
||||||
|
|
||||||
|
|
||||||
|
@freeze_time("2025-6-16")
|
||||||
|
def test_regular_get_datetime() -> None:
|
||||||
|
"""
|
||||||
|
Test a regular get_datetime.
|
||||||
|
|
||||||
|
Expect the returned datetime to be the frozen date.
|
||||||
|
Have two different days to ensure that the date is being returned correctly.
|
||||||
|
"""
|
||||||
|
date_time = get_datetime("6/15")
|
||||||
|
assert date_time == datetime.datetime(2025, 6, 15, tzinfo=datetime.UTC)
|
||||||
|
|
||||||
|
|
||||||
|
@freeze_time("2025-1-16")
|
||||||
|
def test_jan_get_datetime() -> None:
|
||||||
|
"""
|
||||||
|
Test previous year get_datetime.
|
||||||
|
|
||||||
|
Frozen day is in January 2025, datetime string is in December. Expect datetime to be from 2024.
|
||||||
|
"""
|
||||||
|
date_time = get_datetime("12/15")
|
||||||
|
assert date_time == datetime.datetime(2024, 12, 15, tzinfo=datetime.UTC)
|
||||||
|
|
||||||
|
|
||||||
|
@freeze_time("2025-12-16")
|
||||||
|
def test_dec_get_datetime() -> None:
|
||||||
|
"""
|
||||||
|
Test next year get_datetime.
|
||||||
|
|
||||||
|
Frozen day is in December 2025, datetime string is in January. Expect datetime to be from 2026.
|
||||||
|
"""
|
||||||
|
date_time = get_datetime("1/15")
|
||||||
|
assert date_time == datetime.datetime(2026, 1, 15, tzinfo=datetime.UTC)
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
"""Test functions for get_quarter_cycle."""
|
||||||
|
|
||||||
|
from unittest.mock import mock_open, patch
|
||||||
|
|
||||||
|
from freezegun import freeze_time
|
||||||
|
|
||||||
|
from dakiny_bot.dakiny_settings import ChannelIds, DakinySettings, Election, Params, PointSettings, RoleIds
|
||||||
|
from dakiny_bot.election_utils import get_quarter_cycle
|
||||||
|
|
||||||
|
# I only care about term start and term end for this test
|
||||||
|
q1 = Election(True, "", "", "", "", "q1", "4/30", "2/1", "", "") # noqa: FBT003
|
||||||
|
q2 = Election(True, "", "", "", "", "q2", "7/31", "5/1", "", "") # noqa: FBT003
|
||||||
|
q3 = Election(True, "", "", "", "", "q3", "10/31", "8/1", "", "") # noqa: FBT003
|
||||||
|
q4 = Election(True, "", "", "", "", "q4", "1/31", "11/1", "", "") # noqa: FBT003
|
||||||
|
|
||||||
|
# Dummy all the values I don't care about.
|
||||||
|
settings = DakinySettings(
|
||||||
|
ChannelIds(1, 1, 1, 1, 1, 1),
|
||||||
|
[q1, q2, q3, q4],
|
||||||
|
Params("", "", 1),
|
||||||
|
PointSettings(1, 1, 1, 1, 1, True, True), # noqa: FBT003
|
||||||
|
RoleIds(1, 1, 1, 1, 1),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@patch("election_utils.get_quarter_cycle.settings", settings)
|
||||||
|
@patch("builtins.open", new_callable=mock_open)
|
||||||
|
class TestGetQuarterCycle:
|
||||||
|
@freeze_time("2025-2-25")
|
||||||
|
def test_regular_q1(self) -> None:
|
||||||
|
assert get_quarter_cycle() == 0
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
"""File contains util functions."""
|
"""File contains util functions."""
|
||||||
|
|
||||||
import calendar
|
|
||||||
import os
|
import os
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
from datetime import UTC, datetime
|
from datetime import UTC, datetime
|
||||||
@@ -12,8 +11,7 @@ import nextcord
|
|||||||
from sqlalchemy import select, true, update
|
from sqlalchemy import select, true, update
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from DakinySettings import settings
|
from dakiny_bot.database.sql_data_classes import (
|
||||||
from database_setup.sql_data_classes import (
|
|
||||||
CouncilMembers,
|
CouncilMembers,
|
||||||
Messages,
|
Messages,
|
||||||
Points,
|
Points,
|
||||||
@@ -22,6 +20,9 @@ from database_setup.sql_data_classes import (
|
|||||||
engine,
|
engine,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from .dakiny_settings import settings
|
||||||
|
from .election_utils import get_datetime, get_quarter_cycle
|
||||||
|
|
||||||
NOMINEE_SPLITTER = "========================================\n\n"
|
NOMINEE_SPLITTER = "========================================\n\n"
|
||||||
REPO_DIR = "./dakiny-messages"
|
REPO_DIR = "./dakiny-messages"
|
||||||
MESSAGES_DIR = f"{REPO_DIR}/messages"
|
MESSAGES_DIR = f"{REPO_DIR}/messages"
|
||||||
@@ -33,31 +34,6 @@ VoteType = StrEnum("VoteType", ["COUNCIL", "DISCORDMANAGER", "CLANLEADER"])
|
|||||||
PointType = StrEnum("PointType", ["CLAN", "EVENT"])
|
PointType = StrEnum("PointType", ["CLAN", "EVENT"])
|
||||||
|
|
||||||
|
|
||||||
def get_datetime(day: str) -> datetime:
|
|
||||||
"""
|
|
||||||
Takes in a string month and day and returns a datetime object of that Month/Day this year.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
day (str): Month/Day in that format.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
datetime: Datetime representation of Month/Day.
|
|
||||||
"""
|
|
||||||
today = datetime.now(tz=UTC).date()
|
|
||||||
year = today.year
|
|
||||||
month = int(day.split("/")[0])
|
|
||||||
day = int(day.split("/")[1])
|
|
||||||
|
|
||||||
# ensure that year rolls over if current month is December and the next month is less than 12.
|
|
||||||
if today.month == calendar.DECEMBER and month < calendar.OCTOBER:
|
|
||||||
year += 1
|
|
||||||
|
|
||||||
if today.month == calendar.JANUARY and month > calendar.MARCH:
|
|
||||||
year -= 1
|
|
||||||
|
|
||||||
return datetime(year, month, day, tzinfo=UTC)
|
|
||||||
|
|
||||||
|
|
||||||
def get_election_name() -> str:
|
def get_election_name() -> str:
|
||||||
"""
|
"""
|
||||||
Builds the unique name of the current election cycle.
|
Builds the unique name of the current election cycle.
|
||||||
@@ -65,7 +41,10 @@ def get_election_name() -> str:
|
|||||||
Returns:
|
Returns:
|
||||||
str: the name of the election cycle
|
str: the name of the election cycle
|
||||||
"""
|
"""
|
||||||
cycle = get_active_election_cycle()
|
if cycle := get_active_election_cycle() is None:
|
||||||
|
# undefined behavior
|
||||||
|
print("Did not find an active election cycle. Undefined behavior with return string.") # noqa: T201
|
||||||
|
return "No-active-election-cycle"
|
||||||
current_cycle = settings.election_cycles[cycle]
|
current_cycle = settings.election_cycles[cycle]
|
||||||
return f"vote-{get_datetime(current_cycle.term_start).year}-{current_cycle.name}"
|
return f"vote-{get_datetime(current_cycle.term_start).year}-{current_cycle.name}"
|
||||||
|
|
||||||
@@ -77,13 +56,16 @@ def get_quarter_name() -> str:
|
|||||||
Returns:
|
Returns:
|
||||||
str: the name of the cycle.
|
str: the name of the cycle.
|
||||||
"""
|
"""
|
||||||
cycle = get_quarter_cycle()
|
if cycle := get_quarter_cycle() is None:
|
||||||
|
# undefined behavior
|
||||||
|
print("Did not find a quarter cycle. Undefined behavior with return string.") # noqa: T201
|
||||||
|
return "no-quarter-cycle"
|
||||||
current_cycle = settings.election_cycles[cycle]
|
current_cycle = settings.election_cycles[cycle]
|
||||||
|
|
||||||
return f"{get_datetime(current_cycle.term_start).year}-{current_cycle.name}"
|
return f"{get_datetime(current_cycle.term_start).year}-{current_cycle.name}"
|
||||||
|
|
||||||
|
|
||||||
def get_active_election_cycle() -> int:
|
def get_active_election_cycle() -> int | None:
|
||||||
"""
|
"""
|
||||||
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.
|
||||||
|
|
||||||
@@ -103,26 +85,6 @@ def get_active_election_cycle() -> int:
|
|||||||
return get_quarter_cycle()
|
return get_quarter_cycle()
|
||||||
|
|
||||||
|
|
||||||
def get_quarter_cycle() -> int:
|
|
||||||
"""
|
|
||||||
Returns the index for the current cycle/quarter. Defined as between term start and end.
|
|
||||||
|
|
||||||
Can return None if entire year isn't covered by cycles.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
int: cycle index for current cycle.
|
|
||||||
"""
|
|
||||||
today = datetime.now(tz=UTC)
|
|
||||||
for cycle, election in enumerate(settings.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(guild: nextcord.Guild) -> str:
|
def build_votes_str(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.
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
[tool.ruff]
|
|
||||||
# Extend the `pyproject.toml` file in the parent directory...
|
|
||||||
extend = "../pyproject.toml"
|
|
||||||
|
|
||||||
[tool.ruff.lint]
|
|
||||||
# ignore implicit-namespace-package in this directory.
|
|
||||||
ignore = ["INP001"]
|
|
||||||
+10
-2
@@ -6,7 +6,7 @@ dependencies = [
|
|||||||
"fastapi<1.0.0,>=0.111.0",
|
"fastapi<1.0.0,>=0.111.0",
|
||||||
"nextcord<3.0.0,>=2.6.0",
|
"nextcord<3.0.0,>=2.6.0",
|
||||||
"pandas<3.0.0,>=2.2.2",
|
"pandas<3.0.0,>=2.2.2",
|
||||||
"pytz<2025.0,>=2024.1",
|
"pytz<2025.3,>=2025.2",
|
||||||
"sqlalchemy<3.0.0,>=2.0.30",
|
"sqlalchemy<3.0.0,>=2.0.30",
|
||||||
"aiofiles<24.0.0,>=23.2.1",
|
"aiofiles<24.0.0,>=23.2.1",
|
||||||
"setuptools<71.0.0,>=70.0.0",
|
"setuptools<71.0.0,>=70.0.0",
|
||||||
@@ -19,7 +19,12 @@ description = "Dakiny's Discord Bot."
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
dev = ["ruff<1.0.0,>=0.6.9"]
|
dev = [
|
||||||
|
"freezegun>=1.5.1",
|
||||||
|
"pytest>=8.3.5",
|
||||||
|
"pytest-cov>=6.1.1",
|
||||||
|
"ruff<1.0.0,>=0.6.9",
|
||||||
|
]
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
# Exclude a variety of commonly ignored directories.
|
# Exclude a variety of commonly ignored directories.
|
||||||
@@ -126,3 +131,6 @@ docstring-code-format = true
|
|||||||
# This only has an effect when the `docstring-code-format` setting is
|
# This only has an effect when the `docstring-code-format` setting is
|
||||||
# enabled.
|
# enabled.
|
||||||
docstring-code-line-length = "dynamic"
|
docstring-code-line-length = "dynamic"
|
||||||
|
|
||||||
|
[tool.ruff.lint.per-file-ignores]
|
||||||
|
"**/{tests}/*" = ["ANN001", "ANN201", "S101", "PLR2004"]
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
|
"lockFileMaintenance": {
|
||||||
|
"automerge": true,
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
"minor": {
|
||||||
|
"automerge": true,
|
||||||
|
"automergeType": "branch"
|
||||||
|
},
|
||||||
|
"patch": {
|
||||||
|
"automerge": true,
|
||||||
|
"automergeType": "branch"
|
||||||
|
},
|
||||||
|
"pin": {
|
||||||
|
"automerge": true,
|
||||||
|
"automergeType": "branch"
|
||||||
|
},
|
||||||
|
"ignoreTests": true
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
version = 1
|
version = 1
|
||||||
|
revision = 1
|
||||||
requires-python = ">=3.12, <4.0"
|
requires-python = ">=3.12, <4.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -161,7 +162,7 @@ requires-dist = [
|
|||||||
{ name = "gitpython", specifier = ">=3.1.43,<4.0.0" },
|
{ name = "gitpython", specifier = ">=3.1.43,<4.0.0" },
|
||||||
{ name = "nextcord", specifier = ">=2.6.0,<3.0.0" },
|
{ name = "nextcord", specifier = ">=2.6.0,<3.0.0" },
|
||||||
{ name = "pandas", specifier = ">=2.2.2,<3.0.0" },
|
{ name = "pandas", specifier = ">=2.2.2,<3.0.0" },
|
||||||
{ name = "pytz", specifier = ">=2024.1,<2025.0" },
|
{ name = "pytz", specifier = ">=2025.2,<2025.3" },
|
||||||
{ name = "setuptools", specifier = ">=70.0.0,<71.0.0" },
|
{ name = "setuptools", specifier = ">=70.0.0,<71.0.0" },
|
||||||
{ name = "sqlalchemy", specifier = ">=2.0.30,<3.0.0" },
|
{ name = "sqlalchemy", specifier = ">=2.0.30,<3.0.0" },
|
||||||
{ name = "uvicorn", specifier = ">=0.34.0" },
|
{ name = "uvicorn", specifier = ">=0.34.0" },
|
||||||
@@ -544,11 +545,11 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pytz"
|
name = "pytz"
|
||||||
version = "2024.2"
|
version = "2025.2"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/3a/31/3c70bf7603cc2dca0f19bdc53b4537a797747a58875b552c8c413d963a3f/pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a", size = 319692 }
|
sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884 }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/11/c3/005fcca25ce078d2cc29fd559379817424e94885510568bc1bc53d7d5846/pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725", size = 508002 },
|
{ url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
Reference in New Issue
Block a user