Files
QuizBot/cogs/cog_utility.py

151 lines
5.5 KiB
Python

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))