#Kick, Ban or time out user

1 messages · Page 1 of 1 (latest)

dense cave
#

Hi,

I'm using buttons to trigger the discord kick, ban and timeout options but on every try it just retuns the User not Found message.

            admin_action_embed = disnake.Embed(
                title=f"User Warned - Admin Action Required",
                description=f"User {user.mention} has received their third warning. Admins, please take action.",
                color=disnake.Color.red()
            )

            action_row = disnake.ui.ActionRow(
                disnake.ui.Button(
                    label="Kick",
                    style=disnake.ButtonStyle.danger,
                    custom_id=f"kick_{user.id}"
                ),
                disnake.ui.Button(
                    label="Ban",
                    style=disnake.ButtonStyle.danger,
                    custom_id=f"ban_{user.id}"
                ),
                disnake.ui.Button(
                    label="Timeout",
                    style=disnake.ButtonStyle.primary,
                    custom_id=f"timeout_{user.id}"
                )
            )

            await admin_channel.send(embed=admin_action_embed, components=[action_row])

@commands.Cog.listener()
async def on_button_click(self, inter):
    custom_id = inter.data['custom_id']
    user_id = int(custom_id.split('_')[1])

    if custom_id.startswith("kick_"):
        user = inter.guild.get_member(user_id)
        if user:
            await user.kick()
        else:
            await inter.response.send_message("User not found or already kicked.", ephemeral=True)

    elif custom_id.startswith("ban_"):
        user = inter.guild.get_member(user_id)
        if user:
            await user.ban()
        else:
            await inter.response.send_message("User not found or already banned.", ephemeral=True)

    elif custom_id.startswith("timeout_"):
        user = inter.guild.get_member(user_id)
        if user:
            await user.timeout()
        else:
            await inter.response.send_message("User not found.", ephemeral=True)

I feel like I'm not calling the discord user_id correctly which causes it to fail.

I was hoping someone could spot the issue, thanks.

dense cave
dense cave
dense cave
viscid jetty
dense cave
#

Me again, I've inspected my full code and I can't see any errors with my code but it's still giving me the same error.

#
from disnake.ext import commands
import disnake
from cogs.database_cog import conn, cursor

class ModCog(commands.Cog):
    def __init__(self, bot):
        self.bot = bot

    async def send_admin_action_notification(self, inter, user):
        cursor.execute("SELECT admin_channel_id FROM settings WHERE guild_id = ?", (inter.guild.id,))
        admin_channel_id = cursor.fetchone()

        if admin_channel_id:
            admin_channel_id = admin_channel_id[0]

            admin_channel = inter.guild.get_channel(admin_channel_id)
            admins = [member.mention for member in inter.guild.members if member.guild_permissions.administrator]
            admin_mentions = " ".join(admins)

            admin_action_embed = disnake.Embed(
                title=f"User Warned - Admin Action Required",
                description=f"User {user.mention} has received their third warning. Admins, please take action.",
                color=disnake.Color.red()
            )

            action_row = disnake.ui.ActionRow(
                disnake.ui.Button(
                    label="Kick",
                    style=disnake.ButtonStyle.danger,
                    custom_id=f"kick_{user.id}"
                ),
                disnake.ui.Button(
                    label="Ban",
                    style=disnake.ButtonStyle.danger,
                    custom_id=f"ban_{user.id}"
                ),
                disnake.ui.Button(
                    label="Timeout",
                    style=disnake.ButtonStyle.primary,
                    custom_id=f"timeout_{user.id}"
                )
            )

            await admin_channel.send(embed=admin_action_embed, components=[action_row])
