im making discord bot with discord.js v12 and im trying to give role when member has 10 invites
i found invitation code from here and modified it:
if(message.channel.type != "dm" && message.channel.id === '768475421953915093') {
message.delete();
var user = message.author;
message.guild.fetchInvites()
.then
(invites =>
{
const userInvites = invites.array().filter(o => o.inviter.id === user.id);
var userInviteCount = 0;
for(var i=0; i < userInvites.length; i++)
{
var invite = userInvites[i];
userInviteCount += invite['uses'];
}
if(userInviteCount >= 10){
const guildMember = message.member;
guildMember.addRole('767542365812886656');
message.author.send(`you have access now`)
}else {
message.author.send(`sry u have ${userInviteCount} invitations. u need at least five`)
}
}
)
}
yes, it works but you can trick the system easily. If you keep rejoining from the server, the invite counter increases. How can i stop that?
To do this, you will need an external database since Discord API doesn't provide any information about who used that invite and how many times.
ALERT: It's a simple feature but can be very hard for people that don't have any coding experience, so if it's your first project, don't give up and keep trying! :D
You can use MongoDB Atlas, which is very simples and free.
And the logic will be very simple:
1 - Create a collection to store the invites data, you can do something like in this example
2 - Create a collection (you can give any name, but in this example, I will refer to this collection as new_members) to store the new members data, it should have the fields serverId (to store the guild ID), userId (to store the user ID) and inviteCode (to store the invite code or url)
3 - When a user joins the discord server, it will trigger the "guildMemberAdd" event, and you will get the invite that was used (with the example that I give in the first step), and create a new doc in the new_members collection.
4 - After creating this new data, you will search for all the docs from the same invite, and filter them by userId (there are many ways to do this, this is one of them).
5 - With this array of docs, you can use his length to determine how many people were invited, and give the role.
VERY SIMPLE EXAMPLE, THAT SHOULDN'T BE USED:
DiscordClient.on("guildMemberAdd", async (member) => {
/**
* https://github.com/AnIdiotsGuide/discordjs-bot-guide/blob/master/coding-guides/tracking-used-invites.md
* Here you will get the invite that was used, and store in the "inviteCode" variable
*/
const inviteCode = await getInviteUsed()
await NewMemberRepository.insert({
serverId: member.guild.id,
userId: member.id,
inviteCode: inviteCode
});
const joinedMembersFromTheInvite = await NewMemberRepository.find({
inviteCode: inviteCode
});
/**
* https://stackoverflow.com/questions/43374112/filter-unique-values-from-an-array-of-objects
* Here you will filter the results by userId
*/
const invitesWithUniqueUsers = filterJoinedMembersByUserId(joinedMembers)
if (invitesWithUniqueUsers >= REQUIRED_INVITES_QTD) {
/**
* Gives the role to the creator of the invite
*/
}
});
Hope it helps, good luck! :D
OBS:
Yes, Discord API provides how many times an invite was used, but not how many a specific person used this invite.
In the examples, I used something like TypeORM, but if you are using JavaScript instead TypeScript, you can use Mongoose
Related
Im trying to make discord.js code. When a member joins the voice channnel I want the bot to give them a role, when the member leaves, i want the role to be removed. thanks for your help.
const newChannelID = newState.channelID;
const oldChannelID = oldState.channelID;
if (oldChannelID === "835280102764838942"){
member.send('role given');
let role = message.guild.roles.cache.find(r => r.id === "835279162293747774");
member.roles.add(835279162293747774);
} else if(newChannelID === "835280102764838942"){
member.send('role removed');
member.roles.remove(835279162293747774);
}
})
There's a couple of things you need to clean up in your code. I'm going to assume you're using the voiceStateUpdate event to trigger your command.
Most importantly, (logic-wise) you actually need to flip-flop the way you add and remove roles. Currently, the general code states that if the user left the voice channel (thus oldChannelID = actual vc ID), then it would actually give the user a role. This seems to be the opposite of your intention, thus you'd simply swap out the code in each if/else if statement.
Second, the way you're assigning roles and adding them is incorrect. I'd recommend this resource for more info.
Third, you cannot access message if you were indeed using voiceStateUpdate as your event, since it only emits an oldState and a newState.
Lastly, you need to designate a text channel to send the message to. In my code, I manually grabbed the ID of the channel I wanted and plugged it into the code. You'll have to do the same by replacing the number strings I have with your own specific ones.
With that being said, here's the correct modified code:
client.on('voiceStateUpdate', (oldState, newState) => {
const txtChannel = client.channels.cache.get('803359668054786118'); //manually input your own channel
const newChannelID = newState.channelID;
const oldChannelID = oldState.channelID;
if (oldChannelID === "800743802074824747") { //manually put the voice channel ID
txtChannel.send('role removed');
let role = newState.guild.roles.cache.get("827306356842954762"); //added this
newState.member.roles.remove(role).catch(console.error);
} else if (newChannelID === "800743802074824747") {
txtChannel.send('role given');
let role = oldState.guild.roles.cache.get("827306356842954762"); //change this somewhat
oldState.member.roles.add(role).catch(console.error); //adding a catch method is always good practice
}
})
if(message.content == `${config.prefix}mods`) {
const ListEmbed = new Discord.MessageEmbed()
.setTitle('Mods:')
.setDescription(message.guild.roles.cache.get('813803673703809034').members.map(m=>m.user.tag).join('\n'));
message.channel.send(ListEmbed);
}
Hey so iam making a command which displays all the members with that role but it only seems to be sending 1 of the mods
await message.guild.roles.fetch();
let role = message.guild.roles.cache.find(role => role.id == args[0]);
if (!role) return message.channel.send('Role does not exist'); //if role cannot be found by entered ID
let roleMembers = role.members.map(m => m.user.tag).join('\n');
const ListEmbed = new Discord.MessageEmbed()
.setTitle(`Users with \`${role.name}\``)
.setDescription(roleMembers);
message.channel.send(ListEmbed);
};
Make sure your command is async, otherwise it will not run the await message.guild.roles.fetch(); - this fetches all roles in the server to make sure the command works reliably.
In Discord.jsV12 the get method was redacted and find was implemented.
Aswell as this, I would highly recommend defining variables to use in embeds and for searching since it is much more easy to error trap.
If you have many members with the role, you will encounter the maximum character limit for an embeds description. Simply split the arguments between multiple embeds.
I'm somewhat new to coding and I am making a bot in discord.js v12 and I was wondering how I could add verification for new users who join the server. Weather than be sending them a captcha they must complete or just adding a reaction role that they click and it gives them x role such as "member" or "verified." Thanks in advance :D
I have actually just recently created one of those using a very simple method of creating two questions and answers arrays and checking if the user's input matches the answer.
So, first off you'll want to create 2 arrays:
const questions = ['Do you like melon?', 'Do you want melon?']
const answers = ['Yes!', 'What do you want from me...']
Then you can get a randomized question that would match the answer:
var randomIndex = Math.floor(Math.random() * questions.length)
var randomQuestion = questions[randomIndex]
var randomAnswer = answers[randomIndex]
And finally, you can send the question and check if the answer matches:
message.channel.send(randomQuestion)
client.on('message', message => {
if (message.content === randomAnswer) {
let role = message.guild.roles.cache.find(r => r.name === "Member")
message.member.roles.add(role)
message.channel.send('Congratulations! you've completed the verification!');
} else {
message.channel.send('Verification failed. Incorrect answer.');
}
});
I'm developing a bot where at a set interval, like every hour the bot will pick a random user and remove a role from them, it will be using the positioning on the side to do this. The problem was I couldn't really find a function in Discord.JS that had a property for a guild member's position on the side.
I've tried finding other bots that do this and try to mimic them, but I didn't find anything.
I double checked the documentation but didn't find anything.
var thatguild = message.guild.id.find(`576463944298790929`);
thatguild.fetchMembers();
setInterval(function() {
let sizes = thatguild[Math.floor(Math.random() * thatguild.members.size())];
if(thatguild.member.id == `userid1` || `userid2`)
return(thatguild.member.removeRole('roleid'))
}, 1000)
I expect a bot where it randomly picks a user by the position, and remove a role from the member.
What I actually get is code and no way of knowing if it works or not.
Explanation:
Let's go through what we need to do if we want to accomplish what you want.
Acquire the desired guild.
A collection of guilds (GuildStore in master) a client is handling is available with Client.guilds.
To find a value by its key, use Map.get().
To find a value by another property or testing of an expression, use Collection.find().
To simply use the guild the message was sent in within a message event, use message.guild.
Acquire the desired role.
A collection of roles within a guild (GuildMemberRoleStore in master) a client is handling is available with Guild.roles.
Refer to the options previously listed to obtain a value from the collection.
Select a random member.
A collection of a guild's members (GuildMemberStore in master) is available with Guild.members.
Before selecting a member, the possible choices need to be limited to those with the role, so use Collection.filter().
To select a random value from a collection, use Collection.random().
Remove the role from the member.
To remove a role from a member, use GuildMember.removeRole() (GuildMember.roles.remove() in master).
If something goes wrong, make sure to catch the returned promise with a try...catch statement or catch() method.
Set an interval.
To set an interval, use setInterval().
In case something goes wrong, assign it to a variable so it can be cleared later.
Code:
function roleRoulette(guild, role) {
const possible = guild.members.filter(m => m.roles.has(role.id));
if (possible.size === 0) return clearInterval(interval);
const member = possible.random();
member.removeRole(role)
// MASTER: member.roles.remove(role)
.then(() => console.log(`Removed ${role.name} from ${member.tag}.`))
.catch(err => {
console.error(err);
clearInterval(interval);
});
}
const guild = client.guilds.get('576463944298790929');
if (!guild) return;
const role = guild.roles.get('576464298088333323');
if (!role) return;
const interval = setInterval(roleRoulette(), 60 * 1000, guild, role);
Discord.js Docs:
stable
master
It's honestly a bit hard to understand what you exactly want. I understand you want the bot to remove a random role from a random member at a set interval. Also, you want to do that based on the role hirarchy somehow, I'm guessing the highest role first? If that is the case, what you could try is this:
let randomMember = message.guild.members.cache.random()
if(randomMember.roles.cache.length === 0) return
let roleToRemove = randomMember.roles.cache.first()
for (let r in randomMember.roles.cache){
if(r.position < roleToRemove.position) roleToRemove = r;
}
await randomMember.roles.remove(roleToRemove)
Well, no matter what, if you are looking to remove roles based on their position then role.position will be required for your code in some way.
https://discord.js.org/#/docs/discord.js/main/class/Role?scrollTo=position
Good luck :)
Edit: Don't forget to exclude bots and bot roles from the removal when you implement something like this!
This is probably what I wanted:
Every hour, the bot picks a random user from the entire guild, removes a specific role from them, and repeats.
It's still hard to understand what past-me actually wanted, but here's another answer.
I don't know what version of D.JS was hot at the time, but I'm gonna use v9 in my answer.
You want an interval removing members every hour, so 1000 * 60 * 60 means 1000 milliseconds, 60 times -> 60 seconds(1 minute) * 60 times -> 1 hour.
This function inside the interval needs* to be async, so we can request a guild with ALL the members.
Then, we get the members collection and filter it in a way to remove users that don't have the role we're looking for OR if they are in an ignore list.
If no members have a role, don't do anything.
Else, pick a random member and remove the role. Repeat.
var ignore = ['...'];
var guildSel = client.guilds.get('...');
var role2Remove = '...';
setInterval(async () => {
var guild = await guildSel.fetchMembers();
var members = guild.members.filter(m=>m.roles.has(role2Remove) && !ignore.includes(m.id));
if(members.size > 0) {
var randUsr = members.random();
randUsr.removeRole(role2Remove);
} else return;
}, 1000 * 60 * 60);
I am making a "user info" command that returns the user's Discord username, their ID, their server join date and whether or not they are online. I am able to display all the information through user.id, user.username, and user.presence.status. But when I try to use user.joinedAt I get undefined in the display.
I know this is because the User class and the GuildMember class are not the same, and that the GuildMember class contains a User object.
But my problem is: how I could get the .joinedAt data from my user mention?
Here is my current code:
let user = message.mentions.users.first();
let embed = new Discord.RichEmbed()
.setColor('#4286f4')
.addField("Full Username:", `${user.username}#${user.discriminator}`)
.addField("User ID:", `${user.id}`)
.addField("Server Join Date:", `${user.joinedAt}`)
.addField("Online Status:", `${user.presence.status}`)
.setThumbnail(user.avatarURL);
message.channel.send(embed);
Here's the code for my user info command:
if (msg.split(" ")[0] === prefix + "userinfo") {
//ex `member #Rinkky
let args = msg.split(" ").slice(1) // gets rid of the command
let rMember = message.guild.member(message.mentions.users.first() || message.guild.members.get(args[0])) // Takes the user mentioned, or the ID of a user
let micon = rMember.displayAvatarURL // Gets their Avatar
if(!rMember)
return message.reply("Who that user? I dunno him.") // if there is no user mentioned, or provided, it will say this
let memberembed = new Discord.RichEmbed()
.setDescription("__**Member Information**__")
.setColor(0x15f153)
.setThumbnail(micon) // Their icon
.addField("Name", `${rMember.username}#${rMember.discriminator}`) // Their name, I use a different way, this should work
.addField("ID", rMember.id) // Their ID
.addField("Joined at", rMember.joinedAt) // When they joined
await message.channel.send(memberembed)
};
This will send an embed of their user info, this is my current code and
rMember.joinedAt
does work for me.
edit:
After looking at your question again, I found out I didn't need to post everything, you can't get the joined at because it's just the mention. Try this:
let user = message.guild.member(message.mentions.users.first())
Should work
You can technically find it by fetching getting the member from the guild and then using GuildMember.joinedAt: since the User class represents the user in every guild, you will always need the GuildMember to get info about a specific guild.
let user = message.mentions.users.first(),
member;
if (user) member = message.guild.member(user);
if (member) embed.addField("Server Join Date:", `${member.joinedAt}`);
With this said, I would not suggest you to do that, since it's not really efficient. Just take the mention from the members' collection and then take the user from that.
let member = message.mentions.members.first(),
user;
if (member) user = member.user;
The downside of this is that you can't use it if you want your command to be executable from the DMs too. In that case you should use the first method.
const member = message.channel.guild.members.cache.find(member => member.user == message.mentions.users.first())