I'm currently working on a mute function for my bot but so far have only gotten it to set permissions for only the channel the message was sent from.
I tried using the guild.channels property but ended up getting nowhere with it, although I'm sure I'm just using it wrong.
var timer = args[1]
var channels = msg.channel
channels.overwritePermissions(msg.mentions.users.first(), { SEND_MESSAGES: false });
msg.reply(`Muted ${msg.mentions.users.first().username} for ${timer} seconds`)
setTimeout(unmute, timer * 1000);
function unmute(){
channels.overwritePermissions(msg.mentions.users.first(), { SEND_MESSAGES: true });
}
I want it to set the SEND_MESSAGES permission for all channels, but it only does so for the one I send the command from.
Iterate over the text channels in the guild.
const channels = message.guild.channels.filter(c => c.type === 'text');
for (let [, channel] of channels) {
// ^
// Ignoring the key; we don't need it
}
Why use a for...of loop when forEach() is provided for us? The latter simply calls promises and moves on without ensuring their completion. So, if there's an error, it won't be caught even when a catch() method is attached.
Overwrite each channels' permissions using GuildChannel.overwritePermissions() (note: this method will replace permission overwrites on the master branch).
channel.overwritePermissions(msg.mentions.users.first(), { SEND_MESSAGES: false })
.catch(console.error); // Catch and log errors
Putting it together...
const channels = message.guild.channels;
for (let [, channel] of channels) {
channel.overwritePermissions(msg.mentions.users.first(), { SEND_MESSAGES: false })
.catch(console.error);
}
Related
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've been trying to create a Discord bot. A lot of interactions are done through reactions, and I've been aware of the fact that only cached messages triggered the messageReactionAdd event. So I picked the following piece of code that is supposed to emit the packets corresponding to reactions added to "old" (not cached) messages. But it seems to completely block any packets concerning reactions adding because now none is emitted. Is there something that I've been doing wrong ?
Thanks.
My "raw.js" file :
module.exports = {
run: (client, packet) => {
// We don't want this to run on unrelated packets
if (!['MESSAGE_REACTION_ADD', 'MESSAGE_REACTION_REMOVE'].includes(packet.t)) return;
// Grab the channel to check the message from
const channel = client.guilds.cache.get(packet.d.guild_id).channels.cache.get(packet.d.channel_id);
const messageID = packet.d.message_id;
// There's no need to emit if the message is cached, because the event will fire anyway for that
if (channel.messages.has(messageID)) return;
// Since we have confirmed the message is not cached, let's fetch it
channel.messages.fetch(messageID).then(message => {
// Emojis can have identifiers of name:id format, so we have to account for that case as well
const emoji = packet.d.emoji.id ? `${packet.d.emoji.name}:${packet.d.emoji.id}` : packet.d.emoji.name;
// This gives us the reaction we need to emit the event properly, in top of the message object
const reaction = message.reactions.get(emoji);
// Adds the currently reacting user to the reaction's users collection.
if (reaction) reaction.users.set(packet.d.user_id, client.users.get(packet.d.user_id));
// Check which type of event it is before emitting
if (packet.t === 'MESSAGE_REACTION_ADD') {
client.emit('messageReactionAdd', reaction, client.users.get(packet.d.user_id));
}
if (packet.t === 'MESSAGE_REACTION_REMOVE') {
client.emit('messageReactionRemove', reaction, client.users.get(packet.d.user_id));
}
});
}
};
My "event fetcher" :
const fs = require('fs')
fs.readdir('./events/', (err, files) => {
if (err) return console.error(err);
files.forEach((file) => {
const eventFunction = require(`./events/${file}`);
if (eventFunction.disabled) return;
const event = eventFunction.event || file.split('.')[0];
const emitter = (typeof eventFunction.emitter === 'string' ? client[eventFunction.emitter] : eventFunction.emitter) || client;
const { once } = eventFunction;
try {
emitter[once ? 'once' : 'on'](event, (...args) => eventFunction.run(client, ...args));
} catch (error) {
console.error(error.stack);
}
});
});
From the discord.js discord server's #faq channel:
Bug:
• 'messageReactionAdd' does not fire despite proper partials enabled
PR: https://github.com/discordjs/discord.js/pull/4969 (merged, waiting for release)
Temporary fix is to ensure the addition of GUILD_MEMBER partial in the client definition
new Discord.Client({
partials: ['USER', 'GUILD_MEMBER', 'CHANNEL', 'MESSAGE', 'REACTION'],
});
I have a command with my discord bot to make a channel, but I'm trying to figure out how to get the id or name of the channel right after its made.
Line of code that makes the channel:
message.guild.channels.create('ticket ' + message.member.displayName, { parent: '744477882730020965' });
The reason is that since displayname can have characters not possible in a channel name and discord will just automatically remove those characters there's no actual way to predict what the channel name will be in some cases. There's probably a simple solution I'm missing, and thanks in advance for any help.
The GuildChannelManager#create method returns a Promise with the channel that was just created. You can use Promise.then() to get the channel.
Guild.channels.create(`ticket-${message.member.displayName}`, {
parent: "744477882730020965"
}).then(channel => {
message.channel.send(`I've created the channel ${channel.name}!`);
}).catch(error => {
console.error(error);
message.channel.send(`Couldn't create the channel. Check the console for the error.`);
});
If you are creating the channel in an async function, you can use await to avoid .then() for readability.
const Channel = await Guild.channels.create(`ticket-${message.member.displayName}`, {
parent: "744477882730020965"
}).catch(error => {
console.error(error);
message.channel.send(`Couldn't create the channel. Check the console for the error.`);
});
What do you need the ID for? You can use a then function to do whatever to edit the channel.
Try this?
let role = message.guild.roles.find("name", "#everyone");
message.guild.channels.create('ticket ' + message.member.displayName, { parent: '744477882730020965' }).then(c => {
c.overwritePermissions(role, {
SEND_MESSAGES: false,
READ_MESSAGES: false
});
c.overwritePermissions(message.author, {
SEND_MESSAGES: true,
READ_MESSAGES: true
});
message.reply(`Application created!`)
c.send(`Wait for support staff`)
}).catch(console.error);
First post on this site so my bad if I don't format something correctly. I've been trying to make a change prefix command and I don't know how to check next message content for a variable to use instead of the old prefix.
msg.reply("Which prefix do you want?");
const collector = new Discord.MessageCollector(msg.channel, m => m.author.id === msg.author.id, { time: 5000 });
console.log(collector)
collector.on('collect', msg => {
newprefix=collector.content();
msg.reply('Prefix succesfully changed!');
});
I strongly advise using the awaitMessages method. First you need to define a filter, a delegate function that returns true if the reaction is one you want. Typically in a command/response setting, you want a filter that indicates the original command invoker replied.
const filter = (reaction, user) => {
return user.id === msg.author.id;
};
You can then define options for your awaitMessages. (It's quite common to do this in-line with the awaitMessages method, that's fine if that is more clear to you)
const options = {
max: 1,
time: 30000,
errors: ['time']
}
The above example accepts 1 message, if given in 30 seconds, otherwise it throws an exception.
Finally, you are ready to begin...
msg.reply("Which prefix do you want?").then(() => {
msg.channel.awaitMessages(filter, options)
.then(collected => {
newprefix = collected.first();
// Record newprefix to a persistent config here
msg.reply('Prefix successfully changed!');
})
.catch(collected => {
msg.reply("You didn't respond fast enough.");
});
}
Keep in mind, this occurs asynchronously, so if you need to write newprefix somewhere, a JSON config file for example, you should do from within the scope of the .then
Anyone knows what could be the issue that .kick() .setMute(true/false) or even setDeaf(true/false) in discord.js libary don't seem to work. Here is also a part of the code that doesn't do anything when it should but also doesn't throw any errors. Bot was invited with maximum privileges and also code block executes the command to steMute / setDeaf / kick. Any ideas of what might cause this or what should i try logging to find the issue? THANKS!
ar msgUserId = msg.author.id
var allUsers = []
var reset = true
bot.channels.forEach((channel, id) => {
if (reset){
channel.members.forEach((user, id) => {
allUsers.push(user)
if (id == msgUserId){
reset = false
}
})
if (reset){
allUsers = []
}
}
})
if (allUsers){
var number = Math.floor((Math.random() * allUsers.length))
allUsers[number].setDeaf(true)
allUsers[number].setMute(true)
} else {
var channel = msg.channel
channel.send("You must be in a voice channel with others for this to work!")
}
Channels in bot.channels are cached for the sole purpose of metadata which are instances of Channel, you need a guild context (aka. server ID) in order to acquire a TextChannel with which the operations you say can be done.