Discord.py机器人的权限系统

13

我正在使用 discord.py 和 asyncio 制作一个 Discord 机器人。机器人具有像 kickban 这样的命令,显然普通用户不应该拥有这些权限。

我想要制作一个简单的系统,使用 ctx.message.author 获取发送命令的用户来检测用户角色所具有的权限。

我不希望机器人检测特定的角色名称,因为这些名称在服务器之间可能会有所不同。我也不想为机器人编写多个文件以保持简洁。

我已经查看了 discord.py 文档和其他各种来源,但是它们都没有提供如何实现所讨论方法的示例。

以下是我的机器人中的一个命令示例:

async def kick(ctx, userName: discord.User):
    if True: #ctx.message.author.Permissions.administrator
        await BSL.kick(userName)
    else:
        permission_error = str('Sorry ' + ctx.message.author + ' you do not have permissions to do that!')
        await BSL.send_message(ctx.message.channel, permission_error)

这里,if else语句是我自己尝试做到这一点的。注释掉了#ctx.message.author.Permissions.administrator因为它不起作用,并且用True替换以进行测试。

提前感谢您的任何帮助和建议。

4个回答

17

Permissions是类的名称。要获取消息作者的权限,您应该访问作者的guild_permissions属性。

if ctx.message.author.guild_permissions.administrator:
 # you could also use guild_permissions.kick_members

更新:

验证调用命令者的权限更好的方法是使用commands扩展的check功能,特别是has_permissions检查。例如,如果您只想将您的命令开放给具有manage_roles权限或ban_members权限的人员,则可以编写以下命令:

from discord import Member
from discord.ext.commands import has_permissions, MissingPermissions

@bot.command(name="kick", pass_context=True)
@has_permissions(manage_roles=True, ban_members=True)
async def _kick(ctx, member: Member):
    await bot.kick(member)

@_kick.error
async def kick_error(ctx, error):
    if isinstance(error, MissingPermissions):
        text = "Sorry {}, you do not have permissions to do that!".format(ctx.message.author)
        await bot.send_message(ctx.message.channel, text)

我知道最初的问题没有提到,但有没有办法检查消息作者的ID,以便我可以访问所有命令而不考虑角色? - user9123
Member is a subclass of User, so you should be able to just do author.id - Patrick Haugh
我遇到了这个错误:File "C:\Users\Administrator\Desktop\dicordBot.py", line 25, in clear if ctx.message.author.server_permissions.administrator or ctx.message.author.id('344812358868402176'): TypeError: 'str' object is not callable - user9123
author.id will return the id. You should do author.id == '123...' - Patrick Haugh

4

您还可以使用装饰器。

@bot.command(name = "Kick")
@bot.has_permissions(kick_user = True)
@bot.bot_has_permissions(kick_user = True)
async def _kick(ctx, member: Member):
    #Do stuff...

检查用户和机器人权限的优点是更容易处理由于权限不足而产生的错误,并提供有用的“权限不足”错误消息。

1

被接受的答案中的提示可能无法正常工作:

  1. discord.py库的rewrite版本与旧版本存在兼容性问题,旧版本仍在使用且未过时或弃用。

  2. 机器人应该检查自己的权限,以排除错误的原因之一。

  3. 如果出现错误,或者机器人本身的权限无效,则机器人应该说些什么,对吧?

  4. 需要实现某些内容以防止机器人尝试在DM或群组上下文中运行此命令。这几乎总是会出错。

我提议以下解决方案适用于pre-rewrite(假设您使用命令扩展):

import discord
from discord.ext import commands
import time
@bot.command(pass_context=True,description="Kicks the given member. Please ensure both the bot and the command invoker have the permission 'Kick Members' before running this command.")
async def kick(ctx, target:discord.Member):
    """(GUILD ONLY) Boot someone outta the server. See 's!kick' for more."""
    if not str(ctx.message.channel).startswith("Direct Message with "):
        msg=await bot.say("Checking perms...")
        time.sleep(0.5)
        if ctx.message.server.me.server_permissions.kick_members:
            if ctx.message.author.server_permissions.kick_members:
                await bot.edit_message(msg,new_content="All permissions valid, checking issues with target...")
                time.sleep(0.5)
                if target==ctx.message.server.owner:
                    await bot.edit_message(msg, new_content="All permissions are correct, but you're attempting to kick the server owner, whom you can't kick no matter how hard you try. Whoops!")
                else:
                    if target==ctx.message.server.me:
                        await bot.edit_message(msg, new_content="Whoops! All permissions are corrent, but you just tried to make me kick myself, which is not possible. Perhaps you meant someone else, not poor me?")
                    else:
                        await bot.edit_message(msg, new_content="All permissions correct, and no issues with target being self or server owner, attempting to kick.")
                        time.sleep(2)
                        try:
                            await bot.kick(target)
                            await bot.edit_message(msg, ":boom: BAM! ***kicc'd***")
                        except Exception:
                            await bot.edit_message(msg, new_content="I was unable to kick the passed member. The member may have a higher role than me, I may have crashed into a rate-limit, or an unknown error may have occured. In that case, try again.")
            else:
                await bot.edit_message(msg, new_content="I've the correct permissions, {}, but you do not. Perhaps ask for them?").format(ctx.message.author.mention)
        else:
            await bot.edit_message(msg, new_content="I'm just a poor bot with no permissions. Could you kindly grant me the permission `Kick Members`? Thanks! :slight_smile:")
    else:
        await bot.say("'Tis a DM! This command is for servers only... try this again in a server maybe? :slight_smile:")

0
基于当前版本的discord.py,使用discord.ext.commands,您可以做到以下操作:

将所有<>替换为其所表示的内容。

import discord
from discord.ext import commands

bot = commands.Bot(command_prefix = "<this can be whatever you want>", intents = discord.intents.all())
#make sure to enable all intents in the discord dev portal. I use all intents to make things simple.

@bot.command()
@commands.has_permissions(<permission> = True)
async def ban():
   #the ban commands go here

权限必须与API文档这里中所述的完全相同。 这些权限ID适用于Discord,但对于discord.ext也是相同的。 禁止的ID为ban_members。在装饰器@commands.has_permissions中,请记住不要将ID放在引号中。还要记得在ID末尾添加= True


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接