0
votes

I've made a warn command that gives the mentioned user a warned role, but I ran into a problem. Sometimes server owners might forget about moving the role of the bot above the warned role, and that would cause the bot to not be able to give the role to the user. I've tried using role.editable, but it returns false even if the role is below the bot's role. The user to warn has also lower roles than the bot. Here is my code:

const { DiscordAPIError } = require("discord.js");
const Discord = require('discord.js');
const fs = require("fs");
const ms = require("ms")
//let warnedRoleList = JSON.parse(fs.readFileSync("./roleIDs/warnedRole.json", "utf-8"));
var mongoPath = '../../mongo.js' //path.join(__dirname, '..', 'mongo.js');
const mongo = require(mongoPath)
const setWarnedSchema = require('../../schemas/setwarned-schema.js')
const mongoose = require('mongoose');
const cache = {}
const setup = require('../../util/setup')
const moderation = require('../../util/moderation')
const index = require('../../index.js')
//const commands = require("./commands");

module.exports = {
    commands: ['warn'],
    expectedArgs: ['{user ping/user ID} [reason]'],
    permissionError: ['you are missing the manage messages permissions'],
    minArgs: 1,
    maxArgs: null,
    permissions: ['MANAGE_MESSAGES'],
    requiredRoles: [],
    description: "The bot will warn the mentioned user",
    callback: async (message, args, text) => {
        const guild = message.guild
        let guildID = message.guild.id;
        var warnedRoleID = null
        warnedRoleID = await setup.getWarnedRoles(guildID)

        warnedRoleID = warnedRoleID.toString()
        var UserID = args[0]
        var member = index.getMention(args[0], message)

        var warnReason = args
        warnReason.shift()
        warnReason = warnReason.toString()
        warnReason = warnReason.replace(/,/g, ' ')
        if(!member) {
            return message.reply('please specify the user that should be warned')
        };

        if (!warnReason) {
            warnReason = 'no reason given'
        };
        var warnedRole = message.guild.roles.cache.get(warnedRoleID);
        var warnedOneHighestRoleID = member.roles.highest.id;
        var warningOneHighestRoleID = message.member.roles.highest.id;

        if(!warnedRole) {
            return message.reply('there is not a role set as the warned role, set it by doing &setwarnedrole (that requires manage server permissions)')
        };

        //let warnReason = args.join(" ").slice(18);
        if(member.id === message.author.id) {
            return message.reply('can not allow self-harm')
        }
        if (message.member.roles.highest.comparePositionTo(member.roles.highest) <= 0) { //warnedOneHighestRoleID === warningOneHighestRoleID
            return message.reply('you can not warn a user with the same (or higher) permissions as you')
        }
        if(!message.member.permissions.has('MANAGE_MESSAGES')){
            return message.reply(`you don't have manage messages permissions that are required to execute this command.`);
        }

        if (member.roles.cache.has(`${warnedRoleID}`)) {
            const logEmbed = new Discord.MessageEmbed()
            .setColor('#FF0000')
            .setTitle(`An attempt to warn an already warned member happened`)
            //.setAuthor(`${userinfoget.user.tag}`, userinfoget.user.displayAvatarURL())
            .setDescription(`**Warned member:** <@${member.user.id}>\n**Warned by:** <@${message.author.id}>\n**Warn reason:** ${warnReason}`)
            .setTimestamp()
    
            index.modLog(guildID, logEmbed)
            message.reply('this user is already warned!')
            return
        };
        console.log(warnedRole.editable)
        if(!warnedRole.editable) {
            message.reply(`failed to warn <@${member.id}> as the warned role is above my highest role. Try moving at least one of my roles above other ones`)
            return
        };
        member.roles.add(warnedRoleID)
        .then(memberAdded => {
         message.reply(`you have succesfully warned <@${member.id}> with the reason **${warnReason}**`);
        })
        .catch(error => {
        //console.log(error);
            if(message.member.permissions.has('ADMINISTRATOR')){
                message.reply('there is no role set as the warned role. Set it by doing `&setwarnedrole add {role ID}`')
            } else message.reply('there is no role set as the warned role. Ask an admin to set it by doing `&setwarnedrole add {role ID}`')
        });
        const embed = new Discord.MessageEmbed()

        .setColor('#FF0000')
        .setTitle(`You hev been warned in ${message.guild.name}`)
        //.setAuthor(`${userinfoget.user.tag}`, userinfoget.user.displayAvatarURL())
        .setDescription(`**Warned by:** <@${message.author.id}>\n**Warn reason:** ${warnReason}`)
        .setTimestamp()

        member.user.send(embed).catch(error => {
            message.channel.send(`Failed to DM <@${member.id}> the info about this action`)
            console.log(error)
        })

        const logEmbed = new Discord.MessageEmbed()
        .setColor('#FF0000')
        .setTitle(`A member has been warned`)
        //.setAuthor(`${userinfoget.user.tag}`, userinfoget.user.displayAvatarURL())
        .setDescription(`**Warned member:** <@${member.user.id}>\n**Warned by:** <@${message.author.id}>\n**Warn reason:** ${warnReason}`)
        .setTimestamp()

        index.modLog(guildID, logEmbed)
    }
}

Is there a way to check if the role can be added to the user by a bot? Thanks in advance.

1

1 Answers

1
votes

Role hiearchy isn't the sole factor in determining if a role is editable. For example, if your bot doesn't have the MANAGE_ROLES permission, then no matter how high your bot's highest role is, Role#editable will still return false.

What you want to do is first check if the GuildMember is manageable (via GuildMember#manageable). If they aren't, you can't really expect to be able to add roles to them. Then, you want to check if your bot has the MANAGE_ROLES permission. Lastly, you want to check if the position of the said "warn role" is higher than that of the bot's highest role.

The last 2 steps should be done internally by Role#editable (See https://github.com/discordjs/discord.js/blob/master/src/structures/Role.js#L128)

So what you could do is

if(!member.manageable || !warnedRole.editable) return console.log("Nope, cannot add role to that member)