Discord.py审核Bot开发求助:实现带文件存储的warn/warnings/unwarn指令
Discord.py 警告类审核指令实现
前置准备
- 采用本地JSON文件
warnings.json存储警告记录,无需额外数据库,适配中小服务器使用场景 - 记录结构为:
{"用户Discord ID(字符串)": [{"reason": "警告原因", "timestamp": "生成时间", "warner_id": "操作管理员ID"}]} - 统一通过
manage_members权限校验操作门槛,符合要求的权限规则
注意:需要在Discord开发者门户的机器人设置页,开启「Server Members Intent」权限,否则无法正常解析@的用户信息。
工具函数封装
首先导入依赖、初始化机器人,并封装通用的警告记录读写函数:
import discord from discord.ext import commands import json import datetime import os # 初始化机器人配置,命令前缀为? intents = discord.Intents.default() intents.members = True bot = commands.Bot(command_prefix="?", intents=intents) # 警告存储文件路径 WARNING_FILE = "warnings.json" def load_warnings(): # 文件不存在时返回空字典结构,避免读取报错 if not os.path.exists(WARNING_FILE): return {} with open(WARNING_FILE, "r", encoding="utf-8") as f: return json.load(f) def save_warnings(data): with open(WARNING_FILE, "w", encoding="utf-8") as f: # 缩进格式化方便手动调试,开启ensure_ascii=False支持中文存储 json.dump(data, f, indent=2, ensure_ascii=False)
核心指令实现
1. 警告指令 ?warn @user [警告原因]
符合权限的用户执行后将为目标用户新增警告,自动存储到本地文件:
@bot.command(name="warn") @commands.has_permissions(manage_members=True) async def warn(ctx, target: discord.Member, *, reason: str = "未提供警告原因"): # 防滥用校验逻辑 if target == ctx.author: return await ctx.send("你不能警告你自己") if target == ctx.me: return await ctx.send("你不能警告机器人") # 禁止警告权限高于或等于当前操作者的用户(服务器所有者除外) if target.top_role >= ctx.author.top_role and ctx.author != ctx.guild.owner: return await ctx.send("你不能警告权限高于或等于你的用户") warnings = load_warnings() user_id = str(target.id) # 初始化新用户的警告列表 if user_id not in warnings: warnings[user_id] = [] # 新增警告条目 new_warning = { "reason": reason, "timestamp": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "warner_id": str(ctx.author.id) } warnings[user_id].append(new_warning) save_warnings(warnings) await ctx.send(f"已成功警告 {target.mention},原因:{reason}\n该用户当前累计警告数:{len(warnings[user_id])}")
2. 警告查询指令 ?warnings @user
查询指定用户的全部历史警告记录,以Embed卡片形式格式化展示:
@bot.command(name="warnings", aliases=["warns"]) @commands.has_permissions(manage_members=True) async def get_warnings(ctx, target: discord.Member): warnings = load_warnings() user_id = str(target.id) user_warnings = warnings.get(user_id, []) if not user_warnings: return await ctx.send(f"{target.mention} 没有任何历史警告记录") embed = discord.Embed(title=f"{target} 的历史警告记录", color=discord.Color.orange()) for idx, warn in enumerate(user_warnings, 1): warner = await bot.fetch_user(int(warn["warner_id"])) embed.add_field( name=f"警告 #{idx}", value=f"时间:{warn['timestamp']}\n原因:{warn['reason']}\n操作管理员:{warner.mention}", inline=False ) await ctx.send(embed=embed)
3. 警告移除指令 ?unwarn @user [可选:警告序号]
支持移除指定用户的警告记录,默认移除最新一条,也可通过序号指定要删除的警告:
@bot.command(name="unwarn") @commands.has_permissions(manage_members=True) async def unwarn(ctx, target: discord.Member, warn_index: int = None): warnings = load_warnings() user_id = str(target.id) user_warnings = warnings.get(user_id, []) if not user_warnings: return await ctx.send(f"{target.mention} 没有任何警告记录可以移除") # 未指定序号时默认移除最新的一条警告 if warn_index is None: removed = user_warnings.pop() else: # 用户输入的序号从1开始计数,转换为数组索引需减1 try: removed = user_warnings.pop(warn_index - 1) except IndexError: return await ctx.send(f"无效的警告序号,该用户共有 {len(user_warnings)} 条警告,序号范围为 1-{len(user_warnings)}") # 清空警告列表时删除该用户的存储条目,减少冗余 if not user_warnings: del warnings[user_id] else: warnings[user_id] = user_warnings save_warnings(warnings) await ctx.send(f"已成功移除 {target.mention} 的一条警告(原因:{removed['reason']})\n该用户剩余警告数:{len(user_warnings)}")
通用错误处理
统一处理权限不足、参数错误等常见异常,避免用户看到默认的英文报错:
@bot.event async def on_command_error(ctx, error): if isinstance(error, commands.MissingPermissions): await ctx.send("你没有「管理成员」权限,无法执行该指令") elif isinstance(error, commands.MissingRequiredArgument): await ctx.send("指令参数错误,正确用法:\n`?warn @用户 [警告原因]`\n`?warnings @用户`\n`?unwarn @用户 [可选:警告序号]`")
内容的提问来源于stack exchange,提问作者King Zebrus
相关产品推荐
相关产品推荐

