Why does role.permissions.remove() not work? - javascript

I tried to make a command to remove the MENTION_EVERYONE permission from all roles. It didn't work for some reason. I tried console logging which roles have the permission, and it did, but the only thing is that the permission isn't being taken away. I get no error but here is my code.
client.on('message', msg => {
if(msg.content === 'checkroleperms' && msg.author.id === 'xxxxxxxxxx') {
var roles = msg.guild.roles.cache.array()
var all = '{Placeholder}'
roles.forEach(role => {
if(role.permissions.has('MENTION_EVERYONE')) {
all+= ', ' + role.name;
//RIGHT HERE IS THE WHERE THE PROBLEM IS!!
//Changed this to msg.guild.role.cache.get(role.id).permissions.re...
role.permissions.remove('MENTION_EVERYONE');
console.log(role.name);
}
})
setTimeout(() => msg.channel.send(all), 500);
}
})
Was there something I did wrong? Also, the bot has Admin perms and is the second highest role in the server (right under me). The point is that the command is running but the perms are not being removed.
EDIT: I realized I was only modifying the array, but nothing is happening even when I get it from msg.guild.roles.cache

You were pretty close, the problem is you remove the permission but you never update the role itself.
role.permissions.remove() removes bits from these permissions and returns these bits or a new BitField if the instance is frozen. It doesn't remove or update the role's permissions though.
To apply these changes, you need to use the setPermissions() method that accepts a PermissionResolvable, like the bitfield returned from the permissions.remove() method.
It's probably also better to use roles.fetch() to make sure roles are cached.
Check the working code below:
client.on('message', async (msg) => {
if (msg.content === 'checkroleperms' && msg.author.id === 'xxxxxxxxxx') {
try {
const flag = 'MENTION_EVERYONE';
const roles = await msg.guild.roles.fetch();
const updatedRoles = [];
roles.cache.each(async (role) => {
if (role.permissions.has(flag)) {
const updatedPermissions = role.permissions.remove(flag);
await role.setPermissions(updatedPermissions.bitfield);
updatedRoles.push(role.name);
}
});
const roleList = updatedRoles.join(', ') || `No role found with \`${flag}\` flag`;
setTimeout(() => msg.channel.send(roleList), 500);
} catch (error) {
console.log(error);
}
}
});

Related

Discord JS category and returning ID

