129 lines
4.5 KiB
Python
129 lines
4.5 KiB
Python
"""
|
|
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
|
|
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
|
|
|
|
|
|
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()
|
|
|
|
# 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):
|
|
"""
|
|
Runs daily. Checks if the current election is None. If so, checks if there is an active election. If there is
|
|
an active election, runs the check_date() function for the election to perform actions. Finally checks if the
|
|
election is over to delete the current election object.
|
|
"""
|
|
|
|
if self.current_election is None:
|
|
self.current_election = self.get_current_cycle()
|
|
|
|
if self.current_election is not None:
|
|
await self.current_election.check_date()
|
|
if self.current_election.election_over:
|
|
self.current_election = None
|
|
|
|
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"!')
|
|
|
|
await self.cakedays()
|
|
|
|
@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
|
|
between the election start and the term start.
|
|
|
|
Returns:
|
|
ElectionCycle: Current election cycle, None if there is no election happening.
|
|
"""
|
|
|
|
today = datetime.today()
|
|
config: DakinyConfig = self.bot.config
|
|
current_election = None
|
|
|
|
for cycle, election in enumerate(config.election_cycles):
|
|
if (
|
|
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))
|
|
|
|
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)
|
|
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.today()
|
|
guild: nextcord.Guild = self.bot.get_guild(self.bot.config.params.guild_id)
|
|
announce_channel: nextcord.TextChannel = guild.get_channel(self.bot.config.params.announcement_category_id)
|
|
|
|
cakedays: list[nextcord.Member] = [
|
|
human for human in guild.humans if human.joined_at.month == today.month and human.joined_at.day == today.day
|
|
]
|
|
|
|
for member in cakedays:
|
|
years = today.year - member.joined_at.year
|
|
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)
|