Implemented /event edit and /edit cancel

This commit is contained in:
2025-04-21 22:49:23 +02:00
parent b72f930c94
commit 08d1ca4d33
5 changed files with 286 additions and 120 deletions

View File

@@ -3,7 +3,14 @@ from typing import Dict, Any, List
from zoneinfo import ZoneInfo
from bson import ObjectId
from discord import ApplicationContext, Attachment, SlashCommandGroup, option, AutocompleteContext
from discord import (
ApplicationContext,
Attachment,
SlashCommandGroup,
option,
AutocompleteContext,
OptionChoice,
)
from discord.ext.commands import Cog
from discord.utils import basic_autocomplete
@@ -12,38 +19,51 @@ 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"))}}
# TODO Move to staticmethod or to a separate module
async def get_event(ctx: AutocompleteContext) -> List[OptionChoice]:
query: Dict[str, Any] = {
"ended": None,
"ends": {"$gt": datetime.now(tz=ZoneInfo("UTC"))},
"cancelled": {"$ne": True},
}
event_names: List[str] = []
event_names: List[OptionChoice] = []
async for result in col_events.find(query):
event_names.append(result["name"])
event_names.append(OptionChoice(result["name"], str(result["_id"])))
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,
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:
# TODO Make a nice message
await ctx.respond("Start date must be before finish date")
return
elif start_date < datetime.now(tz=guild_timezone):
# TODO Make a nice message
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"))}}
query: Dict[str, Any] = {
"name": name,
"ended": None,
"ends": {"$gt": datetime.now(tz=ZoneInfo("UTC"))},
"cancelled": {"$ne": True},
}
if event_id is not None:
query["_id"] = {"$ne": event_id}
if (await col_events.find_one(query)) is not None:
# TODO Make a nice message
await ctx.respond("There can only be one active event with the same name")
return
@@ -57,26 +77,27 @@ class Event(Cog):
# TODO Introduce i18n
command_group: SlashCommandGroup = SlashCommandGroup("event", "Event management")
# TODO Implement the command
# TODO Introduce i18n
@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("end", description="Date when the event ends (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,
self,
ctx: ApplicationContext,
name: str,
start: str,
end: str,
thumbnail: Attachment = None,
) -> None:
guild: PycordGuild = await self.bot.find_guild(ctx.guild.id)
if not guild.is_configured():
# TODO Make a nice message
await ctx.respond("Guild is not configured.")
return
@@ -84,28 +105,30 @@ class Event(Cog):
try:
start_date: datetime = datetime.strptime(start, "%d.%m.%Y %H:%M")
finish_date: datetime = datetime.strptime(finish, "%d.%m.%Y %H:%M")
end_date: datetime = datetime.strptime(end, "%d.%m.%Y %H:%M")
start_date = start_date.replace(tzinfo=guild_timezone)
finish_date = finish_date.replace(tzinfo=guild_timezone)
end_date = end_date.replace(tzinfo=guild_timezone)
except ValueError:
await ctx.respond("Could not parse start and finish dates.")
# TODO Make a nice message
await ctx.respond("Could not parse start and end dates.")
return
await validate_event_validity(ctx, name, start_date, finish_date, guild_timezone)
await validate_event_validity(ctx, name, start_date, end_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")),
ends=end_date.astimezone(ZoneInfo("UTC")),
thumbnail_id=thumbnail.id if thumbnail else None,
)
# TODO Make a nice message
await ctx.respond("Event has been created.")
# TODO Implement the command
# TODO Introduce i18n
@command_group.command(
name="edit",
description="Edit event",
@@ -115,21 +138,23 @@ class Event(Cog):
)
@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("end", description="Date when the event ends (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,
self,
ctx: ApplicationContext,
event: str,
name: str = None,
start: str = None,
end: 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
)
pycord_event: PycordEvent = await self.bot.find_event(event_id=event)
if pycord_event is None:
await ctx.respond("Event was not found.")
return
if not guild.is_configured():
await ctx.respond("Guild is not configured.")
@@ -137,42 +162,75 @@ class Event(Cog):
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)
try:
start_date: datetime = (
pycord_event.starts if start is None else datetime.strptime(start, "%d.%m.%Y %H:%M")
)
start_date = start_date.replace(tzinfo=guild_timezone)
except ValueError:
await ctx.respond("Could not parse the start date.")
return
await event.set_start_date(start_date)
except ValueError:
await ctx.respond("Could not parse the start date.")
return
try:
end_date: datetime = (
pycord_event.ends if end is None else datetime.strptime(end, "%d.%m.%Y %H:%M")
)
end_date = end_date.replace(tzinfo=guild_timezone)
except ValueError:
await ctx.respond("Could not parse the end 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 validate_event_validity(ctx, name, start_date, end_date, guild_timezone)
await event.set_end_date(finish_date)
except ValueError:
await ctx.respond("Could not parse the finish date.")
return
await pycord_event.update(
self.bot.cache,
starts=start_date,
ends=end_date,
name=pycord_event.name if name is None else name,
thumbnail_id=pycord_event.thumbnail_id if thumbnail is None else thumbnail.id,
)
await validate_event_validity(ctx, name, start_date, finish_date, guild_timezone)
await ctx.respond("Event has been updated.")
# TODO Implement the command
@command_group.command(
name="cancel",
description="Cancel event",
)
@option("name", description="Name of the event", required=True)
@option(
"event", description="Name of the event", autocomplete=basic_autocomplete(get_event), required=True
)
async def command_event_cancel(
self,
ctx: ApplicationContext,
name: str,
self,
ctx: ApplicationContext,
event: str,
) -> None:
guild: PycordGuild = await self.bot.find_guild(ctx.guild.id)
pycord_event: PycordEvent = await self.bot.find_event(event_id=event)
await ctx.respond("Not implemented.")
if pycord_event is None:
await ctx.respond("Event was not found.")
return
if not guild.is_configured():
await ctx.respond("Guild is not configured.")
return
start_date: datetime = pycord_event.starts.replace(tzinfo=ZoneInfo("UTC"))
end_date: datetime = pycord_event.ends.replace(tzinfo=ZoneInfo("UTC"))
# TODO Make ongoing events cancellable
if (
pycord_event.ended is not None
or end_date <= datetime.now(tz=ZoneInfo("UTC"))
or start_date <= datetime.now(tz=ZoneInfo("UTC"))
):
await ctx.respond("Finished or ongoing events cannot be cancelled.")
return
await pycord_event.cancel()
await ctx.respond("Event was cancelled.")
def setup(bot: PycordBot) -> None: