Compare commits

...
Author SHA1 Message Date
imcompiling 5668e4be7e Add release workflow.
build_release / build (push) Successful in 44s
build_develop / build (push) Successful in 43s
build_latest / build (push) Successful in 44s
2023-09-09 11:49:56 -04:00
imcompiling 43c1a5c6cd Merge branch '22-daily-loop-not-starting-election'
build_develop / build (push) Successful in 43s
build_latest / build (push) Successful in 42s
2023-09-09 11:39:31 -04:00
imcompiling c278bae498 I forgot to give the docker image the message files.
build_develop / build (push) Successful in 1m24s
2023-09-09 11:38:22 -04:00
imcompiling 8b831fb6aa start loop in init, use before loop, waiting on bot ready, to set up needed data. 2023-09-09 11:38:03 -04:00
imcompiling e7cfe8bd4c Fix logging issue.
build_develop / build (push) Successful in 1m24s
2023-09-08 20:07:08 -04:00
imcompiling 2640ebdad1 Move current_election setting. The bot needs to be ready first.
build_develop / build (push) Successful in 1m22s
2023-09-08 11:42:34 -04:00
imcompiling c5c242de21 Correct comparison in get_current_cycle().
build_develop / build (push) Successful in 1m30s
build_latest / build (push) Successful in 47s
2023-09-06 14:14:33 -04:00
imcompiling 369ea0dd55 Add logging 2023-09-03 21:12:42 -04:00
imcompiling 25833364d7 Whoops, period on wrong side of bracket.
build_latest / build (push) Successful in 42s
build_develop / build (push) Successful in 44s
2023-08-26 22:15:12 -04:00
imcompiling d73b671257 Copy utils.py into docker image. sort copying.
build_develop / build (push) Successful in 1m25s
build_latest / build (push) Successful in 44s
2023-08-26 21:39:07 -04:00
imcompiling f6e827fba5 Rename a directory, need to store the db file in a directory. 2023-08-26 21:36:18 -04:00
imcompiling 2991f81e04 Update python version.
build_develop / build (push) Successful in 2m4s
build_latest / build (push) Successful in 42s
2023-08-26 21:02:22 -04:00
imcompiling b1c0b7013d Update dockerfile to include database.
build_develop / build (push) Successful in 1m45s
build_latest / build (push) Successful in 42s
2023-08-26 20:52:31 -04:00
imcompiling 22ea29e8ea Merge branch '10-name-change-request'
build_develop / build (push) Successful in 42s
build_latest / build (push) Successful in 42s
2023-07-29 21:13:59 -04:00
imcompiling 8c20641041 Added doc strings for the approve and deny buttons.
build_develop / build (push) Successful in 1m24s
2023-07-29 21:13:14 -04:00
imcompiling fa3fc6bd75 Added logic to handle bot being unable to change a nickname due to role hierarchy. 2023-07-29 21:08:16 -04:00
imcompiling 271cf14697 Need to be able to manage nicknames. 2023-07-29 19:21:11 -04:00
imcompiling ee2aaba421 Must await the edit. 2023-07-29 19:16:59 -04:00
imcompiling 6ae722beb9 Need member intent. 2023-07-29 19:16:47 -04:00
imcompiling 757a753cf5 I want to edit the message, not send a new one. 2023-07-29 19:05:52 -04:00
imcompiling b292fc09fe Log into gitea registry.
build_develop / build (push) Successful in 1m41s
2023-07-29 18:30:05 -04:00
imcompiling 7789e679ce Flush out view with approve and deny actions. 2023-07-29 18:18:31 -04:00
imcompiling 9cae7d002a Create initial command action. 2023-07-29 16:35:03 -04:00
imcompiling f71df0b7f4 Add the admin channel id to config. 2023-07-29 15:41:12 -04:00
imcompiling 2d2631bfac Create request class. 2023-07-29 15:39:53 -04:00
imcompiling f9d6227db1 Add the birthday table. 2023-07-29 15:16:23 -04:00
imcompiling c9946c9afe Merge branch '20-finish-daily-loop' 2023-07-26 16:27:01 -04:00
15 changed files with 196 additions and 26 deletions
+6
View File
@@ -12,6 +12,12 @@ jobs:
fetch-depth: 0
- name: Install Docker
uses: https://github.com/papodaca/install-docker-action@v1
- name: Log into container registry
uses: docker/login-action@v2
with:
registry: gitea.cheezers.org
username: imcompiling
password: ${{ secrets.PASSWORD }}
- name: Build Docker Image
run: docker build -t gitea.cheezers.org/imcompiling/dakiny-bot:develop .
- name: Push Docker Image
+6
View File
@@ -14,6 +14,12 @@ jobs:
fetch-depth: 0
- name: Install Docker
uses: https://github.com/papodaca/install-docker-action@v1
- name: Log into container registry
uses: docker/login-action@v2
with:
registry: gitea.cheezers.org
username: imcompiling
password: ${{ secrets.PASSWORD }}
- name: Build Docker Image
run: docker build -t gitea.cheezers.org/imcompiling/dakiny-bot:latest .
- name: Push Docker Image
+28
View File
@@ -0,0 +1,28 @@
name: build_release
on:
push:
tags: ["v[0-9].[0-9].[0-9]"]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Install Docker
uses: https://github.com/papodaca/install-docker-action@v1
- name: Log into container registry
uses: docker/login-action@v2
with:
registry: gitea.cheezers.org
username: imcompiling
password: ${{ secrets.PASSWORD }}
- name: Set env
run: echo "GIT_TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- name: Build Docker Image
run: docker build -t gitea.cheezers.org/imcompiling/dakiny-bot:${{env.GIT_TAG}} .
- name: Push Tagged Image
run: docker push gitea.cheezers.org/imcompiling/dakiny-bot:${{env.GIT_TAG}}
+1 -1
View File
@@ -139,4 +139,4 @@ TODO.txt
sql_tester.py
conf
outputs
dakiny.db
database
+8 -3
View File
@@ -1,4 +1,4 @@
FROM python:3.8.10-slim
FROM python:3.10.6-slim
# install dependencies for mysqlclient
# RUN apt-get update && apt-get -y upgrade && apt-get -y install python3-dev default-libmysqlclient-dev build-essential
@@ -7,11 +7,16 @@ RUN pip install --upgrade pip
WORKDIR /home
COPY cogs cogs/
COPY dakiny_bot.py dakiny_bot.py
COPY requirements.txt requirements.txt
COPY config.py config.py
COPY dakiny_bot.py dakiny_bot.py
COPY utils.py utils.py
COPY bot_messages bot_messages/
COPY classes classes/
COPY cogs cogs/
COPY database_setup database_setup/
RUN pip install -r requirements.txt
+1 -1
View File
@@ -9,7 +9,7 @@ from sqlalchemy import select
from sqlalchemy.orm import Session
from config import DakinyConfig
from database.sql_data_classes import ElectionInformation, engine
from database_setup.sql_data_classes import ElectionInformation, engine
from utils import get_datetime
+2
View File
@@ -4,6 +4,7 @@ Cog loader. Adds all command cogs to the bot.
from nextcord.ext import commands
from cogs.commands.request import RequestCog
from cogs.commands.test import TestCog
@@ -13,4 +14,5 @@ def setup(bot: commands.Bot):
"""
Adds all command classes to bot.
"""
bot.add_cog(RequestCog(bot))
bot.add_cog(TestCog(bot))
+103
View File
@@ -0,0 +1,103 @@
"""
Contains commands and views for request commands.
"""
import nextcord
from nextcord.ext import commands
from config import DakinyConfig
class RequestCog(commands.Cog, name="Request Commands"):
"""
Class holds request commands.
"""
def __init__(self, bot) -> None:
"""
Default constructor for RequestCog class. Does nothing.
"""
self.bot: commands.Bot = bot
@nextcord.slash_command()
async def request(self, interaction: nextcord.Interaction):
"""
Parent slash command for help. Never called.
"""
@request.subcommand(description="Request to change your Dakiny nickname")
async def change_nickname(
self,
interaction: nextcord.Interaction,
new_nickname: str = nextcord.SlashOption(
required=True, min_length=2, max_length=32, description="Your requested new nickname."
),
):
"""
Sends a message to admins to request a nickname change.
Args:
interaction (nextcord.Interaction): Interaction that invoked the command.
new_username(str): The username to change to.
"""
config: DakinyConfig = self.bot.config
content = f'<@{interaction.user.id}> would like to change their username to "{new_nickname}."'
view = UsernameRequest(interaction.user.id, new_nickname)
await self.bot.get_channel(config.params.admin_channel_id).send(content=content, view=view)
await interaction.response.send_message("Request sent to admins.", ephemeral=True)
class UsernameRequest(nextcord.ui.View):
"""
View provides approve and deny buttons and action for a username change request.
"""
def __init__(self, user_id: int, new_nickname: str, *, timeout: float | None = 180, auto_defer: bool = True):
super().__init__(timeout=timeout, auto_defer=auto_defer)
self.user_id = user_id
self.new_nickname = new_nickname
@nextcord.ui.button(label="Approve", style=nextcord.ButtonStyle.green)
async def approve(self, button: nextcord.ui.Button, interaction: nextcord.Interaction):
"""
Approve button for a nickname change request. Changes the target's nickname to self.new_nickname.
Catches an error if the target as a higher role than the bot.
Removes the view from the interaction message.
Args:
button (nextcord.ui.Button): Unused.
interaction (nextcord.Interaction): The interaction of the user clicking the button.
"""
user = interaction.guild.get_member(self.user_id)
if user is not None:
try:
await user.edit(nick=self.new_nickname)
content = interaction.message.content + f"\nApproved by <@{interaction.user.id}>."
await interaction.response.edit_message(content=content, view=None)
except nextcord.errors.Forbidden:
await interaction.response.send_message(
content="Please change manually.",
ephemeral=True,
)
content = (
interaction.message.content
+ "\n\nFailed. User has too high permissions for bot to change nickname."
)
await interaction.followup.edit_message(interaction.message.id, content=content, view=None)
else:
await interaction.response.edit_message(
content="An error occured while changing the user's nickname.", view=None
)
@nextcord.ui.button(label="Deny", style=nextcord.ButtonStyle.red)
async def deny(self, button: nextcord.ui.Button, interaction: nextcord.Interaction):
"""
Deny button for a nickname request. Just removes the view and logs who denied the request.
Args:
button (nextcord.ui.Button): Unused.
interaction (nextcord.Interaction): The interaction of the user clicking the button.
"""
content = interaction.message.content + f"\nDenied by <@{interaction.user.id}>."
await interaction.response.edit_message(content=content, view=None)
+15 -10
View File
@@ -19,16 +19,10 @@ class DailyLoop(commands.Cog, name="Daily Loop"):
def __init__(self, bot: commands.Bot) -> None:
self.bot = bot
self.current_election = self.get_current_cycle()
self.current_election = None
@commands.Cog.listener()
async def on_ready(self):
"""
Starts the loop when bot is ready.
"""
await self.bot.wait_until_ready()
# pylint doesn't recognize that periodic_update_guild_data is subclassed from tasks.loop.
await self.daily_loop.start() # pylint: disable=no-member
# pylint doesn't recognize that daily_loop is subclassed from tasks.loop.
self.daily_loop.start() # pylint: disable=no-member
@tasks.loop(time=time(hour=0, tzinfo=timezone("GMT")))
async def daily_loop(self):
@@ -46,6 +40,17 @@ class DailyLoop(commands.Cog, name="Daily Loop"):
if self.current_election.election_over:
self.current_election = None
@daily_loop.before_loop
async def before_loop(self):
"""
Actions run before the loop starts. Want to wait for bot to be ready and get the current cycle.
"""
await self.bot.wait_until_ready()
# Bot needs to know guilds to get the current cycle.
self.current_election = self.get_current_cycle()
def get_current_cycle(self) -> ElectionCycle:
"""
Creates an object for the current election cycle if one is active. An election is considered active
@@ -61,7 +66,7 @@ class DailyLoop(commands.Cog, name="Daily Loop"):
for cycle, election in enumerate(config.election_cycles):
if (
today.date() > get_datetime(election.election_start).date()
today.date() >= get_datetime(election.election_start).date()
and today.date() < get_datetime(election.term_start).date()
):
current_election = ElectionCycle(cycle, config, self.bot.get_guild(config.params.guild_id))
+1
View File
@@ -11,6 +11,7 @@ class Params:
"""
active_category_id: int
admin_channel_id: int # might want to rename this...
annoucement_category_id: int
archive_channel_group_id: int
clan_council_elect_role_id: int
+12 -3
View File
@@ -1,3 +1,4 @@
import logging
import os
import sys
@@ -6,12 +7,18 @@ import nextcord
from hydra.core.config_store import ConfigStore
from nextcord.ext import commands
import database.create_database as create_database
import database_setup.create_database as create_database
from config import DakinyConfig
cs = ConfigStore.instance()
cs.store(name="dakiny_config", node=DakinyConfig)
logger = logging.getLogger("nextcord")
logger.setLevel(logging.DEBUG)
handler = logging.FileHandler(filename="nextcord.log", encoding="utf-8", mode="w")
handler.setFormatter(logging.Formatter("%(asctime)s:%(levelname)s:%(name)s: %(message)s"))
logger.addHandler(handler)
@hydra.main(config_path="conf", config_name="config")
def main(cfg: DakinyConfig):
@@ -26,7 +33,7 @@ def main(cfg: DakinyConfig):
# intents.guilds = True
# To enable the members priveleged intent:
# intents.members = True
intents.members = True
bot = commands.Bot(intents=intents)
bot.config = cfg
@@ -48,4 +55,6 @@ def main(cfg: DakinyConfig):
if __name__ == "__main__":
sys.argv.append("hydra.job.chdir=False")
main()
sys.argv.append("hydra/job_logging=none")
sys.argv.append("hydra/hydra_logging=none")
main() # pylint: disable=no-value-for-parameter
@@ -5,11 +5,11 @@ Small script to create the database if it doesn't already exist.
import sqlite3
from os.path import exists
if not exists("dakiny.db"):
with sqlite3.connect("dakiny.db") as con:
if not exists("database/dakiny.db"):
with sqlite3.connect("database/dakiny.db") as con:
cur = con.cursor()
with open("database/database.sql", mode="r", encoding="utf-8") as file:
with open("database_setup/database.sql", mode="r", encoding="utf-8") as file:
database_script = file.read()
cur.executescript(database_script)
con.commit()
@@ -1,6 +1,3 @@
-- CREATE DATABASE dakiny;
-- use dakiny;
CREATE TABLE ElectionInformation(
ElectionCycle varchar(30) not null unique,
ElectionChannel bigint unsigned not null,
@@ -24,4 +21,10 @@ CREATE TABLE Votes(
VotedForId bigint unsigned not null,
FOREIGN KEY (ElectionCycle) REFERENCES ElectionInformation(ElectionCycle),
PRIMARY KEY (ElectionCycle, VoterId)
);
CREATE TABLE UserBirthday (
UserId bigint unsigned not null,
Birthday varchar(5) not null,
PRIMARY KEY (UserId)
);
@@ -5,7 +5,7 @@ from sqlalchemy import create_engine
from sqlalchemy.ext.automap import automap_base
# connect with sql alchemy and autoload schema
URL = "sqlite+pysqlite:///dakiny.db"
URL = "sqlite+pysqlite:///database/dakiny.db"
engine = create_engine(URL)
Base = automap_base()
Base.prepare(autoload_with=engine)
+3 -1
View File
@@ -1,4 +1,6 @@
Discord permissions required for bot to operate:
manage channels
manage roles
manage roles
manage nicknames
need member intent