I tried to make a bot that can kick users and I have a probem with checking if user has a permision to do so. I have aready searched for it trough the whole internet and everywere it was sad to use .has but it doesn't seems to work, console always returns error: Cannot read properties of undefined (reading 'has').
Here's my code:
const { SlashCommandBuilder } = require("#discordjs/builders");
const { Permissions } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName("kick")
.setDescription("Kicks someone")
.addUserOption(option =>
option
.setName("user")
.setDescription("Select the user")
.setRequired(true)),
async execute(interaction){
const user = interaction.options.getUser("user");
const userId = interaction.guild.members.cache.get(user.id);
if(!interaction.user.permissions.has(Permissions.FLAGS.KICK_MEMBERS)) return interaction.reply("You dont have perrmisions to kick KEKW!");
if(!interaction.guild.permissions.me.has(Permissions.FLAGS.KICK_MEMBERS)) return interaction.reply("I dont have perrmisions to kick KEKW!");
if(userId == interaction.user.id) return interaction.reply(
{
content: "You cant kick yourself bro!",
ephemeral: true
});
interaction.reply({
content: `You have succesfuly kicked user: ${user}!`,
ephemeral: true
});
userId.kick();
}
}
Here's the error:
https://ibb.co/86xPdJv
interaction.user is a User object, so methods only available to GuildMember, like permissions.has cannot be applied to the interaction.user. Change it to interaction.member will solve the problem. It's also a good idea to read more about User and GuildMember objects and their differences in the discord.js documentation and guide. I've linked these below:
discord.js documentation pages on topic:
https://discord.js.org/#/docs/discord.js/stable/class/User -User
https://discord.js.org/#/docs/discord.js/stable/class/GuildMember -GuildMember
discord.js guide on topic:
https://discordjs.guide/popular-topics/faq.html#what-is-the-difference-between-a-user-and-a-guildmember
Related
I'm trying to make a blacklist command, and how do I make it so it sends an embed instead of normal message.
(Also, I'm new to discord.js)
Here's my script:
module.exports = {
data: new SlashCommandBuilder()
.setName('blacklist')
.setDescription('Blacklist someone from the server')
.addUserOption((option) => option.setName('member')
.setDescription('Who are you blacklisting?')),
async execute(interaction) {
await interaction.deferReply();
const member = interaction.options.getMember('member');
if (!interaction.member.roles.cache.some(r => r.name === "Blacklist perms")) {
return interaction.editReply({ content: 'You do not have permission to use this command!' });
}
member.send("You have been blacklisted!")
member.kick().catch(err => {
interaction.editReply({ content: `I do not have enough permissions to do that.`})
})
await interaction.editReply({ content: `${member} has been succesfully blacklisted!` });
},
};```
Since your function is already async, simply await sending the message before you call kick.
await member.send("You have been blacklisted!")
member.kick().catch(err => {
interaction.editReply({ content: 'I do not have enough permissions to do that.'})
})
You might also wanna catch() on the send method because users can have DMs from server members disabled or blocked your bot.
You also might consider banning the user instead, because this system would fail if your bot ever happens to go offline when a blacklisted user tries to join. Additionally, depending on how fast your bot reacts, the user may still have time to spam in channels or do something harmful before your bot is able to kick them.
To send an embed either use an EmbedBuilder or a plain JavaScript object with the correct embed structure.
Example:
member.send({ embeds:[{
title: "Title",
description: "Hello World!"
}] })
(the code)
const Command = require("../Structures/Command.js");
module.exports = new Command({
name: "give-role",
description: "gives you the role",
permission: "ADMINISTRATOR",
async run(message, arguments, client) {
const targetUser = message.mentions.users.first();
if (!targetUser) {
message.reply("Tag the user that you want to give the role to");
return;
}
arguments.shift();
const roleName = arguments[1];
const { guild } = message;
const role = guild.roles.cache.find((role) => {
return role.name === roleName;
});
if (!role) {
message.reply(`There is no role called: ${roleName}`);
return;
}
const member = guild.members.cache.get(targetUser.id);
member.roles.add(role);
message.reply(`That user now has the role : ${roleName}`);
}
});
(error message)
/home/runner/Discord-manager/node_modules/discord.js/src/rest/RequestHandler.js:350
throw new DiscordAPIError(data, res.status, request);
^
DiscordAPIError: Missing Permissions
at RequestHandler.execute (/home/runner/Discord-manager/node_modules/discord.js/src/rest/RequestHandler.js:350:13)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async RequestHandler.push (/home/runner/Discord-manager/node_modules/discord.js/src/rest/RequestHandler.js:51:14)
at async GuildMemberRoleManager.add (/home/runner/Discord-manager/node_modules/discord.js/src/managers/GuildMemberRoleManager.js:124:7) {
method: 'put',
path: '/guilds/911548130917498901/members/854133415364263976/roles/924275494810165259',
code: 50013,
httpStatus: 403,
requestData: { json: undefined, files: [] }
}
The error is DiscordAPIError: 50013, the error is getting because the prompt says the bot do not have permissions but I added administrator but it still says it doesn't have permissions and I do not know why. Please help me (sorry if my english is bad :() )
The bot may be trying to give a role higher than the one your bot has. To fix this, drag the bot's highest positioned role over the role you are trying to give.
Credit: Reddit Comment
You need to check the position of the role before trying to add it to the user, for example:
if (message.guild.me.roles.highest.position <= role.position) {
message.reply(`${role.name} is higher than or equal to my highest role.`);
return;
}
Aim: To ban every time a user is caught on the audit log attempting to create a channel
Code:
// Channel Create
client.on("channelCreate", async (channel) => {
const FetchingLogs = await client.guilds.cache.get(channel.guild.id).fetchAuditLogs({
limit: 1,
type: "CHANNEL_CREATE",
})
const ChannelLog = FetchingLogs.entries.first();
if (!ChannelLog) {
return console.log(red(`CHANNEL: ${channel.id} was created.`));
}
const { executor, target, createdAt } = ChannelLog;
if (target.id === channel.id) {
console.log(greenBright(`${channel.id} got created, by ${executor.tag}`));
} else if (target.id === executor.id) {
return
}
if (executor.id !== client.user.id) {
channel.guild.member(executor.id).ban({
reason: `Unauthorised Channel Created`
}).then(channel.guild.owner.send(`**Unauthorised Channel Created By:** ${executor.tag} \n**Channel ID:** ${channel.id} \n**Time:** ${createdAt.toDateString()} \n**Sentence:** Ban.`)).catch();
}
});
Result:
It bans the user successfully but still throws an error.
Error:
TypeError: Cannot read property 'id' of undefined
Code: Error Specified | Referring to channel.guild.id
const FetchingLogs = await client.guilds.cache.get(channel.guild.id).fetchAuditLogs({
limit: 1,
type: "CHANNEL_CREATE",
})
I'm guessing the reason for this is that the parameter ,channel, type is DMChannel and not GuildChannel
Is there any way to fix this or be able to change the parameter type to GuildChannel??? I've checked the Docs and I can't seem to find anything that indicates this is possible. Any help is appreciated ;)
Your assumption of why this error is occurring is correct. The channelCreate event does indeed handle the creation of both GuildChannel and DMChannel, and your code sends the guild owner a DM after banning the user. That's why the ban works but you get an error afterwards; because the DM creates a DMChannel with the owner, triggering the event handler again but with channel.guild being undefined since DMs do not have guilds.
So let me state the problem again. You are getting the error Cannot read property 'id' of undefined which you've figured out means channel.guild is undefined. You don't want the error to occur, so you don't want channel.guild to be undefined. But in your question you're asking:
Is there any way to fix this or be able to change the parameter type to GuildChannel???
That's not the approach you want to take. Doing that would mean users would get banned for DMing your bot because it would trigger your channelCreate event handler; plus, the bot would try to ban the guild owner since it sends the owner a DM. And you only want to ban users for creating channels in the guild.
When we put the problem that way, the solution is simple: check if the channel is a DMChannel, and discontinue if it is. Only allow users to get banned for creating a GuildChannel. So how do you do that? Well, as you've seen from your error already, channel.guild is undefined when the channel is a DMChannel. So simply check for this condition, and return if it is the case. Here's an example:
// Channel Create
client.on("channelCreate", async (channel) => {
if (!channel.guild) return; //<- added this
const FetchingLogs = await client.guilds.cache.get(channel.guild.id).fetchAuditLogs({
limit: 1,
type: "CHANNEL_CREATE",
})
const ChannelLog = FetchingLogs.entries.first();
if (!ChannelLog) {
return console.log(red(`CHANNEL: ${channel.id} was created.`));
}
const { executor, target, createdAt } = ChannelLog;
if (target.id === channel.id) {
console.log(greenBright(`${channel.id} got created, by ${executor.tag}`));
} else if (target.id === executor.id) {
return
}
if (executor.id !== client.user.id) {
channel.guild.member(executor.id).ban({
reason: `Unauthorised Channel Created`
}).then(channel.guild.owner.send(`**Unauthorised Channel Created By:** ${executor.tag} \n**Channel ID:** ${channel.id} \n**Time:** ${createdAt.toDateString()} \n**Sentence:** Ban.`)).catch();
}
});
This prevents the error from occurring, prevents users from getting banned for DMing the bot, and prevents the guild owner from being infinitely DM'd (if the DMChannel were to be somehow converted into a GuildChannel, the bot would DM the owner after banning the user that created the channel, which would trigger the event again and ban the user again, and DM the owner again, in an infinite loop).
I'm trying to make a bot make a role and go to a specified channel in the arguments of a command.
The code will make the bot go to the specified channel, and add permissions for the role that the bot just made, and that's where the problem is.
The console in VSC says that "a role / user was not specified" and it skips over that.
I've tried changing the arole to a var, and setting the arole (message.arole) to arole.id and it still didn't work. Messing around and changing the settings did not work at all.
let woaID = message.mentions.channels.first();
if (!woaID) return message.channel.send("Channel is nonexistant or command was not formatted properly. Please do s!woa #(channelname)");
let specifiedchannel = message.guild.channels.find(t => t.id == woaID.id);
var arole = message.guild.createRole({
name: `A marker v1.0`,
color: 0xcc3b3b,
hoist: false,
mentionable: false,
permissions: ['SEND_MESSAGES']
}).catch(console.error);
message.channel.send("Created role...");
message.channel.send("Role set up...");
/*const sbwrID = message.guild.roles.find(`null v1.0`);
let specifiedrole = message.guild.roles.find(r => r.id == sbwrID.id)*/
message.channel.send('Modified');
specifiedchannel.overwritePermissions(message.arole, {
VIEW_CHANNEL: true,
SEND_MESSAGES: false
})
.then(updated => console.log(updated.permissionOverwrites.get(arole.id)))
.catch(console.error);
I expect the bot able to access the specified channel in the args, and create a role and overwrite role permissions for that channel.
The actual output is that the bot does everything fine, but the role does not have special permissions for the channel.
There are two main issues with your code:
The Guild.createRole() does not synchronously return a Role: it returns a Promise<Role>, so you're in fact not providing a role as argument for .overwritePermissions()
After you create the role (if you properly store it in arole) you can't access it as message.arole.
You can either do that with async/await or using the .then() promise method.
If you're not confident with promises or asynchronous code you should try to learn something about it, it's really useful: check out Using promises, the Promise and async function docs by MDN.
Here's an example:
message.guild.createRole({
name: `A marker v1.0`,
color: 0xcc3b3b,
hoist: false,
mentionable: false,
permissions: ['SEND_MESSAGES']
}).then(async arole => {
let updated = await specifiedchannel.overwritePermissions(arole, {
VIEW_CHANNEL: true,
SEND_MESSAGES: false
});
console.log(updated.permissionOverwrites.get(arole.id));
}).catch(console.error);
I am trying to make a tempmute command, I followed a tutorial online which worked... But my own server has users with multiple roles, and these roles allow them to talk even when they receive the "muted" role.
Is there any way to save all the roles from a mentioned user and then to remove and add those roles?
I already tried to make a new let variable
let roleHistory = tomute.member.roles;
and then adding and removing them with:
await(tomute.removerole(roleHistory));
tomute.addRole(roleHistory);
But that didn't work
module.exports.run = async (bot, message, args) => {
let tomute = message.guild.member(message.mentions.users.first() || message.guild.members.get(args[0]));
if(!tomute) return message.reply("Couldn't find user.");
if(tomute.hasPermission("MANAGE_MESSAGES")) return message.reply("Can't mute them!");
let muterole = message.guild.roles.find(`name`, "muted");
if(!muterole){
try{
muterole = await message.guild.createRole({
name: "muted",
color: "#000000",
permissions:[]
})
message.guild.channels.forEach(async (channel, id) => {
await channel.overwritePermissions(muterole, {
SEND_MESSAGES: false,
ADD_REACTIONS: false
});
});
}catch(e){
console.log(e.stack);
}
}
let mutetime = args[1];
if(!mutetime) return message.reply("You didn't specify a time!");
await(tomute.addRole(muterole.id));
message.reply(`<#${tomute.id}> has been muted for ${ms(ms(mutetime))}`);
setTimeout(function(){
tomute.removeRole(muterole.id);
message.channel.send(`<#${tomute.id}> has been unmuted!`);
}, ms(mutetime));
}
I want the bot to take the roles away, tempmute the user and giving the roles back after the Timeout.
Your attempt is on the right track, but you missed a small detail. A Guild Member has a method addRole and removeRole which you used. However, these methods are meant for adding/removing a single role.
When you first fetch the user roles with let roleHistory = tomute.member.roles;, it returns a Collection of roles. If you then attempt to use removeRole(roleHistory) it attempts to remove a single role equal to the complete collection (which doesn't exist obviously).
To make it work, you need the methods addRoles and removeRoles which adds/removes an entire collection. So your code would be:
let roleHistory = tomute.roles;
// Removing all the roles
await(tomute.removeRoles(roleHistory));
// Adding all the roles
tomute.addRoles(roleHistory);
P.s. Since your tomute variable is already a user you need to change your code to fetch the roles from let roleHistory = tomute.member.roles; to let roleHistory = tomute.roles;