1
votes

I program a discord bot that gives users a role when they react with an emoji under a message. (Reaction Role)

If I create a reaction role with the command !reactadd, then the bot saves it and I can delete the entry in the database again with the command !reactremove.

But if a user reacts with the emoji under the message, then the user doesn't get the role.

Instead, I get the following error message:

Ignoring exception in on_raw_reaction_add
Traceback (most recent call last):
  File "C:\Users\Kai\AppData\Local\Programs\Python\Python37-32\lib\site-packages\discord\client.py", line 270, in _run_event
    await coro(*args, **kwargs)
  File "E:\dev\discord_bot\cogs\reactrole.py", line 24, in on_raw_reaction_add
    role = discord.utils.get(guild.roles, id=int(result[1]['role']))
IndexError: list index out of range

The same problem exists for lines 34, 52 and 62. The bot doesn't find the database entry. And I don't know why.

the complete source code:

import re

import discord
from discord.ext import commands


class Reactrole(commands.Cog, name='Reactrole'):
    def __init__(self, bot):
        self.bot = bot

    @commands.Cog.listener()
    async def on_raw_reaction_add(self, reaction):
        guild = self.bot.get_guild(reaction.guild_id)
        user = guild.get_member(reaction.user_id)
        if user == self.bot.user:
            return
        elif not user == self.bot.user:
            if '<:' in str(reaction.emoji):
                guild_id = str(reaction.guild_id)
                message_id = str(reaction.message_id)
                emoji_id = str(reaction.emoji.id)
                result = await self.bot.pg_con.fetch("SELECT emoji, role, message_id, channel_id FROM reactrole WHERE guild_id = $1 and message_id = $2 and emoji = $3", guild_id, message_id, emoji_id)
                if result:
                    role = discord.utils.get(guild.roles, id=int(result[1]['role']))
                    await user.add_roles(role)
                else:
                    return
            elif '<:' not in str(reaction.emoji):
                guild_id = str(reaction.guild_id)
                message_id = str(reaction.message_id)
                emoji_id = str(reaction.emoji)
                result = await self.bot.pg_con.fetch("SELECT emoji, role, message_id, channel_id FROM reactrole WHERE guild_id = $1 and message_id = $2 and emoji = $3", guild_id, message_id, emoji_id)
                if result:
                    role = discord.utils.get(guild.roles, id=int(result[1]['role']))
                    await user.add_roles(role)
                else:
                    return

    @commands.Cog.listener()
    async def on_raw_reaction_remove(self, reaction):
        guild = self.bot.get_guild(reaction.guild_id)
        user = guild.get_member(reaction.user_id)
        if user == self.bot.user:
            return
        elif not user == self.bot.user:
            if '<:' in str(reaction.emoji):
                guild_id = str(reaction.guild_id)
                message_id = str(reaction.message_id)
                emoji_id = str(reaction.emoji.id)
                result = await self.bot.pg_con.fetch("SELECT emoji, role, message_id, channel_id FROM reactrole WHERE guild_id = $1 and message_id = $2 and emoji = $3", guild_id, message_id, emoji_id)
                if result:
                    role = discord.utils.get(guild.roles, id=int(result[1]['role']))
                    await user.remove_roles(role)
                else:
                    return
            elif '<:' not in str(reaction.emoji):
                guild_id = str(reaction.guild_id)
                message_id = str(reaction.message_id)
                emoji_id = str(reaction.emoji)
                result = await self.bot.pg_con.fetch("SELECT emoji, role, message_id, channel_id FROM reactrole WHERE guild_id = $1 and message_id = $2 and emoji = $3", guild_id, message_id, emoji_id)
                if result:
                    role = discord.utils.get(guild.roles, id=int(result[1]['role']))
                    await user.remove_roles(role)
                else:
                    return

    @commands.command()
    @commands.has_permissions(administrator=True)
    async def reactadd(self, ctx, channel: discord.TextChannel, messageid, emoji, role: discord.Role):
        guild_id = str(ctx.guild.id)
        message_id = str(messageid)
        role_id = str(role.id)
        channel_id = str(channel.id)
        emoji_id = str(emoji)
        result = await self.bot.pg_con.fetch("SELECT emoji, role, message_id, channel_id FROM reactrole WHERE guild_id = $1 and message_id = $2", guild_id, message_id)
        if '<:' in emoji:
            emm = re.sub(':.*?:', '', emoji).strip('<>')
            if not result:
                await self.bot.pg_con.execute('INSERT INTO reactrole(emoji, role, message_id, channel_id, guild_id) VALUES($1, $2, $3, $4, $5)', emm, role_id, message_id, channel_id, guild_id)
                msg = await channel.fetch_message(message_id)
                em = self.bot.get_emoji(int(emm))
                await msg.add_reaction(em)
                await ctx.send(embed=discord.Embed(color=discord.Color.green(), description=f"Reactrole wurde erfolgreich für die Rolle {role.mention} eingerichtet!"))
            elif result:
                if not emm in str(result[0]['emoji']) and role_id in str(result[1]['role']):
                    await self.bot.pg_con.execute('INSERT INTO reactrole(emoji, role, message_id, channel_id, guild_id) VALUES($1, $2, $3, $4, $5)', emm, role_id, message_id, channel_id, guild_id)
                    msg = await channel.fetch_message(message_id)
                    em = self.bot.get_emoji(int(emm))
                    await msg.add_reaction(em)
                    await ctx.send(embed=discord.Embed(color=discord.Color.green(), description=f"Reactrole wurde erfolgreich für die Rolle {role.mention} eingerichtet!"))
                else:
                    await ctx.send(embed=discord.Embed(color=discord.Color.red(), description=f'Der React {emoji} oder die Rolle {role.mention} existieren bereits als Reactrole an dieser Nachricht!'))
        elif '<:' not in emoji:
            if not result:
                await self.bot.pg_con.execute('INSERT INTO reactrole(emoji, role, message_id, channel_id, guild_id) VALUES($1, $2, $3, $4, $5)', emoji_id, role_id, message_id, channel_id, guild_id)
                msg = await channel.fetch_message(message_id)
                await msg.add_reaction(emoji)
                await ctx.send(embed=discord.Embed(color=discord.Color.green(), description=f"Reactrole wurde erfolgreich für die Rolle {role.mention} eingerichtet!"))
            elif result:
                if not emoji_id in str(result[0]['emoji']) and role_id in str(result[1]['role']):
                    await self.bot.pg_con.execute('INSERT INTO reactrole(emoji, role, message_id, channel_id, guild_id) VALUES($1, $2, $3, $4, $5)', emoji_id, role_id, message_id, channel_id, guild_id)
                    msg = await channel.fetch_message(message_id)
                    await msg.add_reaction(emoji)
                    await ctx.send(embed=discord.Embed(color=discord.Color.green(), description=f"Reactrole wurde erfolgreich für die Rolle {role.mention} eingerichtet!"))
                else:
                    await ctx.send(embed=discord.Embed(color=discord.Color.red(), description=f'Der React {emoji} oder die Rolle {role.mention} existieren bereits als Reactrole an dieser Nachricht!'))

    @commands.command()
    @commands.has_permissions(administrator=True)
    async def reactremove(self, ctx, messageid, emoji):
        guild_id = str(ctx.guild.id)
        message_id = str(messageid)
        emoji_id = str(emoji)
        if '<:' in emoji:
            emm = re.sub(':.*?:', '', emoji).strip('<>')
            result = await self.bot.pg_con.fetch("SELECT emoji, role, message_id, channel_id FROM reactrole WHERE guild_id = $1 and message_id = $2 and emoji = $3", guild_id, message_id, emm)
            if not result:
                await ctx.send(embed=discord.Embed(color=discord.Color.red(), description=f'Diese Reaction wurde nicht an der Nachricht gefunden!'))
            elif emm in str(result[0]['emoji']):
                await self.bot.pg_con.execute("DELETE FROM reactrole WHERE guild_id = $1 and message_id = $2 and emoji = $3", guild_id, message_id, emm)
                await ctx.send(embed=discord.Embed(color=discord.Color.green(), description=f'Reactrole wurde für den React {emoji} gelöscht!'))
            else:
                await ctx.send(embed=discord.Embed(color=discord.Color.red(), description=f'Diese Reaction wurde nicht an der Nachricht gefunden!'))
        elif '<:' not in emoji:
            result = await self.bot.pg_con.fetch("SELECT emoji, role, message_id, channel_id FROM reactrole WHERE guild_id = $1 and message_id = $2 and emoji = $3", guild_id, message_id, emoji_id)
            if not result:
                await ctx.send(embed=discord.Embed(color=discord.Color.red(), description=f'Diese Reaction wurde nicht an der Nachricht gefunden!'))
            elif emoji_id in str(result[0]['emoji']):
                await self.bot.pg_con.execute("DELETE FROM reactrole WHERE guild_id = $1 and message_id = $2 and emoji = $3", guild_id, message_id, emoji_id)
                await ctx.send(embed=discord.Embed(color=discord.Color.green(), description=f'Reactrole wurde für den React {emoji} gelöscht!'))
            else:
                await ctx.send(embed=discord.Embed(color=discord.Color.red(), description=f'Diese Reaction wurde nicht an der Nachricht gefunden!'))


