Strings/Arguments for a new person - javascript

I need help with a command, for example, if someone writes
" !report #user Spamming " How can I do so my discord account gets a message from the bot about =
Who reports who and for what reason
I've tried watching videos and posts but I can't get my head around it
client.on('message', async function(message) {
if (message.content.startsWith(prefix + "report")) {
const user = await client.fetchUser(args[1].match(/^<#!?(\d+)>$/)[1]);
if (!user) return message.channel.send('Oops! Please mention a valid user.');
const reason = args.slice(2).join(' ');
const me = await client.fetchUser('123456890'); //My id
me.send(`${message.author} reported ${user} for: \`${reason}\``)
.catch(err => console.error(err));
}
}
)
I want for example
In channel = !report #patrick#4245 He is spamming
Then The bot sends a message to me
#fadssa#2556 Reported #patrick#4245 Reason = He is spamming

Before just copying this code, let's actually think this through...
So, let's start by first getting everything we need for the message. First, we should retrieve a User from the argument provided. We do this by comparing the string to that of a mention and picking out the ID. If one doesn't exist, we return an error telling the user to mention someone.
Now, assuming you already have your arguments declared (if not, see this guide to help), we can simply put together the arguments used for the reason. To do so, we should use Array.slice() and then join those words with Array.join().
Then, since we want the bot to send you a DM, we'll have to find you in the Discord world. For this, we can use client.fetchUser().
Now, we can just send you the DM and you'll be alerted of all reports.
/*
* Should be placed within your command's code, after checking required arguments exist
* Assuming 'client' is the Discord Client and 'args' is the array of arguments
* Must be within an async function to use 'await'
*/
const user = await client.fetchUser(args[1].match(/^<#!?(\d+)>$/)[1]); // see below
if (!user) return message.channel.send('Oops! Please mention a valid user.');
const reason = args.slice(2).join(' ');
const me = await client.fetchUser('189855563893571595'); // replace with your ID
me.send(`${message.author} reported ${user} for: \`${reason}\``))
.catch(err => console.error(err));
Although it may look confusing, using regex is a much better option than message.mentions. There's plenty of whack examples where seemingly perfect code will not return the expected user, so this is why I would definitely choose retrieving the ID from a mention myself.

Related

How to work with member role update part of audit log in discord.js

I am currently making a bot to notify people by sending a message when a member role is being updated on the server. I don’t know how to set up the initial part which should be formally client.on part.
Here I have shown a bit of my code that I think should be working but unfortunately it is not working.
const Discord = require(‘discord.js’);
const client = Discord.Client();
client.on('guildMemberUpdate', (oldMember, newmember) => {
This is what I’m expecting to do:
Before I give you the code, I'll give you the steps that I took to achieve it.
Tip: ALWAYS use the documentation. The discord.js documentation helped me a lot of times.
Process:
Set up a designated text channel. In my case, I manually grabbed the channel's ID and set it as the variable txtChannel. You will have to replace my string of numbers with your own channel ID.
I cached every single role ID from the "new" member as well as from the "old" member.
Checked whether or not the length of the new member roles array was longer than the old member roles array. This signifies that the member has gained a role.
Created a filter function that "cancels" out every single role ID that both new and old role arrays have in common.
Grabbed the icon URL - I found out that if you try to get the URL of a user who has the default discord icon, it'll return NULL. To bypass this, you could just grab some sort of invisible PNG online and set it as a placeholder. Else you'll get an error saying that it wasn't able to retrieve the proper URL link.
Set up the embed, and sent it into the text channel!
Note:
At first, I couldn't figure out why the bot wasn't registering for other users who have their roles changed. Then I found this question on Stack Overflow. The link states that you have to make sure to enable Guild Members Intent. Just follow the instructions from the link and you should be all set! It's a little bit outdated (in terminology), so when it references "Guild Members Intent" it actually is "Server Members Intent" now.
Code:
It's awfully elaborate, but it gets the job done.
client.on('guildMemberUpdate', (oldMember, newMember) => {
let txtChannel = client.channels.cache.get('803359668054786118'); //my own text channel, you may want to specify your own
let oldRoleIDs = [];
oldMember.roles.cache.each(role => {
console.log(role.name, role.id);
oldRoleIDs.push(role.id);
});
let newRoleIDs = [];
newMember.roles.cache.each(role => {
console.log(role.name, role.id);
newRoleIDs.push(role.id);
});
//check if the newRoleIDs had one more role, which means it added a new role
if (newRoleIDs.length > oldRoleIDs.length) {
function filterOutOld(id) {
for (var i = 0; i < oldRoleIDs.length; i++) {
if (id === oldRoleIDs[i]) {
return false;
}
}
return true;
}
let onlyRole = newRoleIDs.filter(filterOutOld);
let IDNum = onlyRole[0];
//fetch the link of the icon name
//NOTE: only works if the user has their own icon, else it'll return null if user has standard discord icon
let icon = newMember.user.avatarURL();
const newRoleAdded = new Discord.MessageEmbed()
.setTitle('Role added')
.setAuthor(`${newMember.user.tag}`, `${icon}`)
.setDescription(`<#&${IDNum}>`)
.setFooter(`ID: ${IDNum}`)
.setTimestamp()
txtChannel.send(newRoleAdded);
}
})

Discord.js; why does this not add the role?

I'm quite new to Stack Overflow, so excuse me if I do something wrong.
I've been working on Discord bots lately, and for my server I want to make a verification bot. I've got a large piece of the code all done and dusted, but now the important part doesn't work, and I don't know why.
My code:
const Discord = require("discord.js");
const client = new Discord.Client({ partials: ["MESSAGE", "CHANNEL", "REACTION"]});
const prefix = "v!";
client.on("ready", async () => {
console.log(`Logged in as ${client.user.tag}`);
client.user.setActivity("v!verify | Verify in #🔐┃verify-here", {type: "LISTENING"});
});
client.on("message", async(msg) => {
const args = msg.content.slice(prefix.length).trim().split(' ');
const command = args.shift().toLowerCase();
if(command === 'svm') { // svm = send verification message
if (msg.member.id !== '434239200607600651') return;
const sEmbed = new Discord.MessageEmbed()
.setTitle("Welcome to **aSpiv's Network**!")
.setDescription("aSpiv's Network is a place to hang out, talk and have fun with friends, family and strangers. Our goal is to make this community as friendly and welcoming as possible. Please, remember the human.")
.addField("🎗 Community Guidelines", "TL;DR Use common sense. If you think you'll get a warning for it, don't do it!\n\nTreat everyone with respect. This is the #1 rule of this server. Absolutely no harassment, witch hunting, sexism, racism, or hate speech will be tolerated.\n\nNo spam or self-promotion (server invites, advertisements, etc) without permission from a staff member. This includes DMing fellow members.\n\nNo NSFW or obscene content. This includes text, images, or links featuring nudity, sex, hard violence, or other graphically disturbing content. (Except for the places where it's allowed; see at own risk!)\n\nTalk English. We want to make sure everyone can participate in all conversations, so no one feels left out.\n\nDon't earrape in the voice chats. It's annoying for people who actually want to talk.\n\nNo voice changers. If you don't want people to hear your voice, then don't talk at all.\n\nIf you see something against the rules or something that makes you feel unsafe, let staff know. We want this server to be a welcoming place!")
.addField("🔐 Getting Verified", "To agree to the rules and receive permission to view all of our channels and send messages, go to <#792391986799837224> and send \`v!verify\`. You are responsible for reading the contents of this channel before agreeing. By being in this server, you agree to all our rules. These rules are subject to change.\n\naSpiv's Network or aSpiv Staff can not and will not be held responsible for any damages or losses that result from the use of our server. We will help you out the best we can, but we are only humans, too.")
.setColor(Math.floor(Math.random()*16777215))
msg.channel.send(sEmbed)
msg.delete();
}
if(command === 'verify') {
let sEmbed = new Discord.MessageEmbed()
.setTitle("Get Verified")
.setDescription("Click on the emoji below to get verified! Make sure you've read the embed in <#791281485276905492>!")
.setColor(Math.floor(Math.random()*16777215))
let m = await msg.channel.send(sEmbed)
m.react('✅')
}
return;
});
client.on("messageReactionAdd", async(reaction, user) => {
if(reaction.message.partial) await reaction.message.fetch();
if(reaction.partial) await reaction.fetch();
if(user.client) return;
if(!reaction.message.guild) return;
if(reaction.emoji.name === '✅') {
await reaction.message.guild.members.cache.get(user.id).roles.add(r => r.id === "792395200676495371")
}
})
client.login("n0t.4-r3al_t0k3n")
Does anyone see the mistake here? It should send a message, react to that message with ✅ (That part works), but when I react with the message too, it should give me a role, but it doesn't.
Thanks in advance for your help!
The Problem
The issue is in your messageReactionAdd event handler, which I assume you must already know given the only part of your code that isn't working is the code's response to your reaction. In that part of your code, you are doing if (user.client) return;. This line is incorrect, and will always return (because user.client is always true).
I'm guessing you want to return if the user that reacted is a bot. But user.client doesn't return whether or not the user is a bot; it returns the Client that created the user variable. Essentially, it returns your client variable. And since the User object stored in the user variable is always created by your client, that if statement will always return and prevent your actual role-adding code from occurring (just like what if (true) return; would do).
The Solution
Here's how to fix it, such that it actually checks if the user is a bot or not instead of trying to check if the client exists or not:
client.on("messageReactionAdd", async(reaction, user) => {
if(reaction.message.partial) await reaction.message.fetch();
if(reaction.partial) await reaction.fetch();
if(user.bot) return;
if(!reaction.message.guild) return;
if(reaction.emoji.name === '✅') {
await reaction.message.guild.members.cache.get(user.id).roles.add(r => r.id === "792395200676495371")
}
})
Simply changing user.client to user.bot will solve your issue, or will at the very least allow your role-adding code to actually run and allow you to see if there are any additional errors.
Relevant Resources
https://discord.js.org/#/docs/main/stable/class/User?scrollTo=bot
https://discord.js.org/#/docs/main/stable/class/User?scrollTo=client

How do I track the number of reactions on a message?

So I wanted to implement report&ban system and I decided to use an embedded message with reactions added to it. Moderator can either agree or disagree. For example once 10 moderators agree with the complaint the user mentioned in this message should be banned or kicked.
I thought of using client.on('messageReactionAdd', (messageReaction, user) => {}), but it only checks cached messages. Then I found discordjs.guide about reactions and they showed how to use client.on('raw', (event) => {}), but it's was abandoned long time ago and I didn't even found any mentions about this official Discord.js documentation. Message has .awaitReactions(filter, [options]), but I have to mark voting messages somehow and then searching them in a some kind client of method which is super complicated.
Here's what I have:
const service = client.channels.get('id');
let user = msg.mentions.users.first();
if (!user) {
msg.reply('Couldn\'t find the user!')
return 1;
}
args.shift();
let reason = args.join(' ').trim();
if (!reason) {
msg.reply('No reason to create a complaint!')
return 1;
}
msg.channel.send(`I've created and sent a user complaint about ${user.tag}!)`)
.catch((e) => console.log(e));
msg.delete();
const emb = new Discord.RichEmbed()
.setTitle('User complaint')
.addField('Who?', `**User: ${user.tag}**`)
.addField('Reason?', `**Reson: ${reason}**`)
.setColor('#ff7b00')
.setFooter('Please take action');
service.send(emb)
.then(async msg => {
await msg.react('✅')
msg.react('❌')
})
.catch(e => {
console.error()
msg.reply('Couldn\'t send a user complaint!');
return 1;
})
Is it even possible? I explained my previous plan earlier, but is there a way to make is simpler?
1. Database
You should use either message.awaitReactions(); or client.on('messageReactionAdd', ...); and fetch the message on the bot ready event.
It's a very simple process. You'd require a database to store the message ID's, channel ID and of course, server ID. After that make a small algorithm inyour ready event to go through all the messages collected from the database and use either message.awaitReactions(); or client.on('messageReactionAdd', ...); on them.
I'd suggest using message.awaitReactions(); if you decide to go with the database method.
2. Global Array (Less Recommended)
If you have a really simple bot and you can't use a database then I'd recommend having a global array storing all the message IDs and using those for the client.on('messageReactionAdd', ...); event.
You'd have to check if the ID from the message array matches the ID of the message collected in the event and then act accordingly.
This method would work well for the smaller bots, but if you have a bigger, multi-server bot, then I'd highly recommend going with the database version because this version would not work after the bot restarts.

How to get specific member username with discord.js

I would like to add one specific member information (username + avatar) into an embed message. Does someone know how to do that?
const feedback = new discord.RichEmbed()
.setColor([0, 0, 255])
.setFooter("Bot created by : " + message.author.username, message.author.avatarURL)
.setDescription("The text I want to be sent")
On the code above, I would like to change "message.author.username" and "message.author.avatarUrl" by a specific discord member identification id such as : 436577130583949315 for example.
However I don't know what is the way from that discord identification number to be able to show the username and the avatar.
Thanks in advance for your help :)
The following code must be modified to use the latest version of Discord.js (v12 at the time of this edit) due to the implementation of Managers.
You can retrieve a user by their ID from the client's cache of users, Client#users. However, every user isn't guaranteed to be cached at all times, so you can fetch a user from Discord using Client#fetchUser(). Keep in mind, it returns a Promise. If the user is in the cache, the method will return it.
Example:
// Async context needed for 'await'
try {
const devID = '436577130583949315';
const dev = await client.fetchUser(devID);
const feedback = new discord.RichEmbed()
.setColor([0, 0, 255])
.setFooter(`Bot created by ${dev.tag}.`, dev.displayAvatarURL)
.setDescription('Your text here.');
await message.channel.send(feedback);
} catch(err) {
console.error(err);
}

Referencing a DM channel

I'm trying to create a command that allows users to create their password following prompts through DM. I'm able to send a message to the user, but not able to read a message sent back with a MessageCollector because I cannot find a way to reference the DM channel.
I have tried using another instance of bot.on("message", message) here, but that creates a leak in the system causing the second instance to never disappear.
I also can't let users use a command say !CreatePassword *** because this function is linked with many others in a strict order.
Maybe I'm doing something fundamentally wrong, or approaching the problem in a bad way, but I need a way to reference a DM channel.
This is the best iteration of my code so far.
function createAccount(receivedMessage, embedMessage)
{
const chan = new Discord.DMChannel(bot, receivedMessage.author);
const msgCollector = new Discord.MessageCollector(chan , m => m.author.id == receivedMessage.author.id);
msgCollector.on("collect", (message) =>
{
// Other Code
msgCollector.stop();
// Removing an embed message on the server, which doesn't have a problem.
embedMessage.delete();
})
}
I can show the rest of my code if necessary.
Thank you for your time. I've lost an entire night of sleep over this.
I would do it like this (I'll assume that receivedMessage is the message that triggered the command, correct me if I'm wrong)
async function createAccount(receivedMessage, embedMessage) {
// first send a message to the user, so that you're sure that the DM channel exists.
let firstMsg = await receivedMessage.author.send("Type your password here");
let filter = () => true; // you don't need it, since it's a DM.
let collected = await firstMsg.channel.awaitMessages(filter, {
maxMatches: 1, // you only need one message
time: 60000 // the time you want it to run for
}).catch(console.log);
if (collected && collected.size > 0) {
let password = collected.first().content.split(' ')[0]; // grab the password
collected.forEach(msg => msg.delete()); // delete every collected message (and so the password)
await firstMsg.edit("Password saved!"); // edit the first message you sent
} else await firstMsg.edit("Command timed out :("); // no message has been received
firstMsg.delete(30000); // delete it after 30 seconds
}

Categories