|  | 
| 1 | 1 | from typing import TYPE_CHECKING | 
| 2 | 2 | 
 | 
| 3 | 3 | import interactions.api.events as events | 
| 4 |  | -from interactions.models import PartialEmoji, Reaction | 
|  | 4 | +from interactions.models import PartialEmoji, Reaction, Message, Permissions | 
| 5 | 5 | 
 | 
| 6 | 6 | from ._template import EventMixinTemplate, Processor | 
| 7 | 7 | 
 | 
|  | 
| 12 | 12 | 
 | 
| 13 | 13 | 
 | 
| 14 | 14 | class ReactionEvents(EventMixinTemplate): | 
|  | 15 | +    async def _check_message_fetch_permissions(self, channel_id: str, guild_id: str | None) -> bool: | 
|  | 16 | +        """ | 
|  | 17 | +        Check if the bot has permissions to fetch a message in the given channel. | 
|  | 18 | +
 | 
|  | 19 | +        Args: | 
|  | 20 | +            channel_id: The ID of the channel to check | 
|  | 21 | +            guild_id: The ID of the guild, if any | 
|  | 22 | +
 | 
|  | 23 | +        Returns: | 
|  | 24 | +            bool: True if the bot has permission to fetch messages, False otherwise | 
|  | 25 | +
 | 
|  | 26 | +        """ | 
|  | 27 | +        if not guild_id:  # DMs always have permission | 
|  | 28 | +            return True | 
|  | 29 | + | 
|  | 30 | +        channel = await self.cache.fetch_channel(channel_id) | 
|  | 31 | +        if not channel: | 
|  | 32 | +            return False | 
|  | 33 | + | 
|  | 34 | +        bot_member = channel.guild.me | 
|  | 35 | +        ctx_perms = channel.permissions_for(bot_member) | 
|  | 36 | +        return Permissions.READ_MESSAGE_HISTORY in ctx_perms | 
|  | 37 | + | 
| 15 | 38 |     async def _handle_message_reaction_change(self, event: "RawGatewayEvent", add: bool) -> None: | 
| 16 | 39 |         if member := event.data.get("member"): | 
| 17 | 40 |             author = self.cache.place_member_data(event.data.get("guild_id"), member) | 
| @@ -53,11 +76,27 @@ async def _handle_message_reaction_change(self, event: "RawGatewayEvent", add: b | 
| 53 | 76 |                 message.reactions.append(reaction) | 
| 54 | 77 | 
 | 
| 55 | 78 |         else: | 
| 56 |  | -            message = await self.cache.fetch_message(event.data.get("channel_id"), event.data.get("message_id")) | 
| 57 |  | -            for r in message.reactions: | 
| 58 |  | -                if r.emoji == emoji: | 
| 59 |  | -                    reaction = r | 
| 60 |  | -                    break | 
|  | 79 | +            guild_id = event.data.get("guild_id") | 
|  | 80 | +            channel_id = event.data.get("channel_id") | 
|  | 81 | + | 
|  | 82 | +            if await self._check_message_fetch_permissions(channel_id, guild_id): | 
|  | 83 | +                message = await self.cache.fetch_message(channel_id, event.data.get("message_id")) | 
|  | 84 | +                for r in message.reactions: | 
|  | 85 | +                    if r.emoji == emoji: | 
|  | 86 | +                        reaction = r | 
|  | 87 | +                        break | 
|  | 88 | + | 
|  | 89 | +            if not message:  # otherwise construct skeleton message with no reactions | 
|  | 90 | +                message = Message.from_dict( | 
|  | 91 | +                    { | 
|  | 92 | +                        "id": event.data.get("message_id"), | 
|  | 93 | +                        "channel_id": channel_id, | 
|  | 94 | +                        "guild_id": guild_id, | 
|  | 95 | +                        "reactions": [], | 
|  | 96 | +                    }, | 
|  | 97 | +                    self, | 
|  | 98 | +                ) | 
|  | 99 | + | 
| 61 | 100 |         if add: | 
| 62 | 101 |             self.dispatch(events.MessageReactionAdd(message=message, emoji=emoji, author=author, reaction=reaction)) | 
| 63 | 102 |         else: | 
|  | 
0 commit comments