Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: use the guild data provided on interactions #1236

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/1235.breaking.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:attr:`Interaction.guild` is now a :class:`Guild` instance if the guild could not be found in cache.
29 changes: 29 additions & 0 deletions disnake/guild.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
from .app_commands import APIApplicationCommand
from .asset import AssetBytes
from .automod import AutoModTriggerMetadata
from .interactions import Interaction
from .permissions import Permissions
from .state import ConnectionState
from .template import Template
Expand All @@ -107,6 +108,7 @@
Guild as GuildPayload,
GuildFeature,
MFALevel,
PartialGuild as PartialGuildPayload,
)
from .types.integration import IntegrationType
from .types.role import CreateRole as CreateRolePayload
Expand Down Expand Up @@ -4963,6 +4965,33 @@ async def onboarding(self) -> Onboarding:
return Onboarding(data=data, guild=self)


class PartialInteractionGuild(Guild):
"""Reimplementation of :class:`Guild` for guilds interactions."""

def __init__(
self,
*,
state: ConnectionState,
data: PartialGuildPayload,
interaction: Interaction,
) -> None:
super().__init__(state=state, data=data)
# init the fake data
self._add_role(
Role(
state=state,
guild=self,
data={"id": self.id, "name": "@everyone"}, # type: ignore
)
)
self._add_channel(interaction.channel) # type: ignore
# honestly we cannot set me, because we do not necessarily have a user in the guild

@property
def me(self) -> Any:
return self._state.user


PlaceholderID = NewType("PlaceholderID", int)


Expand Down
49 changes: 34 additions & 15 deletions disnake/interactions/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
NotFound,
)
from ..flags import MessageFlags
from ..guild import Guild
from ..guild import Guild, PartialInteractionGuild
from ..i18n import Localized
from ..member import Member
from ..message import Attachment, Message
Expand Down Expand Up @@ -75,6 +75,7 @@
from ..poll import Poll
from ..state import ConnectionState
from ..types.components import Modal as ModalPayload
from ..types.guild import PartialGuild as PartialGuildPayload
from ..types.interactions import (
ApplicationCommandOptionChoice as ApplicationCommandOptionChoicePayload,
Interaction as InteractionPayload,
Expand Down Expand Up @@ -183,6 +184,7 @@ class Interaction(Generic[ClientT]):
"_state",
"_session",
"_original_response",
"_guild",
"_cs_response",
"_cs_followup",
"_cs_me",
Expand All @@ -203,6 +205,7 @@ def __init__(self, *, data: InteractionPayload, state: ConnectionState) -> None:
self.version: int = data["version"]
self.application_id: int = int(data["application_id"])
self.guild_id: Optional[int] = utils._get_as_snowflake(data, "guild_id")
self._guild: Optional[PartialGuildPayload] = data.get("guild")

self.locale: Locale = try_enum(Locale, data["locale"])
guild_locale = data.get("guild_locale")
Expand All @@ -216,18 +219,12 @@ def __init__(self, *, data: InteractionPayload, state: ConnectionState) -> None:
self.author: Union[User, Member] = MISSING

guild_fallback: Optional[Union[Guild, Object]] = None
if self.guild_id:
guild_fallback = self.guild or Object(self.guild_id)

if guild_fallback and (member := data.get("member")):
self.author = (
isinstance(guild_fallback, Guild)
and guild_fallback.get_member(int(member["user"]["id"]))
or Member(
state=self._state,
guild=guild_fallback, # type: ignore # may be `Object`
data=member,
)

if self.guild_id and (guild_fallback := self.guild) and (member := data.get("member")):
self.author = guild_fallback.get_member(int(member["user"]["id"])) or Member(
state=self._state,
guild=guild_fallback,
data=member,
)
self._permissions = int(member.get("permissions", 0))
elif user := data.get("user"):
Expand Down Expand Up @@ -263,8 +260,30 @@ def user(self) -> Union[User, Member]:

@property
def guild(self) -> Optional[Guild]:
"""Optional[:class:`Guild`]: The guild the interaction was sent from."""
return self._state._get_guild(self.guild_id)
"""Optional[:class:`Guild`]: The guild the interaction was sent from.

.. versionchanged:: 2.10
Returns a :class:`Guild` object when the guild could not be resolved from cache.
This object is created from the data provided by Discord, but it is not complete.
The only populated attributes are:
- :attr:`Guild.id`
- :attr:`Guild.preferred_locale`
- :attr:`Guild.features`
"""
if self.guild_id is None:
return None

guild = self._state._get_guild(self.guild_id)
if guild:
return guild
if self._guild is None:
return None

# create a guild mash
# honestly we should cache this for the duration of the interaction
# but not if we fetch it from the cache, just the result of this creation
guild = PartialInteractionGuild(data=self._guild, state=self._state, interaction=self)
return guild

@utils.cached_slot_property("_cs_me")
def me(self) -> Union[Member, ClientUser]:
Expand Down
4 changes: 4 additions & 0 deletions disnake/types/guild.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ class Guild(_BaseGuildPreview):
guild_scheduled_events: NotRequired[List[GuildScheduledEvent]]


class PartialGuild(Guild, total=False):
pass


class InviteGuild(Guild, total=False):
welcome_screen: WelcomeScreen

Expand Down
2 changes: 2 additions & 0 deletions disnake/types/interactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from .components import Component, Modal
from .embed import Embed
from .entitlement import Entitlement
from .guild import PartialGuild
from .i18n import LocalizationDict
from .member import Member, MemberWithUser
from .role import Role
Expand Down Expand Up @@ -265,6 +266,7 @@ class _BaseUserInteraction(_BaseInteraction):
locale: str
app_permissions: NotRequired[str]
guild_id: NotRequired[Snowflake]
guild: NotRequired[PartialGuild]
guild_locale: NotRequired[str]
entitlements: NotRequired[List[Entitlement]]
# one of these two will always exist, according to docs
Expand Down
Loading