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: new message type PURCHASE_NOTIFICATION #1226

Draft
wants to merge 2 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
4 changes: 4 additions & 0 deletions changelog/1225.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Implement new :attr:`Message.type`: :attr:`MessageType.purchase_notifcation`.
- New types :class:`PurchaseNotificationInfo`, :class:`GuildProductInfo`.
- New :attr:`Message.purchase_information` attribute.
- New enum :class:`PurchaseType`.
6 changes: 6 additions & 0 deletions disnake/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"OnboardingPromptType",
"SKUType",
"EntitlementType",
"PurchaseType",
)


Expand Down Expand Up @@ -260,6 +261,7 @@ class MessageType(Enum):
guild_incident_alert_mode_disabled = 37
guild_incident_report_raid = 38
guild_incident_report_false_alarm = 39
purchase_notification = 44


class PartyType(Enum):
Expand Down Expand Up @@ -1364,6 +1366,10 @@ class EntitlementType(Enum):
application_subscription = 8


class PurchaseType(Enum):
guild_product = 0


T = TypeVar("T")


Expand Down
64 changes: 63 additions & 1 deletion disnake/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,14 @@
from .components import ActionRow, MessageComponent, _component_factory
from .embeds import Embed
from .emoji import Emoji
from .enums import ChannelType, InteractionType, MessageType, try_enum, try_enum_to_int
from .enums import (
ChannelType,
InteractionType,
MessageType,
PurchaseType,
try_enum,
try_enum_to_int,
)
from .errors import HTTPException
from .file import File
from .flags import AttachmentFlags, MessageFlags
Expand Down Expand Up @@ -64,10 +71,12 @@
from .types.member import Member as MemberPayload, UserWithMember as UserWithMemberPayload
from .types.message import (
Attachment as AttachmentPayload,
GuildProductPurchase as GuildProductPayload,
Message as MessagePayload,
MessageActivity as MessageActivityPayload,
MessageApplication as MessageApplicationPayload,
MessageReference as MessageReferencePayload,
PurchaseNotification as PurchaseNotificationPayload,
Reaction as ReactionPayload,
RoleSubscriptionData as RoleSubscriptionDataPayload,
)
Expand All @@ -86,6 +95,8 @@
"InteractionReference",
"DeletedReferencedMessage",
"RoleSubscriptionData",
"GuildProductInfo",
"PurchaseNotificationInfo",
)


Expand Down Expand Up @@ -748,6 +759,42 @@ def __init__(self, data: RoleSubscriptionDataPayload) -> None:
self.is_renewal: bool = data["is_renewal"]


class GuildProductInfo:
"""Represents the information about the guild product purchased by a user in a message
of type :attr:`MessageType.purchase_notification`.

.. versionadded:: 2.10

Attributes
----------
listing_id: :class:`int`
The ID of the listing the user purchased.
product_name: :class:`str`
The name of the product the user purchased.
"""

__slots__ = ("listing_id", "product_name")

def __init__(self, data: GuildProductPayload) -> None:
self.listing_id: int = int(data["listing_id"])
self.product_name: str = data["product_name"]


class PurchaseNotificationInfo:
"""Represents the information about a purchase made by a user in a message of type
:attr:`MessageType.purchase_notification`.

.. versionadded:: 2.10
"""

__slots__ = ("type", "guild_product")

def __init__(self, data: PurchaseNotificationPayload) -> None:
self.type: PurchaseType = try_enum(PurchaseType, data["type"])
guild_product_info = data.get("guild_product_purchase")
self.guild_product: Optional[GuildProductInfo] = (GuildProductInfo(guild_product_info) if guild_product_info is not None else None)


def flatten_handlers(cls):
prefix = len("_handle_")
handlers = [
Expand Down Expand Up @@ -894,6 +941,11 @@ class Message(Hashable):

.. versionadded:: 2.0

purchase_notification: Optional[:class:`PurchaseNotification`]
The purchase a user made if this message is of type :attr:`MessageType.purchase_notification`.

.. versionadded:: 2.10

guild: Optional[:class:`Guild`]
The guild that the message belongs to, if applicable.
"""
Expand Down Expand Up @@ -930,6 +982,7 @@ class Message(Hashable):
"activity",
"stickers",
"components",
"purchase_notification",
"guild",
"_edited_timestamp",
"_role_subscription_data",
Expand Down Expand Up @@ -986,6 +1039,9 @@ def __init__(
for d in data.get("components", [])
]

purchase_notif = data.get("purchase_notification")
self.purchase_notification: Optional[PurchaseNotificationInfo] = PurchaseNotificationInfo(purchase_notif) if purchase_notif is not None else None

inter_payload = data.get("interaction")
inter = (
None if inter_payload is None else InteractionReference(state=state, data=inter_payload)
Expand Down Expand Up @@ -1538,6 +1594,12 @@ def system_content(self) -> Optional[str]:
if self.type is MessageType.guild_incident_report_false_alarm:
return f"{self.author.name} resolved an Activity Alert."

if self.type is MessageType.purchase_notification and self.purchase_notification is not None:
if self.purchase_notification.guild_product is not None:
return f"{self.author.name} has purchased {self.purchase_notification.guild_product.product_name}!"

# TODO: maybe more purcahse notification types will be added?

# in the event of an unknown or unsupported message type, we return nothing
return None

Expand Down
16 changes: 15 additions & 1 deletion disnake/types/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,21 @@ class RoleSubscriptionData(TypedDict):
is_renewal: bool


class GuildProductPurchase(TypedDict):
listing_id: Snowflake
product_name: str


PurchaseType = Literal[0]


class PurchaseNotification(TypedDict):
type: PurchaseType
guild_product_purchase: NotRequired[GuildProductPurchase]


# fmt: off
MessageType = Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 36, 37, 38, 39]
MessageType = Literal[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 36, 37, 38, 39, 44]
# fmt: on


Expand Down Expand Up @@ -114,6 +127,7 @@ class Message(TypedDict):
sticker_items: NotRequired[List[StickerItem]]
position: NotRequired[int]
role_subscription_data: NotRequired[RoleSubscriptionData]
purchase_notification: NotRequired[PurchaseNotification]

# specific to MESSAGE_CREATE/MESSAGE_UPDATE events
guild_id: NotRequired[Snowflake]
Expand Down
29 changes: 29 additions & 0 deletions docs/api/messages.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,22 @@ RoleSubscriptionData
.. autoclass:: RoleSubscriptionData
:members:

GuildProductInfo
~~~~~~~~~~~~~~~~

.. attributetable:: GuildProductInfo

.. autoclass:: GuildProductInfo
:members:

PurchaseNotificationInfo
~~~~~~~~~~~~~~~~~~~~~~~~

.. attributetable:: PurchaseNotificationInfo

.. autoclass:: PurchaseNotificationInfo
:members:

RawTypingEvent
~~~~~~~~~~~~~~

Expand Down Expand Up @@ -183,6 +199,14 @@ Enumerations
MessageType
~~~~~~~~~~~

.. class:: PurchaseType

Specifies the type of purchase for :class:`PurchaseNotificationInfo`.

.. attribute:: guild_product

The purchase is of a product from a guild.

.. class:: MessageType

Specifies the type of :class:`Message`. This is used to denote if a message
Expand Down Expand Up @@ -367,6 +391,11 @@ MessageType

The system message denoting that a raid report was a false alarm.

.. versionadded:: 2.10
.. attribute:: purchase_notification

The system message denoting that a user has purchased a product.

.. versionadded:: 2.10

Events
Expand Down
Loading