【问题标题】:How can I have two command decorators that go against each other?我怎样才能有两个相互对抗的命令装饰器?
【发布时间】:2021-06-20 20:42:53
【问题描述】:

我有一个命令可以删除用户输入的指定数量的消息。我希望只有我和具有管理员角色的人才能访问此命令。我以前用 if 语句实现过这个,它工作得很好。但是,现在我正在尝试使用命令装饰器来做同样的事情,它只允许管理员使用命令 - 而不是我。这是我正在使用的代码:

@bot.command(description="clears entered amount of messages")
@commands.is_owner() # checks if user is owner
@commands.has_permissions(administrator=True) # checks if user is admin
async def delete(ctx, amount : int):
    await ctx.channel.purge(limit = amount + 1)

我认为@commands.has_permissions(administrator=True) 阻止我使用该命令,因为我不是其中一台服务器的管理员。我试过切换他们的订单,is_owner() 支票低于has_permissions() 支票;尽管如此,它仍然不允许我使用该命令。如何使用装饰器克服这个问题?

【问题讨论】:

    标签: python discord discord.py


    【解决方案1】:

    您可以创建一个自定义装饰器来检查您是机器人的所有者还是管理员

    def owner_or_admin():
        def predicate(ctx):
            owner = ctx.author.id == bot.owner_id # Comparing the author of the message with the owner of the bot
            perms = ctx.author.guild_permissions.administrator # Checking for admin perms
            return owner or perms
        return commands.check(predicate)
    
    
    @bot.command(description="clears entered amount of messages")
    @owner_or_admin()
    async def delete(ctx, amount : int):
        await ctx.channel.purge(limit = amount + 1)
    

    编辑:我刚刚发现commands.check_any - 检查是否有任何通过的检查将通过,即使用逻辑OR

    @bot.command()
    @commands.check_any(commands.is_owner(), commands.has_permissions(administrator=True))
    async def delete(ctx, amount: int):
        await ctx.channel.purge(limit=amount + 1)
    

    【讨论】:

    • 出于某种原因,即使您的逻辑和代码对我来说似乎完全正确,该命令也不会删除消息。因此,我通过将布尔值初始化为 False 并根据 2 个 if 语句更改它们的值,对其进行了一些更改。我会支持您的答案并将其标记为正确,因为它的逻辑基本上是正确的。但是,由于它对我不起作用(而且我不想编辑您的答案,因为它可能对其他人有用)我将发布我自己对这个问题的答案。
    • 随意查看编辑,刚刚发现 commands.check_any,这是您想要实现的更短版本
    【解决方案2】:

    感谢@ŁukaszKwieciński,我了解到我需要制作一个自定义装饰器来检查机器人所有权和管理员角色,如果它们都是 False,则返回 False,如果其中一个是 False,则返回 True没错。

    def owner_or_admin():
        def predicate(ctx):
            owner = False
            perms = False
            if ctx.author.id == bot.owner_id:
                owner = True
            if ctx.author.guild_permissions.administrator:
                perms = True 
            return owner or perms
        return commands.check(predicate)
    
    @bot.command(description="clears entered amount of messages")
    @owner_or_admin()
    async def delete(ctx, amount : int):
        await ctx.channel.purge(limit = amount + 1)
    

    【讨论】:

    • 这仍然会像 commands.has_permissions 装饰器一样工作,如果owner(之前初始化的两行布尔值)等于所有者 ID,您将在第一个 if 语句中进行比较,那将永远是False。你应该把它改成ctx.author.idd == bot.owner_id
    • @ŁukaszKwieciński 哎呀,这是一个复制错误。
    【解决方案3】:

    这对我来说似乎不一样,

    @bot.command(description="clears entered amount of messages")
    @commands.is_owner() # checks if user is owner
    @commands.has_permissions(administrator=True) # checks if user is admin
    async def delete(ctx, amount : int):
        await ctx.channel.purge(limit = amount + 1)
    

    我可以清除消息。 我怀疑你没有正确设置不和谐权限, 尝试确保您已启用 manage_messages 权限

    阅读 Discord API 了解更多信息

    【讨论】:

    • 机器人启用了manage_messages - 这不是问题。问题是在我不是管理员的服务器中,我无法运行该命令。但是,如果我在服务器中并且我具有管理员角色,则该命令有效。
    • 嗯,是的,这就是第三个装饰器所做的,这就是它的重点。仅仅因为您是 1 个随机服务器中的管理员并不意味着您应该能够在您的机器人所在的所有其他服务器中做任何您想做的事情。如果您不希望这样做,请删除它并使用 if专门检查您的 Discord id(在函数中或自定义装饰器中)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-19
    • 1970-01-01
    • 2011-12-21
    • 2019-08-26
    • 1970-01-01
    • 1970-01-01
    • 2015-08-07
    相关资源
    最近更新 更多