From df8cb3dd4995ee1a1530b6faca81dbfaf9e79464 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Sat, 26 Aug 2023 22:52:02 -0400 Subject: [PATCH 1/7] Add message listener portion of birthday fun. --- cogs/message_listener/__init__.py | 43 +++++++++++++++++++++++++++++++ dakiny_bot.py | 2 ++ 2 files changed, 45 insertions(+) create mode 100644 cogs/message_listener/__init__.py diff --git a/cogs/message_listener/__init__.py b/cogs/message_listener/__init__.py new file mode 100644 index 0000000..af6ab20 --- /dev/null +++ b/cogs/message_listener/__init__.py @@ -0,0 +1,43 @@ +""" +Defines cog for on message listener. +""" + +import nextcord +from nextcord.ext import commands + +from dakiny_bot import birthday_list + + +class SubmissionListener(commands.Cog, name="Message Listener"): + """Sets up message listener.""" + + def __init__(self, bot: commands.Bot): + self.bot = bot + + @commands.Cog.listener() + async def on_message(self, message: nextcord.Message): + """Listener for message creation. Adds score and attachments to submission.""" + # don't want to process any messages from bot. + if message.author.id == self.bot.user.id: + return + + await birthday_action(message) + + +# This function will be called when this extension is loaded. +# It is necessary to add these functions to the bot. +def setup(bot: commands.Bot): + """Adds function to bot""" + bot.add_cog(SubmissionListener(bot)) + + +async def birthday_action(message: nextcord.Message) -> None: + """ + Checks a message's auther and mentions to see if they are in the birthday list. + + Args: + message (nextcord.Message): The message to check for a birthday person. + """ + + if message.author.id in birthday_list or bool(set(message.raw_mentions) & set(birthday_list)): + await message.add_reaction("🎂") diff --git a/dakiny_bot.py b/dakiny_bot.py index 1c42bb8..b284b86 100644 --- a/dakiny_bot.py +++ b/dakiny_bot.py @@ -12,6 +12,8 @@ from config import DakinyConfig cs = ConfigStore.instance() cs.store(name="dakiny_config", node=DakinyConfig) +birthday_list: list[int] = [] + @hydra.main(config_path="conf", config_name="config") def main(cfg: DakinyConfig): From ac8d1bc6815f6c591edd326930e60bb98b67d165 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Sat, 26 Aug 2023 23:04:31 -0400 Subject: [PATCH 2/7] Start update_birthdays function. --- cogs/loops/daily_loop.py | 28 ++++++++++++++++++++++++++++ database_setup/sql_data_classes.py | 1 + 2 files changed, 29 insertions(+) diff --git a/cogs/loops/daily_loop.py b/cogs/loops/daily_loop.py index 372f86c..49045ae 100644 --- a/cogs/loops/daily_loop.py +++ b/cogs/loops/daily_loop.py @@ -2,13 +2,18 @@ Defines the daily loop that runs the Dakiny bot functions. """ +import random from datetime import datetime, time from nextcord.ext import commands, tasks from pytz import timezone +from sqlalchemy import select +from sqlalchemy.orm import Session from classes.election_cycle import ElectionCycle from config import DakinyConfig +from dakiny_bot import birthday_list +from database_setup.sql_data_classes import UserBirthday, engine from utils import get_datetime @@ -26,6 +31,8 @@ class DailyLoop(commands.Cog, name="Daily Loop"): """ Starts the loop when bot is ready. """ + + self.update_birthdays() 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 @@ -46,6 +53,8 @@ class DailyLoop(commands.Cog, name="Daily Loop"): if self.current_election.election_over: self.current_election = None + self.update_birthdays() + def get_current_cycle(self) -> ElectionCycle: """ Creates an object for the current election cycle if one is active. An election is considered active @@ -67,3 +76,22 @@ class DailyLoop(commands.Cog, name="Daily Loop"): current_election = ElectionCycle(cycle, config, self.bot.get_guild(config.params.guild_id)) return current_election + + def update_birthdays(self) -> None: + """ + Goes through database to collect all birthdays that are today. Adds user's id to birthday list. + """ + birthday_list.clear() + + # kandy's 1% chance + if random.randint(0, 99) == 0: + birthday_list.append(239547993106284544) + + today = datetime.today() + birthday = f"{today.month}/{today.day}" + + stmt = select(UserBirthday.UserId).where(UserBirthday.Birthday == birthday) + with Session(engine) as session: + to_add = session.scalars(stmt) + print(to_add) + # TODO add the birthdays to the list diff --git a/database_setup/sql_data_classes.py b/database_setup/sql_data_classes.py index d7ed893..5f4897a 100644 --- a/database_setup/sql_data_classes.py +++ b/database_setup/sql_data_classes.py @@ -14,3 +14,4 @@ Base.prepare(autoload_with=engine) ElectionInformation = Base.classes.ElectionInformation CouncilMembers = Base.classes.CouncilMembers Votes = Base.classes.Votes +UserBirthday = Base.classes.UserBirthday From 077119acddea69c1f031c7c518a495466e5db349 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Wed, 30 Aug 2023 22:49:28 -0400 Subject: [PATCH 3/7] Add initial set birthday command. --- cogs/commands/__init__.py | 3 ++ cogs/commands/set.py | 66 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 cogs/commands/set.py diff --git a/cogs/commands/__init__.py b/cogs/commands/__init__.py index 9ebd402..7232b00 100644 --- a/cogs/commands/__init__.py +++ b/cogs/commands/__init__.py @@ -5,6 +5,7 @@ Cog loader. Adds all command cogs to the bot. from nextcord.ext import commands from cogs.commands.request import RequestCog +from cogs.commands.set import setCog from cogs.commands.test import TestCog @@ -14,5 +15,7 @@ def setup(bot: commands.Bot): """ Adds all command classes to bot. """ + bot.add_cog(RequestCog(bot)) bot.add_cog(TestCog(bot)) + bot.add_cog(setCog()) diff --git a/cogs/commands/set.py b/cogs/commands/set.py new file mode 100644 index 0000000..a9b55b3 --- /dev/null +++ b/cogs/commands/set.py @@ -0,0 +1,66 @@ +""" +Contains commands and views for set commands. +""" + +from datetime import datetime + +import nextcord +from nextcord.ext import commands +from sqlalchemy import delete +from sqlalchemy.orm import Session + +from dakiny_bot import birthday_list +from database_setup.sql_data_classes import UserBirthday, engine + + +class setCog(commands.Cog, name="Set Commands"): + """ + Class holds set commands. + """ + + def __init__(self) -> None: + """ + Default constructor for SetCog class. Does nothing. + """ + + @nextcord.slash_command() + async def set(self, interaction: nextcord.Interaction): + """ + Parent slash command for set. Never called. + """ + + @set.subcommand(description="Sets your birth month and day for the Birthday Fun. Use 0/0 to remove yourself.") + async def birthday( + self, + interaction: nextcord.Interaction, + month: int = nextcord.SlashOption(required=True, min_value=0, max_value=12, description="Your birth month."), + day: int = nextcord.SlashOption(required=True, min_value=0, max_value=31, description="Your birth day."), + ): + """ + Sets a user's birthday in the database. Removes on input 0/0. If birthday is today, adds to the birthday_list. + + Args: + interaction (nextcord.Interaction): Interaction that invoked the command. + month (int, optional): The month a user was born. Is SlashOption. + day (int, optional): The day a user was born. Is SlashOption. + """ + + if month == 0 and day == 0: + stmt = delete(UserBirthday).where(UserBirthday.UserId == interaction.user.id) + with Session(engine) as session: + session.scalar(stmt) + session.commit() + return + + # check if valid day + today = datetime.today() + birthday = datetime(today.year, month, day) + + # If the birthday is today, add to birthday_list + if today.date() == birthday.date(): + birthday_list.append(interaction.user.id) + + new_birthday = UserBirthday(interaction.user.id, f"{month}/{day}") + with Session(engine) as session: + session.add(new_birthday) + session.commit() From 5668e4be7e35431607bd3d6db70d2d276e9eb5f9 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Sat, 9 Sep 2023 11:49:56 -0400 Subject: [PATCH 4/7] Add release workflow. --- .gitea/workflows/build_release.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .gitea/workflows/build_release.yml diff --git a/.gitea/workflows/build_release.yml b/.gitea/workflows/build_release.yml new file mode 100644 index 0000000..fd8d857 --- /dev/null +++ b/.gitea/workflows/build_release.yml @@ -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}} From efadcb30c770279943876a3dba487e6315ff9d15 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Sat, 9 Sep 2023 13:27:22 -0400 Subject: [PATCH 5/7] Finish up set birthday command. --- cogs/commands/set.py | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/cogs/commands/set.py b/cogs/commands/set.py index a9b55b3..0b5925d 100644 --- a/cogs/commands/set.py +++ b/cogs/commands/set.py @@ -6,7 +6,8 @@ from datetime import datetime import nextcord from nextcord.ext import commands -from sqlalchemy import delete +from sqlalchemy import delete, select +from sqlalchemy.exc import IntegrityError from sqlalchemy.orm import Session from dakiny_bot import birthday_list @@ -45,22 +46,40 @@ class setCog(commands.Cog, name="Set Commands"): day (int, optional): The day a user was born. Is SlashOption. """ + # Must be deferred, apparently datetime takes a little bit on invalid dates. + await interaction.response.defer(ephemeral=True) + if month == 0 and day == 0: stmt = delete(UserBirthday).where(UserBirthday.UserId == interaction.user.id) with Session(engine) as session: - session.scalar(stmt) + session.execute(stmt) session.commit() + await interaction.followup.send("Removed birthday.", ephemeral=True) return # check if valid day today = datetime.today() - birthday = datetime(today.year, month, day) + try: + birthday = datetime(today.year, month, day) + except ValueError: + await interaction.followup.send(f"Invalid date: {month}/{day}.", ephemeral=True) + return # If the birthday is today, add to birthday_list if today.date() == birthday.date(): birthday_list.append(interaction.user.id) - new_birthday = UserBirthday(interaction.user.id, f"{month}/{day}") + new_birthday = UserBirthday(UserId=interaction.user.id, Birthday=f"{month}/{day}") with Session(engine) as session: - session.add(new_birthday) - session.commit() + try: + session.add(new_birthday) + session.commit() + except IntegrityError: + # User already has birthday, change it instead. + session.rollback() + stmt = select(UserBirthday).where(UserBirthday.UserId == interaction.user.id) + new_birthday = session.scalar(stmt) + new_birthday.Birthday = f"{month}/{day}" + session.commit() + + await interaction.followup.send(f"Birthday set to {month}/{day}.", ephemeral=True) From 7a91cd37ece9a326dda4f303ba8dcaac698746fd Mon Sep 17 00:00:00 2001 From: imcompiling Date: Sat, 9 Sep 2023 13:48:22 -0400 Subject: [PATCH 6/7] Add birthdays from database. --- cogs/loops/daily_loop.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cogs/loops/daily_loop.py b/cogs/loops/daily_loop.py index 08ab79a..6433956 100644 --- a/cogs/loops/daily_loop.py +++ b/cogs/loops/daily_loop.py @@ -97,5 +97,4 @@ class DailyLoop(commands.Cog, name="Daily Loop"): stmt = select(UserBirthday.UserId).where(UserBirthday.Birthday == birthday) with Session(engine) as session: to_add = session.scalars(stmt) - print(to_add) - # TODO add the birthdays to the list + birthday_list.extend(to_add.all()) From 18751bc85ceaf3cce711e5632120a0da1cf68595 Mon Sep 17 00:00:00 2001 From: imcompiling Date: Tue, 12 Sep 2023 13:17:25 -0400 Subject: [PATCH 7/7] Inform Kandy when it is her "birthday". --- cogs/loops/daily_loop.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cogs/loops/daily_loop.py b/cogs/loops/daily_loop.py index 6433956..6b47fa1 100644 --- a/cogs/loops/daily_loop.py +++ b/cogs/loops/daily_loop.py @@ -5,6 +5,7 @@ Defines the daily loop that runs the Dakiny bot functions. import random from datetime import datetime, time +import nextcord from nextcord.ext import commands, tasks from pytz import timezone from sqlalchemy import select @@ -48,6 +49,11 @@ class DailyLoop(commands.Cog, name="Daily Loop"): self.update_birthdays() + if 239547993106284544 in birthday_list: + # inform kandy that it is her "birthday" + kandy: nextcord.User = await self.bot.fetch_user(239547993106284544) + await kandy.send('Happy "Birthday"!') + @daily_loop.before_loop async def before_loop(self): """