Eric Jin
Eric Jin

Reputation: 3924

discord.py client kick user from server

My intended behavior is when someone whose ID is in the list admins can make the bot kick someone using /kick <mention_user_to_kick> <reason>, but it ends up with the error message

Ignoring exception in on_message
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/discord/client.py", line 312, in _run_event
    await coro(*args, **kwargs)
  File "discordbot.py", line 325, in on_message
    await target.kick(reason=reason)
AttributeError: 'User' object has no attribute 'kick'

and I can't find a way to convert the user object into a member object, even given the server/guild ID (from message.guild.id). Trying to kick using client.kick(user) fails because kick is not an attribute of client. Doing client.get_user() returns a user object, so it doesn't work. Doing a search of message.guild.members (what I have) doesn't help as it outputs an iterable of user objects.

This is what I have so far:

import discord
import asyncio
import os
import random
import time
import math


client = discord.Client()


# the list of admins is in here
with open('admins.conf', 'r') as f:
    for line in f.readlines():
        exec(line)

random.seed(os.urandom(32))
searchusers = []
bank_cooldown = {}
bans['global'] = False

@client.event
async def on_ready():
    '''Notification on ready.'''
    print('Logged in! Bot running.')
    await client.change_presence(activity=discord.Game(name='/help'))

@client.event
async def on_member_join(user):
    '''Direct message the rules on member join.'''
    await user.create_dm()
    await user.dm_channel.send(f'Hi **{user.name}**, welcome to the server! Be sure to read the rules to stay out of trouble. Have a great time!')

def isadmin(uid):
    '''Return True if user is a bot admin, False otherwise.'''
    return True if uid in admins else False

def mention_to_uid(mention):
    '''Extract the UID from a mention'''
    uid = mention[2:-1]
    if uid[0] == '!':
        uid = uid[1:]
    return uid


@client.event
async def on_message(message):

    ##########################
    # a bunch of setup stuff #
    ##########################

    if message.content.startswith('/') or message.content.startswith('&') or cmd == 2147483647:
        user = message.author.id
        name = message.author.display_name
        text = message.content[1:].strip()
        command = text.split(' ')[0]
        subcommand = text.split(' ')[1:]

        ##################
        # other commands #
        ##################

        if command == 'kick':
            if len(subcommand) < 2:
                await message.channel.send('Missing arguments! `/kick <user> <reason>`')
            if isadmin(user):
                reason = ''
                for i in subcommand[1:]:
                    reason += (' ' + i)
                reason = reason[1:]
                for member in message.guild.members:
                    if member.id == int(mention_to_uid(subcommand[0])):
                        target = member
                        break
                target = client.get_user(int(mention_to_uid(subcommand[0])))
                await target.kick(reason=reason)
                await message.channel.send('Kicked user from the server')

        ##################
        # other commands #
        ##################

client.run('Nj*********************************************************')

Upvotes: 0

Views: 2063

Answers (1)

Patrick Haugh
Patrick Haugh

Reputation: 60974

What you should be doing is using the discord.ext.commands extension, which makes all of this really simple:

from discord.ext import commands
from discord import Member

bot = commands.Bot("/")

def called_by(id_list):
    def predicate(ctx):
        return ctx.author.id in id_list
    return commands.check(predicate)

@bot.command(name="kick")
@called_by(admins)
async def kick_command(ctx, target: Member, *, reason=None):
    await target.kick(reason=reason)

bot.run("token")

(You would probably want to add an error handler to communicate to users when validations fail).

If you're not willing to do that, you can use Guild.get_member instead:

target = message.guild.get_member(mention_to_uid(subcommand[0]))

Upvotes: 2

Related Questions