From 65f3f54ee7ac3fd0e5b92dd52802271c77fc637b Mon Sep 17 00:00:00 2001 From: Enoki Date: Thu, 21 Dec 2023 00:50:01 +0300 Subject: [PATCH] feat: make reactions usable --- voltage/internals/ws.py | 21 ++++++++++++++++++++- voltage/message.py | 31 +++++++++++++++++++++---------- voltage/types/ws.py | 6 ++++++ 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/voltage/internals/ws.py b/voltage/internals/ws.py index 4d73332..1c63e1b 100644 --- a/voltage/internals/ws.py +++ b/voltage/internals/ws.py @@ -205,8 +205,22 @@ async def handle_messagereact(self, payload: OnMessageReactPayload): message = await self.cache.fetch_message(payload["channel_id"], payload["id"]) user_id = payload["user_id"] emoji_id = payload["emoji_id"] + message.interactions.reactions.setdefault(payload["emoji_id"], []).append( + self.cache.get_user(payload["user_id"]) + ) await self.dispatch("message_react", message, user_id, emoji_id) + async def handle_messageremovereaction( + self, payload: OnMessageRemoveReactionPayload + ): + """ + Handles the message remove reaction event. + """ + message = await self.cache.fetch_message(payload["channel_id"], payload["id"]) + emoji_id = payload["emoji_id"] + message.interactions.reactions[payload["emoji_id"]] = [] + await self.dispatch("message_react", message, emoji_id) + async def handle_messageunreact(self, payload: OnMessageReactPayload): """ Handles the message unreact event. @@ -214,6 +228,9 @@ async def handle_messageunreact(self, payload: OnMessageReactPayload): message = await self.cache.fetch_message(payload["channel_id"], payload["id"]) user_id = payload["user_id"] emoji_id = payload["emoji_id"] + message.interactions.reactions.setdefault(payload["emoji_id"], []).remove( + self.cache.get_user(payload["user_id"]) + ) await self.dispatch("message_unreact", message, user_id, emoji_id) async def handle_channelcreate(self, payload: OnChannelCreatePayload): @@ -323,7 +340,9 @@ async def handle_servermemberjoin(self, payload: OnServerMemberJoinPayload): self.cache.get_user(payload["user"]) except KeyError: self.cache.add_user(await self.http.fetch_user(payload["user"])) - member = self.cache.add_member(payload["id"], {"_id": {"server": payload["id"], "user": payload["user"]}}) + member = self.cache.add_member( + payload["id"], {"_id": {"server": payload["id"], "user": payload["user"]}} + ) await self.dispatch("member_join", member) async def handle_memberleave(self, payload: OnServerMemberLeavePayload): diff --git a/voltage/message.py b/voltage/message.py index aa32f4e..94f176a 100644 --- a/voltage/message.py +++ b/voltage/message.py @@ -2,7 +2,7 @@ from asyncio import sleep from datetime import datetime -from typing import TYPE_CHECKING, List, NamedTuple, Optional, Union +from typing import TYPE_CHECKING, Dict, List, NamedTuple, Optional, Union from ulid import ULID @@ -74,25 +74,28 @@ def to_dict(self) -> dict: return data -class MessageInteractions(NamedTuple): +class MessageInteractions: """A named tuple that represents a message's interactions. Attributes ---------- - reactions: Optional[:class:`list[:class:`str`]`] + reactions: Dict[:class:`str`, List[:class:`User`]] The reactions always below this messsage. restrict_reactions: Optional[:class:`bool`] Only allow reactions specified. """ - reactions: Optional[list[str]] = None - restrict_reactions: Optional[bool] = None + def __init__(self): + self.reactions: Dict[str, List[User]] = {} + self.restrict_reactions = False def to_dict(self) -> dict: """Returns a dictionary representation of the message interactions.""" return { "reactions": self.reactions if self.reactions else None, - "restrict_reactions": self.restrict_reactions if self.restrict_reactions is not None else None, + "restrict_reactions": self.restrict_reactions + if self.restrict_reactions is not None + else None, } @@ -135,6 +138,7 @@ class Message: "reply_ids", "replies", "cache", + "interactions", ) def __init__(self, data: MessagePayload, cache: CacheHandler): @@ -144,12 +148,15 @@ def __init__(self, data: MessagePayload, cache: CacheHandler): self.content = data.get("content") self.attachments = [Asset(a, cache.http) for a in data.get("attachments", [])] self.embeds = [create_embed(e, cache.http) for e in data.get("embeds", [])] + self.interactions = MessageInteractions() self.channel = cache.get_channel(data["channel"]) self.server = self.channel.server self.author = ( - cache.get_member(self.server.id, data["author"]) if self.server else cache.get_user(data["author"]) + cache.get_member(self.server.id, data["author"]) + if self.server + else cache.get_user(data["author"]) ) if masquerade := data.get("masquerade"): @@ -166,7 +173,7 @@ def __init__(self, data: MessagePayload, cache: CacheHandler): self.edited_at = None self.reply_ids = data.get("replies", []) - self.replies = [] + self.replies: List[Message] = [] for i in self.reply_ids: try: self.replies.append(cache.get_message(i)) @@ -201,14 +208,18 @@ async def edit( The new embeds of the message. """ if content is None and embed is None and embeds is None: - raise ValueError("You must provide at least one of the following: content, embed, embeds") + raise ValueError( + "You must provide at least one of the following: content, embed, embeds" + ) if embed: embeds = [embed] content = str(content) if content else None - await self.cache.http.edit_message(self.channel.id, self.id, content=content, embeds=embeds) + await self.cache.http.edit_message( + self.channel.id, self.id, content=content, embeds=embeds + ) async def delete(self, *, delay: Optional[float] = None): """Deletes the message.""" diff --git a/voltage/types/ws.py b/voltage/types/ws.py index 5acab1c..3f4c241 100644 --- a/voltage/types/ws.py +++ b/voltage/types/ws.py @@ -60,6 +60,12 @@ class OnMessageReactPayload(BasePayload): emoji_id: str +class OnMessageRemoveReactionPayload(BasePayload): + id: str + channel_id: str + emoji_id: str + + class OnChannelCreatePayload_SavedMessage(BasePayload, SavedMessagePayload): pass