Check if a mention is a user - discord - javascript

I want to make a simple kick function that kicks a player with mention.
But I first want to check if a mention is a user. which I have no idea how.
let member = message.mentions.members.first();
if ("member.something") { // if member is a user in the server.
member.kick().then((member) => {
channel.send(`${member} has been kicked! :wave:`)
});
} else {
channel.send(`Error: ${member} can't be kicked!`)
}

Here are the options that I can think of:
User.bot Documentation
if (!member.user.bot)
To check if the user is not a bot
GuildMember.kickable Documentation
if (member.kickable)
To check if the member is kickable
To check if a member exists first, check out:
https://stackoverflow.com/a/53284678/11425141

You can do this in multiple ways.
You can either check for which permissions have in order to disallow other's from kicking them (For instance, KICK_MEMBERS). That would look something like this:
let member = message.mentions.members.first();
if (member.hasPermission("KICK_MEMBERS)) return message.channel.send("That member can also kick!")
You can also check if they got a certain role which disallows them to be kicked. (Could be moderator role, could be a protected role)
//Get role by ID (Allows you to later change its name, ID will remain the same)
let modRole = message.guild.roles.get("MODROLE_ID");
if (member.role.has(modRole.id)) return message.channel.send("This member is a moderator")
//Find role by name. Means if you change the name of this, you need to change code too.
let protectedRole = message.guild.roles.find(r => r.name === "Protected from kicking")
if (member.role.has(protectedRole.id)) return message.channel.send("This member is protected")
Lastly (that I know of), you can check if they're kickable. But all that does is, say if someone above them is trying to kick them, it will do it.
So if, say an admin, is testing or something, it will just kick the user if kickable = true
if (member.kickable) {
member.kick()
} else {
message.channel.send("This member is above you!)"
}
If you just want to check if they're an actual user, throw this line in at the top:
if (!member.bot) {
//If they're a user
} else {
//If they're a bot
}
There are obviously a lot of fun things you can do with this. But these are the basics.
Hope I helped a bit, and sorry for this late response, I was pretty much just scrolling through the forum and found this unanswered question.

Related

Detect if member has a role

I am building a Discord bot, more specific, a rolecolor command. I made a version of this command, that worked. Only problem was that it was extremly inefficient, it took like 5 minutes for it to respond. This was because there where a lot of 'if' statements and other things the bot had to check before executing anything. The file had 129K+ lines, and my whole editting program was lagging. I now have a new plan, that is probably much more efficient:
The bot checks if a member has any roles that start with "SRC -". SRC means server role color, just a name every role has that is dedicated to being cosmetic. All my colorrole names start with "SRC - name" If it detects any, delete them. Await this process, and after that, add the new color. I have like 205 roles for colors. I CAN just do:
message.guild.members.cache
.get(user.id)
.roles.remove(roleone);
message.guild.members.cache
.get(user.id)
.roles.remove(roletwo);
This works, but then again, inefficient. Discord isn't that fast with deleting and adding roles. When I ran a test, it didn't give me any errors. Despite this, I thought something was going wrong because my roles wheren't changing. When I was running a debug, and checked again, the roles where finally updated. It just takes a while before updating. I would like to have this more efficient. Here are some code samples:
Role adding, after the role removal:
if (args[0] === "1") {
message.guild.members.cache
.get(user.id)
.roles.add(roleone);
message.channel.send(errmsg);
console.log(logmsg);
else if (args[0] === "2") //etc
So my question is, does someone know how to detect if the member has any roles that start with name, so that only those roles can be deleted?
.remove() takes either a RoleResolvable, Array of RoleResolvables, or a Collection of RoleResolvables. You can filter the roles and pass it in
const member = message.guild.members.resolve(user.id)
const roles = member.roles.cache.filter(r => r.name.startsWith(`SRC -`))
await member.roles.remove(roles) // remove all roles from the member that start with "SRC -"

Hiding messages from a discord user through javascript - Soft blocking

Blocking a user is a good feature of discord, but often enough I find myself wanting to block someone temporarily: not see their messages, but only for a certain period of time and without them knowing that I did so. Theoretically such a thing should be possible to do. I found a userscript that you are supposed to paste into the discord console once you start discord that serves the purpose of hiding messages from blocked users completely. Using the same principle, if instead of searching for blocked messages I could search for messages from a specific user, and then hide them, I could soft-block them for the duration of my current session. So the idea of this is to search all messages in a channel, check if a message was posted by a certain user that I want blocked, and if so, hide it.
To do so I have to figure out how to tie messages to their authors. There appears to be a different class for each new message that a user sends. But when a user sends multiple messages in a row, the classes are different. The first message contains the link to the user's avatar, which in turn contains the user's unique discord ID that he could be identified with. But his follow-up messages don't contain his avatar. And I can't find anything else that I could use to identify a user with except for that.
In the image above the classes that have groupStart contain the avatar links, whereas the classes without it are the follow-up messages from the same user that do not. Like so:
What kind of a loop would be able to include both the messages with some specified avatar, and the follow up messages without it?
As I see it, here's how you'll have to do it:
first identify the groupStart message, and then keep looking at the next messages until you reach a new groupStart message.
Luckily JavaScript keeps elements in the order that they're displayed when you use document.getElementsByClassName so you should just be able to set a variable to true when you hit the target, and then back to false when you hit a new person. This is my code:
function block(userid) {
return setInterval(() => {
let deleteMessages = false;
[...document.getElementsByClassName('message-2qnXI6')].forEach(i => {
if(i) {
if(i.className.match('groupStart-23k01U')) {
if(([...i.children].find(i => i.className.match('contents-2mQqc9')).children[0].src || '/1/').split('/').find(i => i.match(/^\d+$/)) === userid) {
i.style.display = 'none'
deleteMessages = true
} else deleteMessages = false
}
else if(deleteMessages) i.style.display = 'none'
}
})
deleteMessages = false
}, 300)
}
The function block sets an interval for 300 seconds to:
First, get all the messages: [...document.getElementsByClassName('message-2qnXI6')]
Then for each message check to see if it's a groupStart element: if(i.className.match('groupStart-23k01U'))
If it is, it'll check to see if it's a message from the blocked user:
if(([...i.children].find(i => i.className.match('contents-2mQqc9')).children[0].src || '/1/').split('/').find(i => i.match(/^\d+$/)) === userid)
If it is, it'll delete that message and set deleteMessages to true:
i.style.display = 'none'
deleteMessages = true
If it isn't, it'll set deleteMessages to false, so that the next messages don't get deleted.
Going back, if the message isn't a groupStart message, it'll check to see if deleteMessages is true (which would be the first message in the group was from a blocked user, and therefore this message is from a blocked user). If it is, it'll delete it.
Everything should be reset with a simple ctrl+r
Just copy and paste this (the minified version of my code):
function block(e){return setInterval(()=>{let t=!1;[...document.getElementsByClassName("message-2qnXI6")].forEach(n=>{n&&(n.className.match("groupStart-23k01U")?([...n.children].find(e=>e.className.match("contents-2mQqc9")).children[0].src||"/1/").split("/").find(e=>e.match(/^\d+$/))===e?(n.style.display="none",t=!0):t=!1:t&&(n.style.display="none"))}),t=!1},300)}
into the console, and then to block someone type block('<userid>') (make sure the user id is a string and not a number), and it should start working. Also, when you do, it should return a number, just type clearInterval(number) to stop it from blocking new messages.
If you're wondering about this line:
if(([...i.children].find(i => i.className.match('contents-2mQqc9')).children[0].src || '/1/').split('/').find(i => i.match(/^\d+$/)) === userid)
There's a few hackey things I did here:
I start by getting an array of all the messages children, then I find the child with the userID in it (i.className.match('contents-2mQqc9')). If I don't I just use a placeholder to avoid errors.
Then I split via /s because the user id is one of the paths. Then I find which part of the path is the user id by checking to see if it's only numbers (i.match(/^\d+$/)). Finally once I've done all that I check to see if it's the same as the userid.
Here's a quick example:
https://cdn.discordapp.com/avatars/847295719724247388/c9af8fff1110025e6aae862492b4aa29.webp?size=256 (this isn't a real link) => ['https:', '', 'cdn.discordapp.com', 'avatars', '847295719724247388', 'c9af8fff1110025e6aae862492b4aa29.webp?size=256'] => '847295719724247388' is made completely of numbers, so: '847295719724247388'
Unfortunately, if you use this on too many messages by the same person in a row discord will really glitch out, so you'll have to watch for that (note this was testing it on 1000+ messages in a row by the same person). It seems like problems start to happen at around 100, but don't become an issue until it's up to 200 - 300, and even then it'll sometimes work if you wait for a second.
Hopefully if this doesn't work for you you'll at least have an idea of what to do.

Discord.js - How do you use guildUpdate from the client class?

I’m setting up logging for my Discord bot and I don’t know how to use guildUpdate from the client class. The docs say to use the oldGuild and newGuild parameters, but how do you actually check what is being changed (like the server name, region, etc) and display that change? Here’s an example from another bot: https://imgur.com/a/Hj1yhZq
Any help would be appreciated. Thanks!
In JavaScript, there is no built in function to compare the two guild objects, so you would have manually look for the differences in the different parameters. For example:
client.on("guildUpdate", (oldGuild, newGuild) => {
if (oldGuild.description !== newGuild.description) {
let embed = new Discord.MessageEmbed()
.setTitle("changes")
.setDescription(`Description changed from ${oldGuild.description} to ${newGuild.description}`)
somechannel.send(embed)
}
});
guildUpdate gives you 2 parameters. One is the guild before it was updated, and one is the guild after it was updated.
To see which value has been updated, you can check if the new value equals the old value. If it doesn't, it has been updated.
client.on("guildUpdate", (oldGuild, newGuild) => {
if (oldGuild.name !== newGuild.name) console.log(`The guild name has been updated. From ${oldGuild.name} to ${newGuild.name}`);
if (oldGuild.region !== newGuild.region) console.log(`The region has been updated. From ${oldGuild.region} to ${newGuild.region}`);
// etc
});

Use plain text instead of mentions to define user

Here is the code for the command:
if (command === "avatar") {
let user = message.mentions.users.first() || message.author;
let embed = new Discord.RichEmbed()
.setAuthor(`${user.username}`)
.setImage(user.displayAvatarURL)
.setColor(0x842cfc);
message.channel.send(embed),
}
This command shows the avatar of a specified user, but with how it is now, you have to tag the specified user (making them receive a notification) to show the avatar. Right now the command is .avatar #someuser but I want the command to be .avatar someuser, so it doesn't mention them.
Also, I'm pretty sure I need to use client.users.find() somehow but idk how to. Thank you for any help!
I would use Guild.members.find(). Since that contains the members, you will need to check whether the argument the user wrote matches the .nickname or the .user.username. To simplify things a little I will use .displayName instead of .nickname, so that I can always work with strings.
// argument: the string after the command, I don't know how you're currently getting it
let user = message.guild.members.find(m => [m.displayName.toLowerCase(), m.user.username.toLowerCase()].includes(argument.toLowerCase()));

How to create a command that only who have one of the roles can use?

let staffrole = ['383874699941117952', '149622819158884353', '149622998180036608'];
How do you make a command that only people who have one of the roles can use it?
Thank you!
What you can do is that, on a message event, you run the command, and you can check the member's roles for one of the ones in the array.
Heres what that would look like:
client.on("message", msg => {
if(command === "whateverItIs") {
let staffrole = ['383874699941117952', '149622819158884353', '149622998180036608'];
for(i=0;i<staffrole.length;i++) {
if(msg.member.roles.filter((role) => role.id == staffrole[i]).size > 0) {
//run the code
return;
}
}
}
})
On a message event, with the determined command, the bot will check through each of the staff roles and if the message author 's roles includes one of the staffrole's then the command will run.
I would recommend doing something like this:
First, set your command name in the client's message listener:
// ... (in client message listener)
switch(command) {
case '<your command>':
runIfRoleIncluded(message);
break;
}
Next, get the role Id from the message that was sent and check if that message's role Id is in your staffrole array:
function runIfRoleIncluded(message) {
let rolesCollection = message.member.roles;
let staffrole = ['383874699941117952', '149622819158884353', '149622998180036608'];
// only 1 member can send a message, so get role collection's first key (id)
let messageRoleId = rolesCollection.firstKey();
// check if message's role id is in staff role array
if (staffrole.includes(messageRoleId)) {
// do stuff here
// ...
}
}
The .roles property of the .member object is a Collection, which is why you have to use the .firstKey() method. You can also turn the Collection into a normal js Array, but the way I outlined above is easier.
Started looking at this... Don't know the discord space very well but got an example bot and with a hello world ping, also found this pretty sweet Github gist that lays out fairly well how to build what amounts to a command switch statement. Making a lot of guesses here -- as a note for future questions it would be very helpful for you to add in some code on what you are trying to do -- a single variable set to an array isn't much to go on...
After Reading what #Raymond Zhang said, because, yeh that's what I was doing...
this is straight out of the Github gist I linked ->
...
if(command === "kick") {
if(!message.member.roles.some(r=>["Administrator","Moderator"].includes(r.name)) )
return message.reply("Sorry, you don't have permissions to use this!");
...
I have tested this and it works great, although it checks against the roles name not a number. It would help if you updated you answer to explain your process. More info = better answer. :)

Categories