Discord机器人interaction_check致Revoke按钮失效问题求助
问题与解决方案
问题现象
启用interaction_check时,Revoke按钮完全无法工作;关闭该检查后,Revoke功能恢复正常。
需求:
- Acknowledge按钮仅允许slash命令指定的违规用户(userid参数)触发
- Revoke按钮仅允许拥有"Headquarters"或"First Line Supervisors"角色的用户触发
问题根源
原代码的interaction_check逻辑存在缺陷:仅当用户是指定违规用户且点击的是Acknowledge按钮时才返回True,所有其他情况直接返回False并发送统一的未授权提示。这导致点击Revoke按钮时,还没走到按钮自身的逻辑就被check拦截,直接返回未授权,自然无法正常工作。
修复方案
修改interaction_check,针对不同按钮的custom_id分别做权限校验,避免一刀切的拦截逻辑。同时可以把Revoke按钮的角色校验移到check中,让权限逻辑更集中:
class MyView(discord.ui.View): def __init__(self, user_id: str): super().__init__() self.user_id = user_id # 提前定义角色ID,避免重复查询 self.role_ids = {994233392478560297, 994233182532685825} async def interaction_check(self, interaction: discord.Interaction) -> bool: custom_id = interaction.data.get("custom_id") # 处理Acknowledge按钮权限 if custom_id == "acknowledge": target_user_id = int(self.user_id) if interaction.user.id == target_user_id: return True await interaction.response.send_message("你无权使用此按钮", ephemeral=True) return False # 处理Revoke按钮权限 elif custom_id == "revoke": # 检查用户是否拥有指定角色 user_roles = {role.id for role in interaction.user.roles} if self.role_ids & user_roles: return True await interaction.response.send_message("你没有使用此按钮的权限", ephemeral=True) return False # 其他未知按钮直接拦截 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): new_embed = Embed.from_dict(interaction.message.embeds[0].to_dict()) new_embed.set_footer(text=f'发送者: {interaction.user.name} | 已确认: ✔') 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完成,这里直接执行逻辑 await interaction.channel.send(f"**处罚已被 {interaction.user.mention} 撤销**") await interaction.message.delete() # 以下slash命令代码保持不变 @bot.tree.command(name="infract") @app_commands.describe(userid = "被处罚用户ID") @app_commands.describe(reason = "处罚原因") @app_commands.describe(type = "选择处罚类型") @app_commands.choices(type=[ Choice(name='开除', value=1), Choice(name='降级', value=2), Choice(name='警告', value=3), Choice(name="拉黑", value=4), Choice(name="调查中", value=5) ]) @app_commands.describe(note = "备注信息(无则填N/A)") @app_commands.describe(acknowledge = "是否添加确认按钮?") @app_commands.choices(acknowledge=[ Choice(name='是', value=1), Choice(name='否', value=2) ]) # 补充slash命令执行逻辑示例 async def infract(interaction: discord.Interaction, userid: str, reason: str, type: Choice[int], note: str, acknowledge: Choice[int]): embed = discord.Embed(title="处罚通知", description=f"用户ID: {userid}\n原因: {reason}\n类型: {type.name}\n备注: {note}", color=discord.Color.red()) view = MyView(userid) if acknowledge.value == 1 else None await interaction.response.send_message(embed=embed, view=view)
关键修改点
- 拆分权限校验逻辑:针对两个按钮的custom_id分别做权限判断,避免统一拦截
- 集中权限逻辑:将Revoke按钮的角色校验移到
interaction_check中,让代码更清晰,避免重复校验 - 避免重复响应:每个分支只在权限不通过时发送一次ephemeral消息,确保不会出现响应冲突
- 优化角色查询:提前定义角色ID集合,用集合交集判断用户是否拥有权限,比逐个遍历更高效
内容的提问来源于stack exchange,提问作者sac
相关产品推荐
相关产品推荐

