Discord.js频道/角色权限变更审计日志实现求助
看起来你已经把基础的频道更新日志推送搞定了,接下来要处理频道/角色的权限、层级变更这类场景,核心还是围绕审计日志和事件监听来展开,我给你梳理几个具体的开发方向和实现思路:
1. 完善频道变更的细节处理(覆盖权限、层级)
你现有的channelUpdate代码只处理了名称变更,但频道的层级位置、权限规则等变更也需要捕捉。可以通过对比新旧频道对象的属性,再结合审计日志获取执行者和具体变更详情:
const { RichEmbed } = require("discord.js"); const { purple_light } = require("../../colours.json"); module.exports = (bot, oldChannel, newChannel) => { const logChannel = oldChannel.guild.channels.find(c => c.id === "687260937744416798"); if (!logChannel) return; // 收集所有变更项 let changes = []; if (oldChannel.name !== newChannel.name) { changes.push(`名称: **${oldChannel.name}** → **${newChannel.name}**`); } if (oldChannel.position !== newChannel.position) { changes.push(`层级位置: **${oldChannel.position}** → **${newChannel.position}**`); } // 对比频道内角色权限规则的变化 const oldPerms = oldChannel.permissionOverwrites.map(ow => `${ow.id}: ${ow.allow.bitfield}`); const newPerms = newChannel.permissionOverwrites.map(ow => `${ow.id}: ${ow.allow.bitfield}`); if (JSON.stringify(oldPerms) !== JSON.stringify(newPerms)) { changes.push("频道内角色权限规则已更新"); } if (changes.length === 0) return; // 同时获取频道基础更新(type:11)和权限更新(type:10)的审计日志 oldChannel.guild.fetchAuditLogs({ type: [10, 11], limit: 1 }) .then(audit => { const entry = audit.entries.first(); if (!entry) return; const user = entry.executor; const logEmbed = new RichEmbed() .setAuthor(`频道已更新: ${oldChannel.name}`, user.displayAvatarURL()) .addField("频道ID", newChannel.id, true) .addField("更新者", `${user.tag} (${user.id})`, true) .addField("变更内容", changes.join("\n")) .setColor(purple_light) .setTimestamp(); // 如果是权限变更,补充具体的权限详情 if (entry.type === "CHANNEL_OVERWRITE_UPDATE") { const extra = entry.extra; logEmbed.addField("权限变更详情", `目标角色/用户: ${extra.target.tag || extra.target.id}\n` + `新增允许权限: ${extra.allow.toArray().join(", ") || "无"}\n` + `新增拒绝权限: ${extra.deny.toArray().join(", ") || "无"}` ); } logChannel.send(logEmbed).catch(err => console.error("发送日志失败:", err)); }) .catch(err => console.error("获取审计日志失败:", err)); };
2. 新增角色变更事件的监听
针对角色层级、权限的变更,需要单独监听roleUpdate事件,同样结合审计日志实现:
// roleUpdate事件处理文件 const { RichEmbed } = require("discord.js"); const { purple_light } = require("../../colours.json"); module.exports = (bot, oldRole, newRole) => { const logChannel = oldRole.guild.channels.find(c => c.id === "687260937744416798"); if (!logChannel) return; let changes = []; if (oldRole.name !== newRole.name) { changes.push(`名称: **${oldRole.name}** → **${newRole.name}**`); } if (oldRole.position !== newRole.position) { changes.push(`层级位置: **${oldRole.position}** → **${newRole.position}**`); } // 对比权限差异 if (!oldRole.permissions.equals(newRole.permissions)) { const addedPerms = newRole.permissions.difference(oldRole.permissions).toArray(); const removedPerms = oldRole.permissions.difference(newRole.permissions).toArray(); if (addedPerms.length > 0) changes.push(`新增权限: ${addedPerms.join(", ")}`); if (removedPerms.length > 0) changes.push(`移除权限: ${removedPerms.join(", ")}`); } if (changes.length === 0) return; oldRole.guild.fetchAuditLogs({ type: 25, limit: 1 }) .then(audit => { const entry = audit.entries.first(); if (!entry) return; const user = entry.executor; const logEmbed = new RichEmbed() .setAuthor(`角色已更新: ${oldRole.name}`, user.displayAvatarURL()) .addField("角色ID", newRole.id, true) .addField("更新者", `${user.tag} (${user.id})`, true) .addField("变更内容", changes.join("\n")) .setColor(purple_light) .setTimestamp(); logChannel.send(logEmbed).catch(err => console.error("发送日志失败:", err)); }) .catch(err => console.error("获取审计日志失败:", err)); };
3. 用
guildAuditLogEntryCreate统一处理所有审计事件 如果想更高效地覆盖所有需要审核的操作(包括频道/角色的创建、删除、变更),可以监听guildAuditLogEntryCreate事件,它会在每次有审计日志条目生成时触发,不用单独监听每个事件:
// guildAuditLogEntryCreate事件处理文件 const { RichEmbed } = require("discord.js"); const { purple_light } = require("../../colours.json"); module.exports = (bot, entry) => { const logChannel = entry.guild.channels.find(c => c.id === "687260937744416798"); if (!logChannel) return; // 筛选我们关心的事件类型 const targetTypes = [ "CHANNEL_UPDATE", "CHANNEL_OVERWRITE_UPDATE", "ROLE_UPDATE", "CHANNEL_CREATE", "CHANNEL_DELETE", "ROLE_CREATE", "ROLE_DELETE" ]; if (!targetTypes.includes(entry.type)) return; let embed = new RichEmbed() .setAuthor(`审计日志: ${entry.type}`, entry.executor.displayAvatarURL()) .addField("执行者", `${entry.executor.tag} (${entry.executor.id})`, true) .addField("目标ID", entry.target.id, true) .setColor(purple_light) .setTimestamp(); // 根据事件类型添加具体内容 switch(entry.type) { case "CHANNEL_UPDATE": embed.setTitle(`频道更新: ${entry.target.name}`); const channelChanges = entry.changes.map(change => `${change.key}: **${change.old}** → **${change.new}**`); embed.addField("变更内容", channelChanges.join("\n")); break; case "CHANNEL_OVERWRITE_UPDATE": embed.setTitle(`频道权限更新: ${entry.target.name}`); embed.addField("受影响角色/用户", entry.extra.target.tag || entry.extra.target.id); embed.addField("新增允许权限", entry.extra.allow.toArray().join(", ") || "无"); embed.addField("新增拒绝权限", entry.extra.deny.toArray().join(", ") || "无"); break; case "ROLE_UPDATE": embed.setTitle(`角色更新: ${entry.target.name}`); const roleChanges = entry.changes.map(change => `${change.key}: **${change.old}** → **${change.new}**`); embed.addField("变更内容", roleChanges.join("\n")); break; case "CHANNEL_CREATE": embed.setTitle(`频道创建: ${entry.target.name}`); embed.addField("频道类型", entry.target.type); break; case "CHANNEL_DELETE": embed.setTitle(`频道删除: ${entry.target.name}`); embed.addField("频道类型", entry.target.type); break; } logChannel.send(embed).catch(err => console.error("发送日志失败:", err)); };
相关资料查询方向
- 优先查阅Discord.js官方文档中
Guild.fetchAuditLogs()方法和AuditLogEntry类的说明,里面详细讲解了审计日志的类型参数、返回结构(比如changes、extra属性的含义)。 - 查看Discord官方API文档的Audit Log Event Types枚举,里面列出了所有事件类型对应的数字和名称,方便你精准筛选需要监听的操作。
- 参考Discord.js的事件文档,比如
channelUpdate、roleUpdate、guildAuditLogEntryCreate的参数说明,明确每个事件触发的时机和传递的数据。
内容的提问来源于stack exchange,提问作者Sorrow
相关产品推荐
相关产品推荐

