from typing import Any, Dict, List from bson.errors import InvalidId from discord import ApplicationContext, Attachment, SlashCommandGroup, option from discord.ext.commands import Cog from discord.utils import basic_autocomplete from libbot.i18n import _, in_every_locale from classes import PycordEvent, PycordEventStage, PycordGuild from classes.errors import ( EventNotFoundError, EventStageNotFoundError, GuildNotFoundError, ) from classes.pycord_bot import PycordBot from modules.utils import ( autocomplete_active_events, autocomplete_event_stages, is_event_status_valid, is_operation_confirmed, ) class CogStage(Cog): """Cog with event stage management commands.""" def __init__(self, bot: PycordBot): self.bot: PycordBot = bot command_group: SlashCommandGroup = SlashCommandGroup( "stage", description=_("description", "commands", "stage"), description_localizations=in_every_locale("description", "commands", "stage"), ) # TODO Maybe add an option for order? @command_group.command( name="add", description=_("description", "commands", "stage_add"), description_localizations=in_every_locale("description", "commands", "stage_add"), ) @option( "event", description=_("description", "commands", "stage_add", "options", "event"), description_localizations=in_every_locale( "description", "commands", "stage_add", "options", "event" ), autocomplete=basic_autocomplete(autocomplete_active_events), required=True, ) @option( "question", description=_("description", "commands", "stage_add", "options", "question"), description_localizations=in_every_locale( "description", "commands", "stage_add", "options", "question" ), required=True, ) @option( "answer", description=_("description", "commands", "stage_add", "options", "answer"), description_localizations=in_every_locale( "description", "commands", "stage_add", "options", "answer" ), max_length=500, required=True, ) @option( "media", description=_("description", "commands", "stage_add", "options", "media"), description_localizations=in_every_locale( "description", "commands", "stage_add", "options", "media" ), required=False, ) async def command_stage_add( self, ctx: ApplicationContext, event: str, question: str, answer: str, media: Attachment = None, ) -> None: try: guild: PycordGuild = await self.bot.find_guild(ctx.guild.id) except (InvalidId, GuildNotFoundError): await ctx.respond(self.bot._("unexpected_error", "messages", locale=ctx.locale), ephemeral=True) return if not guild.is_configured(): await ctx.respond( self.bot._("guild_unconfigured_admin", "messages", locale=ctx.locale), ephemeral=True ) return try: pycord_event: PycordEvent = await self.bot.find_event(event_id=event) except (InvalidId, EventStageNotFoundError): await ctx.respond(self.bot._("event_not_found", "messages", locale=ctx.locale), ephemeral=True) return if not (await is_event_status_valid(ctx, pycord_event)): return processed_media: List[Dict[str, Any]] = ( [] if media is None else await self.bot.process_attachments([media]) ) event_stage: PycordEventStage = await self.bot.create_event_stage( event=pycord_event, event_id=pycord_event._id, guild_id=guild.id, sequence=len(pycord_event.stage_ids), creator_id=ctx.author.id, question=question, answer=answer, media=[] if media is None else processed_media, ) await ctx.respond(self.bot._("stage_created", "messages", locale=ctx.locale)) @command_group.command( name="edit", description=_("description", "commands", "stage_edit"), description_localizations=in_every_locale("description", "commands", "stage_edit"), ) @option( "event", description=_("description", "commands", "stage_edit", "options", "event"), description_localizations=in_every_locale( "description", "commands", "stage_edit", "options", "event" ), autocomplete=basic_autocomplete(autocomplete_active_events), required=True, ) @option( "stage", description=_("description", "commands", "stage_edit", "options", "stage"), description_localizations=in_every_locale( "description", "commands", "stage_edit", "options", "stage" ), autocomplete=basic_autocomplete(autocomplete_event_stages), required=True, ) @option( "order", description=_("description", "commands", "stage_edit", "options", "order"), description_localizations=in_every_locale( "description", "commands", "stage_edit", "options", "order" ), min_value=1, required=False, ) @option( "question", description=_("description", "commands", "stage_edit", "options", "question"), description_localizations=in_every_locale( "description", "commands", "stage_edit", "options", "question" ), required=False, ) @option( "answer", description=_("description", "commands", "stage_edit", "options", "answer"), description_localizations=in_every_locale( "description", "commands", "stage_edit", "options", "answer" ), max_length=500, required=False, ) @option( "media", description=_("description", "commands", "stage_edit", "options", "media"), description_localizations=in_every_locale( "description", "commands", "stage_edit", "options", "media" ), required=False, ) @option( "remove_media", description=_("description", "commands", "stage_edit", "options", "remove_media"), description_localizations=in_every_locale( "description", "commands", "stage_edit", "options", "remove_media" ), required=False, ) async def command_stage_edit( self, ctx: ApplicationContext, event: str, stage: str, order: int, question: str, answer: str, media: Attachment = None, remove_media: bool = False, ) -> None: try: guild: PycordGuild = await self.bot.find_guild(ctx.guild.id) except (InvalidId, GuildNotFoundError): await ctx.respond(self.bot._("unexpected_error", "messages", locale=ctx.locale), ephemeral=True) return if not guild.is_configured(): await ctx.respond( self.bot._("guild_unconfigured_admin", "messages", locale=ctx.locale), ephemeral=True ) return try: pycord_event: PycordEvent = await self.bot.find_event(event_id=event) except (InvalidId, EventNotFoundError): await ctx.respond(self.bot._("event_not_found", "messages", locale=ctx.locale), ephemeral=True) return if not (await is_event_status_valid(ctx, pycord_event)): return try: event_stage: PycordEventStage = await self.bot.find_event_stage(stage) except (InvalidId, EventStageNotFoundError): await ctx.respond(self.bot._("stage_not_found", "messages", locale=ctx.locale), ephemeral=True) return if order is not None and order > len(pycord_event.stage_ids): await ctx.respond( self.bot._("stage_sequence_out_of_range", "messages", locale=ctx.locale), ephemeral=True ) return processed_media: List[Dict[str, Any]] = ( [] if media is None else await self.bot.process_attachments([media]) ) if not (question is None and answer is None and media is None and remove_media is False): await event_stage.update( question=event_stage.question if question is None else question, answer=event_stage.answer if answer is None else answer, media=([] if remove_media else (event_stage.media if media is None else processed_media)), ) if order is not None and order - 1 != event_stage.sequence: await pycord_event.reorder_stage(self.bot, event_stage._id, order - 1, cache=self.bot.cache) await ctx.respond(self.bot._("stage_updated", "messages", locale=ctx.locale)) @command_group.command( name="delete", description=_("description", "commands", "stage_delete"), description_localizations=in_every_locale("description", "commands", "stage_delete"), ) @option( "event", description=_("description", "commands", "stage_delete", "options", "event"), description_localizations=in_every_locale( "description", "commands", "stage_delete", "options", "event" ), autocomplete=basic_autocomplete(autocomplete_active_events), required=True, ) @option( "stage", description=_("description", "commands", "stage_delete", "options", "stage"), description_localizations=in_every_locale( "description", "commands", "stage_delete", "options", "stage" ), autocomplete=basic_autocomplete(autocomplete_event_stages), required=True, ) @option( "confirm", description=_("description", "commands", "stage_delete", "options", "confirm"), description_localizations=in_every_locale( "description", "commands", "stage_delete", "options", "confirm" ), required=False, ) async def command_stage_delete( self, ctx: ApplicationContext, event: str, stage: str, confirm: bool = False ) -> None: if not (await is_operation_confirmed(ctx, confirm)): return try: guild: PycordGuild = await self.bot.find_guild(ctx.guild.id) except (InvalidId, GuildNotFoundError): await ctx.respond(self.bot._("unexpected_error", "messages", locale=ctx.locale), ephemeral=True) return if not guild.is_configured(): await ctx.respond( self.bot._("guild_unconfigured_admin", "messages", locale=ctx.locale), ephemeral=True ) return try: pycord_event: PycordEvent = await self.bot.find_event(event_id=event) except (InvalidId, EventNotFoundError): await ctx.respond(self.bot._("event_not_found", "messages", locale=ctx.locale), ephemeral=True) return if not (await is_event_status_valid(ctx, pycord_event)): return try: event_stage: PycordEventStage = await self.bot.find_event_stage(stage) except (InvalidId, EventStageNotFoundError): await ctx.respond(self.bot._("stage_not_found", "messages", locale=ctx.locale), ephemeral=True) return await pycord_event.remove_stage(self.bot, event_stage._id, cache=self.bot.cache) await event_stage.purge(cache=self.bot.cache) await ctx.respond(self.bot._("stage_deleted", "messages", locale=ctx.locale)) def setup(bot: PycordBot) -> None: bot.add_cog(CogStage(bot))