#
    @commands.slash_command(description="Warn a user (Mods only)")
    async def warn(self, inter, user: disnake.Member, *, reason: str):
        if inter.author.guild_permissions.mute_members:
            cursor.execute("SELECT warning_count, reason FROM warnings WHERE user_id = ?", (user.id,))
            result = cursor.fetchone()

            if result is None:
                cursor.execute("INSERT INTO warnings (user_id, warning_count, reason) VALUES (?, 1, ?)", (user.id, reason))
                warning_count = 1 
            else:
                warning_count = result[0] + 1
                stored_reason = result[1]
                if stored_reason:
                    reason = f"{stored_reason}\n{reason}"  
                cursor.execute("UPDATE warnings SET warning_count = ?, reason = ? WHERE user_id = ?", (warning_count, reason, user.id))

            conn.commit()

            mention = user.mention

            embed = disnake.Embed(
                title=f"User Warned",
                description=f"{mention} has received a warning for the following reason(s):\n\n{reason}\n\n"
                            f"This is warning number {warning_count}.",
                color=disnake.Color.red()
            )

            await inter.response.send_message(f"{mention}", embed=embed)

            if warning_count == 3:
                await self.send_admin_action_notification(inter, user)
        else:
            await inter.response.send_message("You don't have the right permissions to warn users.", ephemeral=True)

    @commands.Cog.listener()
    async def on_button_click(self, inter):
        custom_id = inter.data['custom_id']
        user_id = int(custom_id.split('_')[1])

        user = inter.guild.get_member(user_id)

        if custom_id.startswith("kick_"):
            if user:
                try:
                    await user.kick(reason="Kicked via button")
                    await inter.response.send_message(f"{user.mention} has been kicked successfully!")
                except disnake.Forbidden:
                    await inter.response.send_message("You do not have the proper permissions to kick.", ephemeral=True)
                except disnake.HTTPException:
                    await inter.response.send_message("Kicking failed.", ephemeral=True)
            else:
                await inter.response.send_message("User not found or already kicked.", ephemeral=True)

        elif custom_id.startswith("ban_"):
            if user:
                try:
                    await user.ban(reason="Banned via button")
                    await inter.response.send_message(f"{user.mention} has been banned successfully!")
                except disnake.Forbidden:
                    await inter.response.send_message("You do not have the proper permissions to ban.", ephemeral=True)
                except disnake.HTTPException:
                    await inter.response.send_message("Banning failed.", ephemeral=True)
            else:
                await inter.response.send_message("User not found or already banned.", ephemeral=True)

        elif custom_id.startswith("timeout_"):
            if user:
                try:
                    await user.timeout(reason="Timed out via button")
                    await inter.response.send_message(f"{user.mention} has been timed out successfully!")
                except disnake.Forbidden:
                    await inter.response.send_message("You do not have the proper permissions to time out.", ephemeral=True)
                except disnake.HTTPException:
                    await inter.response.send_message("Timing out failed.", ephemeral=True)
            else:
                await inter.response.send_message("User not found.", ephemeral=True)


def setup(bot):
    bot.add_cog(ModCog(bot))
viscid jetty
#

intents?

#

btw

#

await user.timeout(reason="Timed out via button") will raise ValueError

dense cave
#
intents = disnake.Intents(messages=True, guilds=True)

bot = commands.Bot(command_prefix=commands.when_mentioned, intents=intents)

Sorry they're in the main.py file

viscid jetty
#

there your fault

dense cave
viral sleetBOT
#

disnake/guild.py lines 4538 to 4539

if not (duration is MISSING) ^ (until is MISSING):
    raise ValueError("Exactly one of `​duration`​ and `​until`​ must be provided")
viscid jetty
#

there no timeout forever

dense cave
#

Ah yeah, that makes a lot of sense...

dense cave
#

