Skip to content

Commit

Permalink
Merge pull request #1690 from interactions-py/unstable
Browse files Browse the repository at this point in the history
5.13
  • Loading branch information
silasary authored Jun 26, 2024
2 parents a8f6fcf + cf395d1 commit 87f814f
Show file tree
Hide file tree
Showing 41 changed files with 1,522 additions and 359 deletions.
4 changes: 4 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ repos:
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
language: python
- repo: https://github.com/psf/black
rev: 24.2.0
hooks:
Expand All @@ -48,6 +49,9 @@ repos:
# name: isort Formatting
# language: python
# types: [file, python]

default_language_version:
python: python3.10
ci:
autoupdate_branch: "unstable"
autofix_prs: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ search:
- [Invite](invite)
- [Message](message)
- [Modals](modals)
- [Poll](poll)
- [Reaction](reaction)
- [Role](role)
- [Scheduled event](scheduled_event)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
::: interactions.models.discord.poll
2 changes: 1 addition & 1 deletion docs/src/Guides/01 Getting Started.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ async def on_ready():
@listen()
async def on_message_create(event):
# This event is called when a message is sent in a channel the bot can see
print(f"message received: {event.message.content}")
print(f"message received: {event.message.jump_url}")


bot.start("Put your token here")
Expand Down
71 changes: 61 additions & 10 deletions docs/src/Guides/03 Creating Commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -423,18 +423,69 @@ There are two ways to define permissions.

Multiple permissions are defined with the bitwise OR operator `|`.

### Blocking Commands in DMs
## Usable Contexts

You can also block commands in DMs. To do that, just set `dm_permission` to false.
You can control where slash commands (and other application commands) can be used using - in guilds, in DMs, and/or other private channels. By default, commands can be used in all contexts.

```py
@slash_command(
name="my_guild_only_command",
dm_permission=False,
)
async def my_command_function(ctx: SlashContext):
...
```
As with permissions, there are two ways to define the context.

=== ":one: Decorators"

```python
from interactions import contexts

@slash_command(name="my_guild_only_command")
@contexts(guild=True, bot_dm=False, private_channel=False)
async def my_command_function(ctx: SlashContext):
...
```

=== ":two: Function Definition"

```python
from interactions import ContextType

@slash_command(
name="my_command",
contexts=[ContextType.GUILD],
)
async def my_command_function(ctx: SlashContext):
...
```

## Integration Types

Applications can be installed/integrated in different ways:
- The one you are familiar with is the *guild* integration, where the application is installed in a specific guild, and so the entire guild can use the application.
- You can also install the application to a *user*, where the application can then be used by the user anywhere they desire.

By default, commands can only be used in guild integrations. Like many other properties, this can be changed.

There are two ways to define this:

=== ":one: Decorators"

```python
from interactions import integration_types

@slash_command(name="my_command")
@integration_types(guild=True, user=True)
async def my_command_function(ctx: SlashContext):
...
```

=== ":two: Function Definition"

```python
from interactions import IntegrationType

@slash_command(
name="my_command",
integration_types=[IntegrationType.GUILD_INSTALL, IntegrationType.USER_INSTALL],
)
async def my_command_function(ctx: SlashContext):
...
```

## Checks

