|
| 1 | +from __future__ import annotations |
| 2 | + |
1 | 3 | import datetime
|
2 | 4 | import typing
|
| 5 | +from typing import TYPE_CHECKING |
3 | 6 | from warnings import warn
|
4 | 7 |
|
5 | 8 | import discord
|
|
9 | 12 | from . import error, http, model
|
10 | 13 | from .dpy_overrides import ComponentMessage
|
11 | 14 |
|
| 15 | +if TYPE_CHECKING: # circular import sucks for typehinting |
| 16 | + from . import client |
| 17 | + |
12 | 18 |
|
13 | 19 | class InteractionContext:
|
14 | 20 | """
|
@@ -114,6 +120,25 @@ def channel(self) -> typing.Optional[typing.Union[discord.TextChannel, discord.D
|
114 | 120 | """
|
115 | 121 | return self.bot.get_channel(self.channel_id)
|
116 | 122 |
|
| 123 | + @property |
| 124 | + def voice_client(self) -> typing.Optional[discord.VoiceProtocol]: |
| 125 | + """ |
| 126 | + VoiceClient instance of the command invoke. If the command was invoked in DM, then it is ``None``. |
| 127 | + If the bot is not connected to any Voice/Stage channels, then it is ``None``. |
| 128 | +
|
| 129 | + :return: Optional[discord.VoiceProtocol] |
| 130 | + """ |
| 131 | + return self.guild.voice_client if self.guild else None |
| 132 | + |
| 133 | + @property |
| 134 | + def me(self) -> typing.Union[discord.Member, discord.ClientUser]: |
| 135 | + """ |
| 136 | + Bot member instance of the command invoke. If the command was invoked in DM, then it is ``discord.ClientUser``. |
| 137 | +
|
| 138 | + :return: Union[discord.Member, discord.ClientUser] |
| 139 | + """ |
| 140 | + return self.guild.me if self.guild != None else self.bot.user |
| 141 | + |
117 | 142 | async def defer(self, hidden: bool = False):
|
118 | 143 | """
|
119 | 144 | 'Defers' the response, showing a loading state to the user
|
@@ -256,6 +281,64 @@ async def send(
|
256 | 281 | else:
|
257 | 282 | return resp
|
258 | 283 |
|
| 284 | + async def reply( |
| 285 | + self, |
| 286 | + content: str = "", |
| 287 | + *, |
| 288 | + embed: discord.Embed = None, |
| 289 | + embeds: typing.List[discord.Embed] = None, |
| 290 | + tts: bool = False, |
| 291 | + file: discord.File = None, |
| 292 | + files: typing.List[discord.File] = None, |
| 293 | + allowed_mentions: discord.AllowedMentions = None, |
| 294 | + hidden: bool = False, |
| 295 | + delete_after: float = None, |
| 296 | + components: typing.List[dict] = None, |
| 297 | + ) -> model.SlashMessage: |
| 298 | + """ |
| 299 | + Sends response of the interaction. This is currently an alias of the ``.send()`` method. |
| 300 | +
|
| 301 | + .. warning:: |
| 302 | + - Since Release 1.0.9, this is completely changed. If you are migrating from older version, please make sure to fix the usage. |
| 303 | + - You can't use both ``embed`` and ``embeds`` at the same time, also applies to ``file`` and ``files``. |
| 304 | + - If you send files in the initial response, this will defer if it's not been deferred, and then PATCH with the message |
| 305 | +
|
| 306 | + :param content: Content of the response. |
| 307 | + :type content: str |
| 308 | + :param embed: Embed of the response. |
| 309 | + :type embed: discord.Embed |
| 310 | + :param embeds: Embeds of the response. Maximum 10. |
| 311 | + :type embeds: List[discord.Embed] |
| 312 | + :param tts: Whether to speak message using tts. Default ``False``. |
| 313 | + :type tts: bool |
| 314 | + :param file: File to send. |
| 315 | + :type file: discord.File |
| 316 | + :param files: Files to send. |
| 317 | + :type files: List[discord.File] |
| 318 | + :param allowed_mentions: AllowedMentions of the message. |
| 319 | + :type allowed_mentions: discord.AllowedMentions |
| 320 | + :param hidden: Whether the message is hidden, which means message content will only be seen to the author. |
| 321 | + :type hidden: bool |
| 322 | + :param delete_after: If provided, the number of seconds to wait in the background before deleting the message we just sent. If the deletion fails, then it is silently ignored. |
| 323 | + :type delete_after: float |
| 324 | + :param components: Message components in the response. The top level must be made of ActionRows. |
| 325 | + :type components: List[dict] |
| 326 | + :return: Union[discord.Message, dict] |
| 327 | + """ |
| 328 | + |
| 329 | + return await self.send( |
| 330 | + content=content, |
| 331 | + embed=embed, |
| 332 | + embeds=embeds, |
| 333 | + tts=tts, |
| 334 | + file=file, |
| 335 | + files=files, |
| 336 | + allowed_mentions=allowed_mentions, |
| 337 | + hidden=hidden, |
| 338 | + delete_after=delete_after, |
| 339 | + components=components, |
| 340 | + ) |
| 341 | + |
259 | 342 |
|
260 | 343 | class SlashContext(InteractionContext):
|
261 | 344 | """
|
@@ -285,6 +368,30 @@ def __init__(
|
285 | 368 |
|
286 | 369 | super().__init__(_http=_http, _json=_json, _discord=_discord, logger=logger)
|
287 | 370 |
|
| 371 | + @property |
| 372 | + def slash(self) -> client.SlashCommand: |
| 373 | + """ |
| 374 | + Returns the associated SlashCommand object created during Runtime. |
| 375 | +
|
| 376 | + :return: client.SlashCommand |
| 377 | + """ |
| 378 | + return self.bot.slash # noqa |
| 379 | + |
| 380 | + @property |
| 381 | + def cog(self) -> typing.Optional[commands.Cog]: |
| 382 | + """ |
| 383 | + Returns the cog associated with the command invoked, if any. |
| 384 | +
|
| 385 | + :return: Optional[commands.Cog] |
| 386 | + """ |
| 387 | + |
| 388 | + cmd_obj = self.slash.commands[self.command] |
| 389 | + |
| 390 | + if isinstance(cmd_obj, (model.CogBaseCommandObject, model.CogSubcommandObject)): |
| 391 | + return cmd_obj.cog |
| 392 | + else: |
| 393 | + return None |
| 394 | + |
288 | 395 |
|
289 | 396 | class ComponentContext(InteractionContext):
|
290 | 397 | """
|
|
0 commit comments