from datetime import datetime from logging import Logger from pathlib import Path from typing import Any, Dict, List from zoneinfo import ZoneInfo from bson import ObjectId from bson.errors import InvalidId from discord import Activity, ActivityType, Cog, File, Member, TextChannel from classes import PycordEvent, PycordGuild, PycordUser from classes.errors import GuildNotFoundError from classes.pycord_bot import PycordBot from modules.database import col_users from modules.utils import get_logger, get_utc_now logger: Logger = get_logger(__name__) class CogUtility(Cog): def __init__(self, bot: PycordBot): self.bot: PycordBot = bot @Cog.listener() async def on_ready(self) -> None: """Listener for the event when bot connects to Discord and becomes "ready".""" logger.info("Logged in as %s", self.bot.user) activity_enabled: bool = self.bot.config["bot"]["status"]["enabled"] activity_type: str = self.bot.config["bot"]["status"]["activity_type"] activity_message: str = self.bot.config["bot"]["status"]["activity_text"] if not activity_enabled: return if activity_type == "playing": await self.bot.change_presence( activity=Activity(type=ActivityType.playing, name=activity_message) ) elif activity_type == "watching": await self.bot.change_presence( activity=Activity(type=ActivityType.watching, name=activity_message) ) elif activity_type == "listening": await self.bot.change_presence( activity=Activity(type=ActivityType.listening, name=activity_message) ) elif activity_type == "streaming": await self.bot.change_presence( activity=Activity(type=ActivityType.streaming, name=activity_message) ) elif activity_type == "competing": await self.bot.change_presence( activity=Activity(type=ActivityType.competing, name=activity_message) ) elif activity_type == "custom": await self.bot.change_presence( activity=Activity(type=ActivityType.custom, name=activity_message) ) else: return logger.info("Set activity type to %s with message %s", activity_type, activity_message) @Cog.listener("on_member_join") async def on_member_join(self, member: Member) -> None: try: guild: PycordGuild = await self.bot.find_guild(member.guild.id) except (InvalidId, GuildNotFoundError) as exc: logger.error( "Could not process member join event for %s in %s due to: %s", member.id, member.guild.id, exc, ) return user: PycordUser = await self.bot.find_user(member.id, member.guild.id) events: List[PycordEvent] = [] utc_now: datetime = get_utc_now() pipeline: List[Dict[str, Any]] = [ {"$match": {"id": user.id}}, { "$lookup": { "from": "events", "let": {"event_ids": "$registered_event_ids"}, "pipeline": [ { "$match": { "$expr": { "$and": [ {"$in": ["$_id", "$$event_ids"]}, {"$eq": ["$ended", None]}, {"$gt": ["$ends", utc_now]}, {"$lt": ["$starts", utc_now]}, {"$eq": ["$is_cancelled", False]}, ] } } } ], "as": "registered_events", } }, {"$match": {"registered_events.0": {"$exists": True}}}, ] async with await col_users.aggregate(pipeline) as cursor: async for result in cursor: for registered_event in result["registered_events"]: events.append(PycordEvent(**registered_event)) for event in events: if user.current_event_id is not None and user.current_event_id != event._id: continue if user.current_event_id is None: await user.set_event(event._id, cache=self.bot.cache) channel: TextChannel | None = await user.fix_event_channel( self.bot, member.guild, guild, event, cache=self.bot.cache ) if channel is None: continue thumbnail: File | None = ( None if event.thumbnail is None else File(Path(f"data/{event.thumbnail['id']}"), event.thumbnail["filename"]) ) await channel.send( self.bot._("notice_event_already_started", "messages").format(event_name=event.name), file=thumbnail, ) stage_id: ObjectId = ( event.stage_ids[0] if user.current_stage_id is None else user.current_stage_id ) await user.set_event_stage(stage_id, cache=self.bot.cache) await self.bot.send_stage_question(channel, event, await self.bot.find_event_stage(stage_id)) def setup(bot: PycordBot) -> None: bot.add_cog(CogUtility(bot))