Expand Down
30 changes: 30 additions & 0 deletions interactions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
MentionPrefix,
Missing,
MISSING,
POLL_MAX_ANSWERS,
POLL_MAX_DURATION_HOURS,
PREMIUM_GUILD_LIMITS,
SELECT_MAX_NAME_LENGTH,
SELECTS_MAX_OPTIONS,
Expand All @@ -37,6 +39,7 @@
smart_cache,
T,
T_co,
ClientT,
utils,
)
from .client import const
Expand Down Expand Up @@ -83,6 +86,7 @@
BrandColors,
BrandColours,
Buckets,
BulkBanResponse,
Button,
ButtonStyle,
CallbackObject,
Expand All @@ -104,9 +108,11 @@
ComponentContext,
ComponentType,
ConsumeRest,
contexts,
context_menu,
ContextMenu,
ContextMenuContext,
ContextType,
Converter,
cooldown,
Cooldown,
Expand Down Expand Up @@ -179,6 +185,8 @@
IDConverter,
InputText,
IntegrationExpireBehaviour,
IntegrationType,
integration_types,
Intents,
InteractionCommand,
InteractionContext,
Expand Down Expand Up @@ -214,6 +222,7 @@
MessageConverter,
MessageFlags,
MessageInteraction,
MessageInteractionMetadata,
MessageReference,
MessageType,
MFALevel,
Expand All @@ -238,6 +247,12 @@
PartialEmojiConverter,
PermissionOverwrite,
Permissions,
Poll,
PollAnswer,
PollAnswerCount,
PollLayoutType,
PollMedia,
PollResults,
PremiumTier,
PremiumType,
process_allowed_mentions,
Expand Down Expand Up @@ -403,6 +418,7 @@
"BrandColors",
"BrandColours",
"Buckets",
"BulkBanResponse",
"Button",
"ButtonStyle",
"CallbackObject",
Expand All @@ -415,6 +431,7 @@
"ChannelType",
"check",
"Client",
"ClientT",
"ClientUser",
"Color",
"COLOR_TYPES",
Expand All @@ -426,10 +443,12 @@
"ComponentType",
"ConsumeRest",
"const",
"contexts",
"context_menu",
"CONTEXT_MENU_NAME_LENGTH",
"ContextMenu",
"ContextMenuContext",
"ContextType",
"Converter",
"cooldown",
"Cooldown",
Expand Down Expand Up @@ -519,6 +538,8 @@
"IDConverter",
"InputText",
"IntegrationExpireBehaviour",
"IntegrationType",
"integration_types",
"Intents",
"InteractionCommand",
"InteractionContext",
Expand Down Expand Up @@ -558,6 +579,7 @@
"MessageConverter",
"MessageFlags",
"MessageInteraction",
"MessageInteractionMetadata",
"MessageReference",
"MessageType",
"MFALevel",
Expand All @@ -584,6 +606,14 @@
"PartialEmojiConverter",
"PermissionOverwrite",
"Permissions",
"Poll",
"PollAnswer",
"PollAnswerCount",
"PollLayoutType",
"POLL_MAX_ANSWERS",
"POLL_MAX_DURATION_HOURS",
"PollMedia",
"PollResults",
"PREMIUM_GUILD_LIMITS",
"PremiumTier",
"PremiumType",
Expand Down
4 changes: 4 additions & 0 deletions interactions/api/events/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
MessageCreate,
MessageDelete,
MessageDeleteBulk,
MessagePollVoteAdd,
MessagePollVoteRemove,
MessageReactionAdd,
MessageReactionRemove,
MessageReactionRemoveAll,
Expand Down Expand Up @@ -159,6 +161,8 @@
"MessageCreate",
"MessageDelete",
"MessageDeleteBulk",
"MessagePollVoteAdd",
"MessagePollVoteRemove",
"MessageReactionAdd",
"MessageReactionRemove",
"MessageReactionRemoveAll",
Expand Down
69 changes: 69 additions & 0 deletions interactions/api/events/discord.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ async def an_event_handler(event: ChannelCreate):
"MessageCreate",
"MessageDelete",
"MessageDeleteBulk",
"MessagePollVoteAdd",
"MessagePollVoteRemove",
"MessageReactionAdd",
"MessageReactionRemove",
"MessageReactionRemoveAll",
Expand Down Expand Up @@ -115,6 +117,7 @@ async def an_event_handler(event: ChannelCreate):
from interactions.models.discord.entitlement import Entitlement
from interactions.models.discord.guild import Guild, GuildIntegration
from interactions.models.discord.message import Message
from interactions.models.discord.poll import Poll
from interactions.models.discord.reaction import Reaction
from interactions.models.discord.role import Role
from interactions.models.discord.scheduled_event import ScheduledEvent
Expand Down Expand Up @@ -588,6 +591,72 @@ class MessageReactionRemoveEmoji(MessageReactionRemoveAll):
"""The emoji that was removed"""