I'm trying to check (and create, if it does not exist) the checking process works fine.
Here is a copy of my code:
var bb_admin='0';
//Check if admin_logs exists if not create it
if(message.guild.channels.cache.find(channel => channel.name === "admin_logs") === undefined && typeof message.guild.channels.cache.find(channel => channel.name === "admin_logs") == 'undefined')
{
console.log("creating");
bb_admin = message.guild.channels.create('admin_logs', {parent: bb_cat});
} else {
console.log("already exists");
bb_admin = message.guild.channels.cache.find(channel => channel.name === "admin_logs");}
console.log('bb_admin after',bb_admin);
The problem which I'm having is I need to be able to assign the channel ID to a variable once it is created before moving on.
I cannot use a .then statement as the next steps has to happen outside of this. (I'm cycling a log file and populating the row into a channel based on contents).
What appears to be happening is I'm getting a promise back, however when I change this line:
bb_admin = message.guild.channels.create('admin_logs', {parent: bb_cat})
to:
bb_admin = await message.guild.channels.create('admin_logs', {parent: bb_cat})
to wait for the response I'm given the following error message: SyntaxError: await is only valid in async functions and the top level bodies of modules
I've seen this question which seems pretty much the same as what I'm trying to achieve. but even running attempt 2 presented with the error: TypeError: Cannot read property 'create' of undefined
Any pointers where I am going wrong here, I've been going around in circles for a few days now.
Edit: Very Basic Example:
/**
* #file app.js
* #description BeerBot
* #author Beer
* #version 0.0.1
*/
// Require all needed packages and files
const { Client, MessageEmbed } = require('discord.js');
const config = require('./config.json');
const client = new Client();
// Ready event
client.on('ready', () => {
// Log when bot is ready
console.log(`${client.user.tag} is online!`);
});
// Message event
client.on('message', message => {
if (message.author.bot || !message.guild) return;
if (!message.content.startsWith("!")) return;
//Try a simple category created command
var bb_cat = message.guild.channels.cache.find(channel => channel.name === "BeerBot");
var bb_admin = 0;
//Check if admin_logs exists if not create it
if(message.guild.channels.cache.find(channel => channel.name === "admin_logs") === undefined && typeof message.guild.channels.cache.find(channel => channel.name === "admin_logs") == 'undefined')
{
//Try and create channel
console.log("creating");
bb_admin = message.guild.channels.create('admin_logs', {parent: bb_cat});
//End try and create channel
} else {
console.log("already exists");
bb_admin = await message.guild.channels.cache.find(channel => channel.name === "admin_logs");
}
//This always returns a promise
console.log('bb_admin after',bb_admin);
});
// Login into your bot with the bot token
client.login(config.client.token);
Instead of creating an async IIFE as #Viriato suggested, you should turn your current callback to an async function like in my example below.
Also, you should use a variable if you're calling message.guild.channels.cache.find() three times :) And you don't need to check if the find() method returned undefined or checking its typeof. You can simply check if the returned value is truthy.
// make the callback function async
client.on('message', async (message) => {
if (message.author.bot || !message.guild) return;
if (!message.content.startsWith('!')) return;
let adminLogsChannel = message.guild.channels.cache.find(
(channel) => channel.name === 'admin_logs',
);
// if admin_logs does not exist, create it
if (!adminLogsChannel) {
let parent = message.guild.channels.cache.find(
(channel) => channel.name === 'BeerBot',
);
adminLogsChannel = await message.guild.channels.create('admin_logs', { parent });
}
// this returns a GuildChannel now
console.log('adminLogsChannel after', adminLogsChannel);
});

How do I make a user answer a question using reactions in Discord.js?

I want the user to answer a "yes or no" question using reactions. Here is my code below.
var emojiArray = ['🔥', '👍', '👎', '✅', '❌'];
client.on('message', (negotiate) => {
const listen = negotiate.content;
const userID = negotiate.author.id;
var prefix = '!';
var negotiating = false;
let mention = negotiate.mentions.user.first();
if(listen.toUpperCase().startsWith(prefix + 'negotiate with '.toUpperCase()) && (mention)) {
negotiate.channel.send(`<#${mention.id}>, do you want to negotiate with ` + `<#${userID}>`)
.then(r => r.react(emojiArray[3], emojiArray[4]));
negotiating = true;
}
if(negotiating == true && listen === 'y') {
negotiate.channel.send('Please type in the amount and then the item you are negotiating.');
} else return;
})
As you can see, the code above allows the user to tag someone and negotiate with them (the negotiating part doesn't matter). When the user tags someone else, it asks them if they want to negotiate with the user that tagged them. If the user says yes, they negotiate.
I want to do this in a cleaner way using reactions in discord. Is there any way to just add a yes or no reaction emoji and the user will have to click yes or no in order to confirm?
First of all, you kinda messed up while getting the user object of the mentioned user, so just so you know it's negotiate.mentions.users.first()!
While wanting to request user input through reactions, we'd usually want to use either one of the following:
awaitReactions()
createReactionCollector
Since I personally prefer awaitReactions(), here's a quick explanation on how to use it:
awaitReactions is a message object extension and creates a reaction collector over the message that we pick. In addition, this feature also comes with the option of adding a filter to it. Here's the filter I usually like to use:
const filter = (reaction, user) => {
return emojiArray.includes(reaction.emoji.name) && user.id === mention.id;
// The first thing we wanna do is make sure the reaction is one of our desired emojis!
// The second thing we wanna do is make sure the user who reacted is the mentioned user.
};
From there on, we could very simply implement our filter in our awaitReactions() function as so:
message.awaitReactions(filter, {
max: 1, // Accepts only one reaction
time: 30000, // Will not work after 30 seconds
errors: ['time'] // Will display an error if using .catch()
})
.then(collected => { // the reaction object the user reacted with
const reaction = collected.first();
// Your code here! You can now use the 'reaction' variable in order to check certain if statements such as:
if (reaction.emoji.name === '🔥') console.log(`${user.username} reacted with Fire emoji!`)
Finally, your code should look like this:
const filter = (reaction, user) => {
return emojiArray.includes(reaction.emoji.name) && user.id === mention.id;
};
message.awaitReactions(filter, {
max: 1,
time: 30000,
errors: ['time']
})
.then(collected => {
const reaction = collected.first();
if (reaction.emoji.name === '🔥') console.log(`${user.username} reacted with Fire emoji!`)
you should use a ReactionCollector:
var emojiArray = ['🔥', '👍', '👎', '✅', '❌'];
const yesEmoji = '✅';
const noEmoji = '❌';
client.on('message', (negotiate) => {
const listen = negotiate.content;
const userID = negotiate.author.id;
var prefix = '!';
var negotiating = false;
let mention = negotiate.mentions.user.first();
if(listen.toUpperCase().startsWith(prefix + 'negotiate with '.toUpperCase()) && (mention)) {
negotiate.channel.send(`<#${mention.id}>, do you want to negotiate with ` + `<#${userID}>`)
.then(async (m) => {
await m.react(yesEmoji);
await m.react(noEmoji);
// we want to get an answer from the mentioned user
const filter = (reaction, user) => user.id === mention.id;
const collector = negotiate.createReactionCollector(filter);
collector.on('collect', (reaction) => {
if (reaction.emoji.name === yesEmoji) {
negotiate.channel.send('The mentioned user is okay to negotiate with you!');
// add your negotiate code here
} else {
negotiate.channel.send('The mentioned user is not okay to negotiate with you...');
}
});
});
negotiating = true;
}
})
This allows you to listen for new reactions added to a message. Here is the documentation: https://discord.js.org/#/docs/main/stable/class/Message?scrollTo=createReactionCollector

if else in loop bringing up errors in typescript

I have this function that is supposed to get referral codes from users. User gives a code and the referral code checked if it exists in the database then evaluated if
it does not match the current user, so that one should not refer himself and
it is a match with one of the codes in the database
This code however just does not find a match even if the code given is in the database. If the referral code matches the one of the current user, it works correctly and points that out i.e one cannot refer themselves.
But if the referral code is a match to that of another user which is how a referral system should work, it still says no match.
How can I remove this error
export const getID = functions.https.onCall(async(data, context) => {
const db = admin.firestore();
const usersSnapshot = await db.collection("user").get();
const allUIDs = usersSnapshot.docs.map(doc => doc.data().userID);
const userID = context.auth.uid;
const providedID = "cNx7IuY6rZlR9mYSfb1hY7ROFY2";
//db.collection("user").doc(providedID).collection("referrals").doc(userID);
await check();
function check() {
let result;
allUIDs.forEach(idFromDb => {
if (providedID === idFromDb && (idFromDb === userID)) {
result = "ownmatch";
} else if (providedID === idFromDb && (idFromDb !== userID)) {
result = "match";
} else {
result = "nomatch";
}
});
return result;
}
if (check() === "match") {
return {
message: `Match Found`,
};
} else if (check() === "ownmatch") {
return {
message: `Sorry, you can't use your own invite code`,
};
} else {
return {
message: `No User with that ID`
};
}
});
(This is not an answer, but a simple refactoring.)
This is what your code is currently doing (roughly, I didn't run it):
const resultMsgs = {
nomatch: 'No User With That ID',
ownmatch: 'Sorry, you can\'t use your own invite code',
match: 'Match Found',
}
function check(uids, providedId, userId) {
let result
uids.forEach(idFromDb => {
if (providedId !== idFromDb) {
result = 'nomatch'
return
}
if (userID === idFromDb) {
result = 'ownmatch'
return
}
result = 'match'
})
return result
}
export const getID = functions
.https
.onCall(async (data, context) => {
const userId = context.auth.uid
const providedId = 'cNx7IuY6rZlR9mYSfb1hY7ROFY2'
const db = admin.firestore()
const user = await db.collection('user').get()
const uids = user.docs.map(doc => doc.data().userId)
const checkResult = check(uids, providedId, userId)
return { message: resultMsgs[checkResult] }
})
(I removed the seemingly-spurious db collection operation.)
Your forEach is iterating over all of the uuids, but result will be set to whatever the last comparison was. Perhaps this is correct, but:
If you're looking for any match, this is not what you want.
If you're looking for all matches, this is not what you want.
If you're looking to match the last UUID, it's what you want, but an odd way to go about it.
So:
If you want any matches, use... ahem any form of an any function.
If you want all matches, use any form of an all function.
If you want the first match, then just check the first element.
If you want the complete set of comparisons then you'll need to use map instead of forEach, and handle each result appropriately, whatever that means in your case.
In any event, I'd recommend breaking up your code more cleanly. It'll be much easier to reason about, and fix.

First name mentions in a text using discord.js

I am trying to make some sort of kick system. I would like to know how I would get the first name mentioned in a text.
client.on("message", (message) => {
if (message.member.hasPermission(["KICK_MEMBERS"],["BAN_MEMBERS"])){
if(message.content == "!kick"){
let member = message.mentions.members();
console.log(member)
member.kick("You have been kicked").then ((member) => {
message.channel.send( member.displayName + " has been Kicked!");
})
}
}
});
No error is thrown that I know of.
First off, if you want to check multiple permissions in GuildMember.hasPermission(), you need to pass an array. The way your code is written now, you're passing an array with "KICK_MEMBERS" as the permissions to check and an array with "BAN_MEMBERS" for the explicit parameter.
Solution: message.member.hasPermission(["KICK_MEMBERS", "BAN_MEMEBRS"])
Secondly, you're declaring member as a Collection, when it should be a GuildMember.
Solution: const member = message.mentions.members.first()
client.on("message", async message => {
if (message.content === "!kick" && message.member.hasPermission(["KICK_MEMBERS", "BAN_MEMBERS"])) {
try {
const member = message.mentions.members.first();
if (!member) return await message.channel.send(`No user mentioned.`);
await member.kick(`Kicked by ${message.author.tag}`);
await message.channel.send(`${member.user.tag} has been kicked.`);
} catch(err) {
console.error(err);
}
}
});

Why doesn't kicking people work using discord.js

const Discord = require("discord.js"),
bot = new Discord.Client();
let pre = "?"
bot.on("message", async msg => {
var msgArray = msg.content.split(" ");
var args = msgArray.slice(1);
var prisonerRole = msg.guild.roles.find("name", "Prisoner");
let command = msgArray[0];
if (command == `${pre}roll`) {
if (!msg.member.roles.has(prisonerRole.id)) {
roll = Math.floor(Math.random()*6)+1;
msg.reply(`You rolled a ${roll}`)
} else {
msg.reply(`HaHa NOOB, you're in prison you don't get priveleges!`)
}
}
if (command == `${pre}kick`) {
var leaderRole = msg.guild.roles.find("name", "LEADER");
var co_leaderRole = msg.guild.roles.find("name", "CO-LEADER");
if (msg.member.roles.has(leaderRole.id) ||
msg.member.roles.has(co_leaderRole.id)) {
var kickUser = msg.guild.member(msg.mentions.users.first());
var kickReason = args.join(" ").slice(22);
msg.guild.member(kickUser).kick();
msg.channel.send(`${msg.author} has kicked ${kickUser}\nReason: ${kickReason}`);
} else {
return msg.reply("Ya pleb, you can't kick people!");
}
}
})
bot.login("token").then(function() {
console.log('Good!')
}, function(err) {
console.log('Still good, as long as the process now exits.')
bot.destroy()
})
Everything works except actually kicking the person. The message sends nut it doesn't kick people. For example, when I type in ?kick #BobNuggets#4576 inactive, it says
#rishabhase has kicked #BobNuggets
Reason: inactive
But it doesn't actually kick the user, which is weird, can you help me?
Change
msg.guild.member(kickUser).kick();
to
kickUser.kick();
also, make sure the bot is elevated in hierarchy
Use kickUser.kick();
I recommend using a command handler to neaten up your code. You don't want all your commands in one .js file.
Try something like this for the Ban command itself. I use this for my Bot:
client.on("message", (message) => {
if (message.content.startsWith("!ban")) {
if(!message.member.roles.find("name", "Role that can use this bot"))
return;
// Easy way to get member object though mentions.
var member= message.mentions.members.first();
// ban
member.ban().then((member) => {
// Successmessage
message.channel.send(":wave: " + member.displayName + " has been successfully banned :point_right: ");
}).catch(() => {
// Failmessage
message.channel.send("Access Denied");
});
}
});
That should work, set the role you want to use it (cAsE sEnSiTiVe) and change !ban to whatever you feel like using. If you change all "ban"s in this to kick, it will have the same effect. If this helped you, mark this as the answer so others can find it, if not, keep looking :)

Categories