diff --git a/ModuBotDiscord/commands/__init__.py b/ModuBotDiscord/commands/__init__.py index db3aa79..c973ea5 100644 --- a/ModuBotDiscord/commands/__init__.py +++ b/ModuBotDiscord/commands/__init__.py @@ -1,28 +1,102 @@ import functools +import logging +import warnings from abc import ABC, abstractmethod -from typing import Awaitable, Callable, TypeVar +from typing import Awaitable, Callable, List, Optional, TypeVar -from discord import Interaction +import discord +from discord import Embed, Interaction from ModuBotDiscord.config import DiscordConfig from ..enums import PermissionEnum T = TypeVar("T", bound=Callable[..., Awaitable[None]]) +logger = logging.getLogger(__name__) + async def send_message( - interaction: Interaction, msg: str, ephemeral: bool = False + interaction: Interaction, + msg: Optional[str] = None, + content: Optional[str] = None, + *, + embed: Optional[Embed] = None, + embeds: Optional[List[Embed]] = None, + file: Optional[discord.File] = None, + files: Optional[List[discord.File]] = None, + view: Optional[discord.ui.View] = None, + tts: bool = False, + ephemeral: bool = False, + allowed_mentions: Optional[discord.AllowedMentions] = None, + suppress_embeds: bool = False, + silent: bool = False, + delete_after: Optional[float] = None, + poll=None, ) -> None: - if not interaction.response.is_done(): - await interaction.response.send_message(msg, ephemeral=ephemeral) + if content is None and msg is not None: + warnings.warn( + "`msg` is deprecated, use `content` instead", + DeprecationWarning, + stacklevel=2, + ) + content = msg + + if not interaction.is_expired(): + if not interaction.response.is_done(): + await interaction.response.send_message( + content=content, + embed=embed, + embeds=embeds, + file=file, + files=files, + view=view, + tts=tts, + ephemeral=ephemeral, + allowed_mentions=allowed_mentions, + suppress_embeds=suppress_embeds, + silent=silent, + delete_after=delete_after, + poll=poll, + ) + else: + await interaction.followup.send( + content=content, + embed=embed, + embeds=embeds, + file=file, + files=files, + view=view, + tts=tts, + ephemeral=ephemeral, + allowed_mentions=allowed_mentions, + suppress_embeds=suppress_embeds, + silent=silent, + delete_after=delete_after, + poll=poll, + ) else: - await interaction.followup.send(msg, ephemeral=ephemeral) + logger.warning("Interaction is expired. Skipping send_message().") async def send_error( - interaction: Interaction, msg: str = "You are not allowed to use this command." + interaction: Interaction, + msg: Optional[str] = None, + title: str = "⚠️ An error occurred", + description: Optional[str] = None, ) -> None: - await send_message(interaction, msg, True) + if msg is not None: + warnings.warn( + "`msg` is deprecated, use `title` or `description` instead", + DeprecationWarning, + stacklevel=2, + ) + if description is None: + description = msg + else: + title = msg + + embed: Embed = Embed(title=title, description=description, color=0xFF0000) + await send_message(interaction, embed=embed, ephemeral=True) def check_permission(*permissions: PermissionEnum) -> Callable[[T], T]: @@ -38,7 +112,8 @@ async def wrapper(interaction: Interaction, *args, **kwargs): missing_permissions = ", ".join(f"`{m}`" for m in missing) await send_error( interaction, - f"You are missing the following permissions: {missing_permissions}", + title="🚫 Action not allowed", + description=f"You are missing the following permissions: {missing_permissions}", ) return None return await func(interaction, *args, **kwargs) @@ -54,7 +129,9 @@ def decorator(func: T) -> T: async def wrapper(interaction: Interaction, *args, **kwargs): if not interaction.guild: await send_error( - interaction, "This command can only be used in a server." + interaction, + title="🚫 Action not allowed", + description="This command can only be used in a server.", ) return None @@ -68,7 +145,8 @@ async def wrapper(interaction: Interaction, *args, **kwargs): missing_permissions = ", ".join(f"`{m}`" for m in missing) await send_error( interaction, - f"The bot is missing the following permissions: {missing_permissions}", + title="🚫 Action not allowed", + description=f"The bot is missing the following permissions: {missing_permissions}", ) return None @@ -85,7 +163,9 @@ def decorator(func: T) -> T: async def wrapper(interaction: Interaction, *args, **kwargs): if interaction.user.id != DiscordConfig.OWNER_ID: await send_error( - interaction, "You must be the bot owner to use this command." + interaction, + title="🚫 Action not allowed", + description="You must be the bot owner to use this command.", ) return None return await func(interaction, *args, **kwargs) @@ -104,7 +184,9 @@ async def wrapper(interaction: Interaction, *args, **kwargs): or interaction.user.id != interaction.guild.owner_id ): await send_error( - interaction, "You must be the server owner to use this command." + interaction, + title="🚫 Action not allowed", + description="You must be the server owner to use this command.", ) return None return await func(interaction, *args, **kwargs) diff --git a/pyproject.toml b/pyproject.toml index e6d274d..40085b7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "ModuBotDiscord" -version = "0.2.0" +version = "0.3.0" description = "Modular Discord bot framework built on top of ModuBotCore" authors = [{ name = "Endkind", email = "endkind.ender@endkind.net" }] readme = "README.md"