@attrs.define(eq=False, order=False, hash=False, kw_only=False)
class BaseMessagePollEvent(BaseEvent):
user_id: "Snowflake_Type" = attrs.field(repr=False)
"""The ID of the user that voted"""
channel_id: "Snowflake_Type" = attrs.field(repr=False)
"""The ID of the channel the poll is in"""
message_id: "Snowflake_Type" = attrs.field(repr=False)
"""The ID of the message the poll is in"""
answer_id: int = attrs.field(repr=False)
"""The ID of the answer the user voted for"""
guild_id: "Optional[Snowflake_Type]" = attrs.field(repr=False, default=None)
"""The ID of the guild the poll is in"""

def get_message(self) -> "Optional[Message]":
"""Get the message object if it is cached"""
return self.client.cache.get_message(self.channel_id, self.message_id)

def get_user(self) -> "Optional[User]":
"""Get the user object if it is cached"""
return self.client.get_user(self.user_id)

def get_channel(self) -> "Optional[TYPE_ALL_CHANNEL]":
"""Get the channel object if it is cached"""
return self.client.get_channel(self.channel_id)

def get_guild(self) -> "Optional[Guild]":
"""Get the guild object if it is cached"""
return self.client.get_guild(self.guild_id) if self.guild_id is not None else None

def get_poll(self) -> "Optional[Poll]":
"""Get the poll object if it is cached"""
message = self.get_message()
return message.poll if message is not None else None

async def fetch_message(self) -> "Message":
"""Fetch the message the poll is in"""
return await self.client.cache.fetch_message(self.channel_id, self.message_id)

async def fetch_user(self) -> "User":
"""Fetch the user that voted"""
return await self.client.fetch_user(self.user_id)

async def fetch_channel(self) -> "TYPE_ALL_CHANNEL":
"""Fetch the channel the poll is in"""
return await self.client.fetch_channel(self.channel_id)

async def fetch_guild(self) -> "Optional[Guild]":
"""Fetch the guild the poll is in"""
return await self.client.fetch_guild(self.guild_id) if self.guild_id is not None else None

async def fetch_poll(self) -> "Poll":
"""Fetch the poll object"""
message = await self.fetch_message()
return message.poll


@attrs.define(eq=False, order=False, hash=False, kw_only=False)
class MessagePollVoteAdd(BaseMessagePollEvent):
"""Dispatched when a user votes in a poll"""


@attrs.define(eq=False, order=False, hash=False, kw_only=False)
class MessagePollVoteRemove(BaseMessagePollEvent):
"""Dispatched when a user remotes a votes in a poll"""


@attrs.define(eq=False, order=False, hash=False, kw_only=False)
class PresenceUpdate(BaseEvent):
"""A user's presence has changed."""
Expand Down
38 changes: 38 additions & 0 deletions interactions/api/events/processors/message_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,41 @@ async def _on_raw_message_delete_bulk(self, event: "RawGatewayEvent") -> None:
event.data.get("ids"),
)
)

@Processor.define()
async def _on_raw_message_poll_vote_add(self, event: "RawGatewayEvent") -> None:
"""
Process raw message poll vote add event and dispatch a processed poll vote add event.
Args:
event: raw poll vote add event
"""
self.dispatch(
events.MessagePollVoteAdd(
event.data.get("guild_id", None),
event.data["channel_id"],
event.data["message_id"],
event.data["user_id"],
event.data["option"],
)
)

@Processor.define()
async def _on_raw_message_poll_vote_remove(self, event: "RawGatewayEvent") -> None:
"""
Process raw message poll vote remove event and dispatch a processed poll vote remove event.
Args:
event: raw poll vote remove event
"""
self.dispatch(
events.MessagePollVoteRemove(
event.data.get("guild_id", None),
event.data["channel_id"],
event.data["message_id"],
event.data["user_id"],
event.data["option"],
)
)
Loading

0 comments on commit 87f814f

Please sign in to comment.