Added handle_reaction().
authorCMDR furrycat <elite@furrycat.net>
Sat, 20 Mar 2021 16:36:11 +0000 (17:36 +0100)
committerCMDR furrycat <elite@furrycat.net>
Sat, 20 Mar 2021 16:36:11 +0000 (17:36 +0100)
app.py
bot.py
plugins/__init__.py

diff --git a/app.py b/app.py
index bd225d4..2f3dd09 100644 (file)
--- a/app.py
+++ b/app.py
@@ -373,6 +373,59 @@ async def on_message(message):
   if not result:
     await process_module(message, command, raw)
 
+async def on_reaction(reaction, event_type, emoji = None):
+  message = None
+  channel = bot.get_channel(reaction.channel_id)
+  if not channel:
+    user = bot.get_user(reaction.user_id)
+    if not user:
+      log.error("Can't get channel with ID {}.  Maybe it is a DMChannel...".format(reaction.channel_id))
+      return
+    message = await user.fetch_message(reaction.message_id)
+    if message:
+      channel = message.channel
+  try:
+    if not message:
+      message = await channel.fetch_message(reaction.message_id)
+    if message.author.id != client.user.id:
+      return
+  except discord.NotFound:
+    log.error('No message with ID {} found in channel {}!'.format(reaction.message_id, channel))
+    return
+  except discord.Forbidden:
+    log.error("We don't have access to message with ID {} in channel {}!".format(reaction.message_id, channel))
+    return
+  except:
+    log.error('Failed to retrieve message with ID {} from channel {}!'.format(reaction.message_id, channel))
+    return
+
+  server = bot.get_server(reaction.guild_id) if reaction.guild_id is not None else None
+  if server:
+    member = server.get_member(reaction.user_id)
+  else:
+    member = None
+
+  if not emoji and event_type in ['REACTION_ADD', 'REACTION_REMOVE']:
+    emoji = reaction.emoji
+
+  await plugins.handle_reaction(reaction, message = message, member = member, channel = channel, server = server, event_type = event_type, emoji = emoji)
+
+@client.event
+async def on_raw_reaction_add(reaction):
+  await on_reaction(reaction, 'REACTION_ADD')
+
+@client.event
+async def on_raw_reaction_remove(reaction):
+  await on_reaction(reaction, 'REACTION_REMOVE')
+
+@client.event
+async def on_raw_reaction_clear(reaction):
+  await on_reaction(reaction, 'REACTION_CLEAR')
+
+@client.event
+async def on_raw_reaction_clear_emoji(reaction):
+  await on_reaction(reaction, event_type = 'REACTION_CLEAR_EMOJI', emoji = reaction.emoji)
+
 @client.event
 async def on_member_join(member):
   await plugins.on_member_join(member)
diff --git a/bot.py b/bot.py
index 3028146..995e01f 100644 (file)
--- a/bot.py
+++ b/bot.py
@@ -179,6 +179,9 @@ def get_server(id):
 def get_channel(id):
   return client.get_channel(snowflake(id))
 
+def get_user(id):
+  return client.get_user(snowflake(id))
+
 def get_message_servers(message, allow_private = False):
   servers = []
   if is_private(message.channel):
index 4cd28c1..02f12e2 100644 (file)
@@ -5,6 +5,8 @@ import logging
 import os
 from enum import Enum
 
+import bot
+
 log = logging.getLogger('plugins')
 
 class PluginCommand(Enum):
@@ -21,6 +23,7 @@ class Plugins(object):
       'on_typing',
       'handle_command',
       'handle_help',
+      'handle_reaction',
       'eddn_message',
       'non_command_message',
       'not_our_message'
@@ -170,6 +173,18 @@ class Plugins(object):
         log.debug('Plugin {} handled command {}.'.format(name, command))
         continue
 
+  async def handle_reaction(self, reaction, message, member, channel, server, event_type, emoji):
+    handled = []
+    args = [reaction]
+    for name in self.method_cache('handle_reaction'):
+      asyncio.ensure_future(self.call_coroutine(name, 'handle_reaction', reaction, message, member, channel, server, event_type, emoji))
+      handled.append(name)
+    emoji_name = emoji.name if emoji else 'unknown'
+    if handled:
+      log.info('{} "{}" on message {} in channel {} delegated to plugins: {}'.format(event_type, emoji_name, message.id, channel if bot.is_private(channel) else channel.name, ', '.join(handled)))
+    else:
+      log.info('Unhandled {} "{}" on message {} in channel {}.'.format(event_type, emoji_name, message.id, channel if bot.is_private(channel) else channel.name))
+
   async def non_command_message(self, message):
     for name in self.method_cache('non_command_message'):
       asyncio.ensure_future(self.call_coroutine(name, 'non_command_message', message))