キャッシュされた古い情報の参照による問題
以下の実装(v13でより起こりそうな話なのでv13を使用)には極めて限定されたパターンで問題が発生することがある。 勘のいい人は気が付きそうではあるが、キックするメンバーの指定がidになっている
問題を起こすためにわざとそうしましたごめんなさいtig.icon
実際にここが問題で、discord.jsのマネージャーのfetchはキャッシュにメンバーが存在するとき、Discord APIへリクエストを行わない
したがって指定されたメンバーが持っている役職の情報が古い状態で、役職の順位の比較が行われることが起こり得る。
具体的に言うと、キック対象がキャッシュされた後、キック対象の一番高いロールが変更されるようなロールの付与、剥奪を行った後、キャッシュの更新が行われなかった場合。
結果として、本来キックできるべきときにメンバーがキックできなかったり、逆にキックできてはならないときに、キックできたりする。
メンションでメンバーの指定を受けるときはメンションされているメンバーの持っている役職の情報がAPIから渡されているので問題は発生しない。
他にも様々なパターンで起こり得るので注意されたい。
対処
必ずAPIへリクエストを行う
この場合はforceパラメータを使用する
code:js
const Discord = require("discord.js");
const client = new Discord.Client({
intents: Discord.Intents.FLAGS.GUILDS | Discord.Intents.FLAGS.GUILD_MESSAGES,
allowedMentions: {
parse: []
},
});
/**
*
* @param {Discord.Message} message
*/
async function onMessage(message) {
const guild = message.guild;
if (command !== '!kick' || !guild) {
return;
}
if (!message.member.permissions.has("KICK_MEMBERS")) return message.channel.send('あなたにはユーザーをkickする権限がありません');
if (target == undefined) return message.channel.send('kickしたいユーザーのidを指定してください');
const member = await guild.members.fetch(target);
const owner = await guild.fetchOwner();
if (owner.id !== message.author.id && member.roles.highest.comparePositionTo(message.member.roles.highest) >= 0) {
return message.channel.send('あなたより上の役職をもつメンバーをkickすることはできません');
}
if (!member.kickable) return message.channel.send('botがこのユーザーをkickすることができません');
await member.kick();
await message.channel.send(${member.user.tag} をkickしました);
}
client.on("messageCreate", (message) => onMessage(message));
client.once("ready", () => {
console.log("ready");
})
client.login();