优化 Discord.py 视图中的交互检查逻辑

花韻仙語
发布: 2025-10-28 15:17:20
原创
253人浏览过

优化 discord.py 视图中的交互检查逻辑

本文深入探讨了 `discord.py` 中 `discord.ui.View` 类的 `interaction_check` 方法的正确使用,以解决因过度限制导致部分按钮无法响应的问题。通过分析原始代码的逻辑缺陷,文章提供了一种分按钮定制交互检查的解决方案,确保不同功能按钮(如“确认”和“撤销”)能独立根据其业务逻辑(用户ID匹配或角色权限)进行权限验证,从而提升交互组件的灵活性和用户体验。

理解 discord.ui.View 和 interaction_check

在 discord.py 中,discord.ui.View 提供了一种构建交互式组件(如按钮、选择菜单)的方式,使其能够附加到消息上。View 类中的 interaction_check 方法是一个强大的工具,用于在任何组件的交互回调被触发之前,对交互进行全局性的预检查。如果 interaction_check 返回 False,则相应的组件回调将不会执行,并且可以向用户发送一条错误消息。

其基本作用是为视图中的所有组件定义一个通用的权限或条件。然而,不当的 interaction_check 逻辑可能导致某些按钮的功能被意外阻止,即使这些按钮在其自身的逻辑中包含了正确的权限检查。

遇到的问题:interaction_check 的过度限制

考虑以下场景:一个 View 包含“确认 (Acknowledge)”和“撤销 (Revoke)”两个按钮。

  • “确认”按钮应仅由特定用户(通过 user_id 参数传入)点击。
  • “撤销”按钮应仅由具有特定角色的用户点击。

原始的 interaction_check 实现如下:

async def interaction_check(self, interaction: discord.Interaction) -> bool:
    userid = int(self.user_id)
    if interaction.user.id == userid and interaction.data["custom_id"] == "acknowledge":
        return True
    else:
        await interaction.response.send_message("你无权使用此按钮。", ephemeral=True)
        return False
登录后复制

此代码段的逻辑是:只有当交互用户ID与 self.user_id 匹配,并且 被点击的按钮 custom_id 为 "acknowledge" 时,才允许交互继续。否则,无论点击哪个按钮,都会发送一条错误消息并阻止交互。

360智图
360智图

AI驱动的图片版权查询平台

360智图38
查看详情 360智图

问题分析: 当用户点击“撤销”按钮时,interaction.data["custom_id"] 将是 "revoke"。此时,interaction.user.id == userid and interaction.data["custom_id"] == "acknowledge" 这个条件将评估为 False(因为 interaction.data["custom_id"] 不等于 "acknowledge")。因此,interaction_check 会立即返回 False,阻止“撤销”按钮的回调函数执行,即使“撤销”按钮内部有自己的角色检查逻辑。这就是导致“撤销”按钮无法工作的根本原因。

解决方案:分按钮定制 interaction_check 逻辑

为了解决这个问题,我们需要优化 interaction_check 的逻辑,使其能够区分不同的按钮,并应用相应的检查,或者在某些情况下允许交互通过,以便按钮自身的逻辑能够处理权限。

核心思想是:

  1. “确认”按钮: 仍然需要验证交互用户的ID是否与 self.user_id 匹配。
  2. “撤销”按钮: interaction_check 不应阻止它。它的角色权限验证应该在其自身的 @discord.ui.button 回调函数中处理。

以下是修改后的 MyView 类和 interaction_check 方法:

import discord
from discord import Embed, app_commands
from discord.app_commands import Choice

class MyView(discord.ui.View):
    def __init__(self, user_id: str):
        super().__init__(timeout=None) # Consider adding a timeout
        self.user_id = user_id

    async def interaction_check(self, interaction: discord.Interaction) -> bool:
        """
        根据按钮的 custom_id 进行条件检查,以允许不同按钮执行其特定的权限逻辑。
        """
        button_custom_id = interaction.data.get("custom_id")

        # 对于 "acknowledge" 按钮,执行用户ID匹配检查
        if button_custom_id == "acknowledge":
            if interaction.user.id == int(self.user_id):
                return True
            else:
                await interaction.response.send_message("你无权确认此消息。", ephemeral=True)
                return False

        # 对于 "revoke" 按钮,允许其通过 interaction_check,
        # 具体的角色权限检查将在其自身的异步回调函数中完成。
        elif button_custom_id == "revoke":
            return True 

        # 对于其他未明确处理的按钮,默认拒绝交互
        else:
            await interaction.response.send_message("你无权使用此按钮。", ephemeral=True)
            return False

    @discord.ui.button(label="Acknowledge", emoji="<:check:1135773225423491122>", style=discord.ButtonStyle.grey, custom_id="acknowledge")
    async def menu1(self, interaction: discord.Interaction, button: discord.ui.Button):
        # 这里的 interaction_check 已经确保只有授权用户才能点击此按钮
        new_embed = Embed.from_dict(interaction.message.embeds[0].to_dict())
        new_embed.set_footer(text=f'Sent by {interaction.user.name}     |     Acknowledged: ✔')
        await interaction.response.edit_message(embed=new_embed)
        button.disabled = True
        await interaction.message.edit(view=self)

    @discord.ui.button(label="Revoke", emoji="<:Cross:1135773287880867900>", style=discord.ButtonStyle.grey, custom_id="revoke")
    async def menu2(self, interaction: discord.Interaction, button: discord.ui.Button):
        # interaction_check 允许此按钮的回调执行,现在在此处进行角色检查
        user = interaction.guild.get_member(interaction.user.id)
        # 建议使用配置或环境变量存储角色ID,而非硬编码
        role_headquarters_id = 994233392478560297
        role_first_line_supervisors_id = 994233182532685825

        role1 = discord.utils.get(interaction.guild.roles, id=role_headquarters_id)
        role2 = discord.utils.get(interaction.guild.roles, id=role_first_line_supervisors_id)

        # 确保角色存在,避免NoneType错误
        if role1 and role2 and (role1 in user.roles or role2 in user.roles):
            await interaction.response.send_message(f"**惩罚已由 {interaction.user.mention} 撤销**", ephemeral=False)
            await interaction.message.delete()
        else:
            await interaction.response.send_message("你没有所需的角色来使用此按钮。", ephemeral=True)

# 你的机器人命令部分 (保持不变)
# @bot.tree.command(name="infract")
# ... (省略,与问题内容相同)
登录后复制

代码解释:

  1. 在修改后的 interaction_check 中,我们首先获取被点击按钮的 custom_id。
  2. 如果 custom_id 是 "acknowledge",则执行原始的用户ID匹配逻辑。
  3. 如果 custom_id 是 "revoke",我们直接 return True。这意味着 interaction_check 不会阻止“

以上就是优化 Discord.py 视图中的交互检查逻辑的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号