def setup(bot):
    bot.add_cog(Reactrole(bot))
1
Looks like that listener might be being invoked when the bot first reacts to the message. You should check if the user reacting is the bot and just return if they are, probably before anything else in the listener.Patrick Haugh
@PatrickHaugh I revised the two event listeners. If the bot react now, it will be return. But the problem remains. I also changed the source code in the question. I have print the result of the database query to the console. That came out. print(result) [<Record emoji='✅' role='616814659198124053' message_id='626451077209915412' channel_id='618084679916060731'>] print(result[1]) IndexError: list index out of rangeKai
It looks like you're only inserting once for each reactadd. What do you expect to be in the second row?Patrick Haugh
@PatrickHaugh Sorry but I don't know what you mean. Can you reformulate your question?Kai
Python lists have indices starting at 0. Try replacing result[1] with result[0] in your codePatrick Haugh

1 Answers

1
votes

I understand now my mistake and how it is done correctly. Many thanks to Patrick for his help.

Lines 24, 34, 52 and 62 must look like this:

role = discord.utils.get(guild.roles, id=int(result[0]['role']))

In addition, there was a mistake in lines 85 and 100. Here I want the result of all

Row 85 must look like this:

if not emm in str(result) and role_id in str(result):

Row 100 must look like this:

if not emoji_id in str(result) and role_id in str(result):