"""Defines the daily loop that runs the Off Cooldown bot functions.""" from datetime import UTC, datetime, time import nextcord from nextcord.ext import commands, tasks from pytz import timezone from sqlalchemy import select from sqlalchemy.orm import Session from sqlmodel import col from database.db import engine from database.models import UserBirthday from logger import ocd_logger from main import birthday_list from settings import settings class DailyLoop(commands.Cog, name="Daily Loop"): """Class for performing daily functions.""" def __init__(self, bot: commands.Bot) -> None: self.bot = bot self.current_election = None self.update_birthdays() self.daily_loop.start() @tasks.loop(time=time(hour=0, tzinfo=timezone("UTC"))) async def daily_loop(self) -> None: """Run daily repeated functions.""" self.update_birthdays() await self.cakedays() @daily_loop.before_loop async def before_loop(self) -> None: """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() 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() today = datetime.now(tz=UTC).date() stmt = ( select(col(UserBirthday.user_id)) .where(col(UserBirthday.month) == today.month) .where(col(UserBirthday.day) == today.day) ) with Session(engine) as session: to_add = session.scalars(stmt) birthday_list.extend(to_add.all()) async def cakedays(self) -> None: """ Loops through the guild's humans checking for joined_at dates that match today's date. Sends a message saying happy cakeday. """ today = datetime.now(tz=UTC).date() if (guild := self.bot.get_guild(settings.params.guild_id)) is None: ocd_logger.warning("Guild not found in bot.") return if (announce_channel := guild.get_channel(settings.channel_ids.general)) is None or not isinstance( announce_channel, nextcord.TextChannel ): ocd_logger.warning("Set general channel isn't found or isn't a text channel.") return cakedays: list[nextcord.Member] = [ human for human in guild.humans if human.joined_at is not None and human.joined_at.month == today.month and human.joined_at.day == today.day ] for member in cakedays: years = today.year - member.joined_at.year # type: ignore reportOptionalMemberAccess year_str = "years" if years > 1 else "year" msg = f"Happy Cake day! <@{member.id}> joined the discord {years} {year_str} ago!" await announce_channel.send(msg)