The code below errors, I can't pinpoint why this happens

    async def perform_timeout_action(self, inter, user):
        if user:
            timeout_modal = self.TimeoutModal(user, duration=60)
            message = await inter.followup.send("Specify the timeout duration:", view=timeout_modal, ephemeral=True)
            timeout_modal.message = message

    async def timeout_user(self, user, duration, reason):
        if user:
            try:
                await user.timeout(duration=duration, reason=reason)  
                return user
            except disnake.Forbidden:
                return "You do not have the proper permissions to time out."
            except disnake.HTTPException:
                return "Timing out failed."
        else:
            return "User not found."

    class TimeoutModal(disnake.ui.View):
        def __init__(self, user, duration):
            super().__init()

            options = [
                disnake.SelectOption(
                    label="15 minutes",
                    value="15",
                    description="Timeout for 15 minutes"
                ),
                disnake.SelectOption(
                    label="30 minutes",
                    value="30",
                    description="Timeout for 30 minutes"
                ),
            ]

            select = disnake.ui.Select(
                custom_id="timeout_duration",
                placeholder="Select timeout duration",
                options=options
            )

            self.add_item(select)

            self.user = user
            self.timeout_duration = duration

        async def interaction_check(self, inter):
            return inter.user.id == self.user.id

        async def on_select(self, inter):
            if inter.component.custom_id == "timeout_duration":
                duration = int(inter.values[0])
                reason = "Timed out"
                result = await self.timeout_user(self.user, duration=duration * 60, reason=reason)
                if isinstance(result, str):
                    await inter.response.send_message(result, ephemeral=True)
                else:
                    await inter.response.send_message(f"{self.user.mention} (User ID: {self.user.id}) has been timed out for {duration} minutes.")```
#
Ignoring exception in on_button_click
 Traceback (most recent call last):
   File "/usr/local/lib/python3.10/dist-packages/disnake/client.py", line 703, in _run_event
     await coro(*args, **kwargs)
   File "/root/Discord-Bots/Mod-Bot/cogs/mod_cog.py", line 113, in on_button_click
     await self.perform_timeout_action(inter, user)
   File "/root/Discord-Bots/Mod-Bot/cogs/mod_cog.py", line 147, in perform_timeout_action
     timeout_modal = self.TimeoutModal(user, duration=60)  
   File "/root/Discord-Bots/Mod-Bot/cogs/mod_cog.py", line 165, in __init__
     super().__init()
AttributeError: 'super' object has no attribute '_TimeoutModal__init'
long viper
#

I'm confused by this.
Are you calling on_select from somewhere else?

dense cave
#

I am yeah, hold on let me get the whole cog

gritty shoreBOT
#

If your code is too long to fit in a codeblock in discord, you can paste your code here:
https://paste.disnake.dev/

After pasting your code, save it by clicking the save button in the top right, or by typing ctrl + S. After doing that, the URL should change. Copy the URL and post it here so others can see it.

dense cave
long viper
#

super().__init() shoudl be super().__init__()

#
File "/root/Discord-Bots/Mod-Bot/cogs/mod_cog.py", line 165, in __init__
     super().__init()
dense cave
#

It's 2 am I should have just picked this up in the morning lol

long viper
#

Also in your slash command, the defer should be first if you're going to do that.
Deferring AFTER all the db execution is done then immediately editing defeats the entire purpose of its existence.

dense cave
#

Ah I see, thanks lol

long viper
#

I'd also mention you should look into switching to an async db driver.

#

I'm assuming you're using sqlite3, switch to aiosqlite

dense cave
#

Ah okay, I'll keep that in mind!

long viper
#

And your whole if permission check/else can be removed with a simple @commands.has_permissions(mute_members=True)

#

This ensures the command user has the required permission(s) to use the command. Otherwise, it throws a commands.MissingPermissions error that you can capture and handle

dense cave
#

Thanks!

long viper
#

Just makes life easier when you have mutiple commands that require different things and can throw different errors. Using the decorators allows you to easily handle these errors in one place since they'll likely have similar responses rather than having to do that if check for every single command.

#

And since this is a ModCog, I'm assuming you plan to add more functionality so you can have a single error handler for the entire cog that will catch and handle those missing permission errors, and any other errors that originate from inside that cog.

dense cave
#

Ah fair, yeah I see what you're trying to say!

Thanks for these tips :)