Files
QuizBot/cogs/event.py
2025-04-21 14:34:13 +02:00

180 lines
6.1 KiB
Python

from datetime import datetime
from typing import Dict, Any, List
from zoneinfo import ZoneInfo
from bson import ObjectId
from discord import ApplicationContext, Attachment, SlashCommandGroup, option, AutocompleteContext
from discord.ext.commands import Cog
from discord.utils import basic_autocomplete
from classes import PycordEvent, PycordGuild
from classes.pycord_bot import PycordBot
from modules.database import col_events
async def get_event(ctx: AutocompleteContext):
query: Dict[str, Any] = {"ended": None, "ends": {"$gt": datetime.now(tz=ZoneInfo("UTC"))}}
event_names: List[str] = []
async for result in col_events.find(query):
event_names.append(result["name"])
return event_names
async def validate_event_validity(
ctx: ApplicationContext,
name: str,
start_date: datetime | None,
finish_date: datetime | None,
guild_timezone: ZoneInfo,
event_id: ObjectId | None = None,
) -> None:
if start_date > finish_date:
await ctx.respond("Start date must be before finish date")
return
elif start_date < datetime.now(tz=guild_timezone):
await ctx.respond("Start date must not be in the past")
return
query: Dict[str, Any] = {"name": name, "ended": None, "ends": {"$gt": datetime.now(tz=ZoneInfo("UTC"))}}
if event_id is not None:
query["_id"] = {"$ne": event_id}
if (await col_events.find_one(query)) is not None:
await ctx.respond("There can only be one active event with the same name")
return
class Event(Cog):
"""Cog with event management commands."""
def __init__(self, bot: PycordBot):
self.bot: PycordBot = bot
# TODO Introduce i18n
command_group: SlashCommandGroup = SlashCommandGroup("event", "Event management")
# TODO Implement the command
@command_group.command(
name="create",
description="Create new event",
)
@option("name", description="Name of the event", required=True)
@option("start", description="Date when the event starts (DD.MM.YYYY HH:MM)", required=True)
@option("finish", description="Date when the event finishes (DD.MM.YYYY HH:MM)", required=True)
@option("thumbnail", description="Thumbnail of the event", required=False)
async def command_event_create(
self,
ctx: ApplicationContext,
name: str,
start: str,
finish: str,
thumbnail: Attachment = None,
) -> None:
guild: PycordGuild = await self.bot.find_guild(ctx.guild.id)
if not guild.is_configured():
await ctx.respond("Guild is not configured.")
return
guild_timezone: ZoneInfo = ZoneInfo(guild.timezone)
try:
start_date: datetime = datetime.strptime(start, "%d.%m.%Y %H:%M")
finish_date: datetime = datetime.strptime(finish, "%d.%m.%Y %H:%M")
start_date = start_date.replace(tzinfo=guild_timezone)
finish_date = finish_date.replace(tzinfo=guild_timezone)
except ValueError:
await ctx.respond("Could not parse start and finish dates.")
return
await validate_event_validity(ctx, name, start_date, finish_date, guild_timezone)
event: PycordEvent = await self.bot.create_event(
name=name,
guild_id=guild.id,
creator_id=ctx.author.id,
starts=start_date.astimezone(ZoneInfo("UTC")),
ends=finish_date.astimezone(ZoneInfo("UTC")),
thumbnail_id=thumbnail.id if thumbnail else None,
)
await ctx.respond("Event has been created.")
# TODO Implement the command
@command_group.command(
name="edit",
description="Edit event",
)
@option(
"event", description="Name of the event", autocomplete=basic_autocomplete(get_event), required=True
)
@option("name", description="New name of the event", required=False)
@option("start", description="Date when the event starts (DD.MM.YYYY HH:MM)", required=False)
@option("finish", description="Date when the event finishes (DD.MM.YYYY HH:MM)", required=False)
@option("thumbnail", description="Thumbnail of the event", required=False)
async def command_event_edit(
self,
ctx: ApplicationContext,
event: str,
name: str = None,
start: str = None,
finish: str = None,
thumbnail: Attachment = None,
) -> None:
guild: PycordGuild = await self.bot.find_guild(ctx.guild.id)
event: PycordEvent = await self.bot.find_event(
event_name=name
)
if not guild.is_configured():
await ctx.respond("Guild is not configured.")
return
guild_timezone: ZoneInfo = ZoneInfo(guild.timezone)
if start is not None:
try:
start_date: datetime = datetime.strptime(start, "%d.%m.%Y %H:%M")
start_date = start_date.replace(tzinfo=guild_timezone)
await event.set_start_date(start_date)
except ValueError:
await ctx.respond("Could not parse the start date.")
return
if finish is not None:
try:
finish_date: datetime = datetime.strptime(finish, "%d.%m.%Y %H:%M")
finish_date = finish_date.replace(tzinfo=guild_timezone)
await event.set_end_date(finish_date)
except ValueError:
await ctx.respond("Could not parse the finish date.")
return
await validate_event_validity(ctx, name, start_date, finish_date, guild_timezone)
# TODO Implement the command
@command_group.command(
name="cancel",
description="Cancel event",
)
@option("name", description="Name of the event", required=True)
async def command_event_cancel(
self,
ctx: ApplicationContext,
name: str,
) -> None:
guild: PycordGuild = await self.bot.find_guild(ctx.guild.id)
await ctx.respond("Not implemented.")
def setup(bot: PycordBot) -> None:
bot.add_cog(Event(bot))