How to delete messages and log them back in another channel - javascript

I'm wondering how I could delete messages using a command like !clear [number] and have those messages fetched back to a channel including:
The user ID who used the command to delete the message
The user ID of who said the deleted message(s)
The content of the message(s)
The channel it has been deleted from
The timestamp of the message
All this stuff in a discord embed.
I'm relatively new to coding, and I'm developing this bot for a server with 40,000 people and we need to keep logs of all deleted messages.
Please, someone, help me out. I would greatly appreciate it :D. If needed I can explain in further detail if you still aren't sure of what I'm looking to do with this bot :D

To delete messages with a command, you have to use TextChannel.bulkDelete(), in this case maybe after fetching the messages via TextChannel.fetchMessages().
To "log" them, you may want to build a RichEmbed and put your info in the fields.
I would try something like this:
// ASSUMPTIONS:
// logs = the TextChannel in wich you want the embed to be sent
// trigger = the Messages that triggered the command
//
// This is just a sample implementation, it could contain errors or might not be the fastest
// Its aim is not to make it for you, but to give you a model
async function clear(n = 1, logs, trigger) {
let {channel: source, author} = trigger;
if (n < 1 || !logs || !source) throw new Error("One of the arguments was wrong.");
let coll = await source.fetchMessages({ limit: n }), // get the messages
arr = coll.array(),
collected = [],
embeds = [];
// create groups of 25 messages, the field limit for a RichEmbed
let index = 0;
for (let i = 0; i < arr.length; i += 25) {
collected.push([]);
for (let m = i; m < i + 25; m++)
if (arr[m]) collected[index].push(arr[m]);
index++;
}
// for every group of messages, create an embed
// I used some sample titles that you can obviously modify
for (let i = 0; i < collected.length; i++) {
let embed = new Discord.RichEmbed()
.setTitle(`Channel cleaning${collected.length > 1 ? ` - Part ${i+1}` : ""}`)
.setDescription(`Deleted from ${source}`)
.setAuthor(`${author.tag} (${author.id})`, author.displayAvatarURL)
.setTimestamp(trigger.editedAt ? trigger.editedAt : trigger.createdAt),
group = collected[i];
for (let msg of group) {
let a = `${msg.author.tag} (${msg.author.id}) at ${msg.editedAt ? msg.editedAt : msg.createdAt}`,
c = msg.content.length > 1024 ? msg.content.substring(0, msg.content.length - 3) + '...' : msg.content;
embed.addField(a, c);
}
embeds.push(embed);
}
// once the embeds are ready, you can send them
source.bulkDelete(coll).then(async () => {
for (let embed of embeds) await source.send({embed});
}).catch(console.error);
}
// this is a REALLY basic command implementation, please DO NOT use this as yours
client.on('message', async msg => {
let command = 'clear ';
if (msg.content.startsWith(command)) {
let args = msg.content.substring(command.length).split(' ');
if (isNaN(args[0]) || parseInt(args[0]) < 1) msg.reply(`\`${args[0]}\` is not a valid number.`);
else {
await msg.delete(); // delete your message first
let logs; // store your channel here
clear(parseInt(args[0]), logs, msg);
}
}
});
Note: the highlighting for this kind of stuff, with a lot of backtick strings and objects, is pretty bad. I suggest reading the code in another editor or you might end up not understanding anything

Related

Is it possible to delete the embed if it has a certain word after its edited

in this form if possible
client.on('messageUpdate', (oldMessage, newMessage) => {
const words = ['word1', 'word2']
});
Tried using embed.title.includes('word') but did not work
If there is an embed in a message, you can get the embeds' data through message.embeds. This return an array of MessageEmbed in the message if exist or null if there is no embed. Now you just check each the embed, parse it to JSON and get its properties(embed.title, embed.description, etc...).
Here is an example of getting embeds' data:
const embeds = message.embeds?.map(embed => embed?.toJSON()); // Get array of message embeds parsed to JSON
if (!embeds) return; // Return if no embed in the message
let include = false; // Define the variable to check in each embed
for(let i = 0; i < embeds.length; i++) { // Loop through the embeds gotten from message
const embed = embeds[i];
// The variables below are the embed's part which can contain string
const title = embed.title;
const description = embed.description;
const footer = embed.footer?.text; // footer maybe null, put ? after footer won't throw error "Can not read property of null (reading 'text')"
if (title?.includes('word') || description?.includes('word') || footer?.includes('word')) { // Check if the embed contains 'word' or not
include = true; // The embed contains the word, so set `include` to true
break; // We now have what we need, destroy the loop
}
}
if (include) console.log('The message embeds contain the `word` word!');
else { console.log('The message embeds don\'t contain the `word` word.'); }

quick.db leveling system - database.updateValue is not a function

I'm trying to make a leveling system with a discord bot using quick.db. I've been working with this for a while and couldn't figure it out so I figured I'd go here. My current code is:
(app.js)
//Message Leveling
database.updateValue(message.author.id + message.guild.id, 1).then(i => {
let messages;
if (i.value = 25) messages = 25; // Level 1
else if (i.value == 50) messages = 50; // Level 2
else if (i.value == 75) messages = 75; //Level 3
if (!isNaN(messages)) { // If messages iss STILL empty, run this
database.updateValue(`userLevel_${message.author.id + message.guild.id}`, 1).then(o => {
message.channel.send(`You sent ${messages} messages, LEVEL UP HOME BOY! level ${o.value}`)
})
}
})
(messages.js)
const db = require('quick.db');
var database = require('quick.db')
exports.run = (bot, message, args, func) => {
database.fetchObject(message.author.id + message.guild.id).then(i => {
database.fetchObject(`userLevel_${message.author.id + message.guild.id}`).then(o => {
message.channel.send('Messages sent: `' + (i.value + 1) + '`\nLevel: `' + o.value +'`');
})
})
}
Now, the error I get happens in app.js but I figured the code from messages.js might be helpful. The error is:
[help] database.updateValue(message.author.id + message.guild.id, 1).then(i => {
[help] ^
[help]
[help] TypeError: database.updateValue is not a function
Being new to this I still don't quite understand what a TypeError is or how to fix it, despite looking it up on google (I know, I'm a real researcher). So I was hoping someone could give me a hand. I also couldn't find an example of this error, so I'm pretty lost.
As always, thanks for taking the time to read my question, if I got any terminology wrong feel free to ask me about what I mean, or you can just call me stupid.
<3
database.updateValue isn't a function, instead you would want to use database.addlike:
database.add(`level_${message.guild.id}_${message.author.id}`, 1).then(i => {
let messages;
if (i.value = 25) messages = 25; // Level 1
else if (i.value == 50) messages = 50; // Level 2
else if (i.value == 75) messages = 75; //Level 3
if (!isNaN(messages)) { // If messages iss STILL empty, run this
database.add(`level_${message.guild.id}_${message.author.id}`, 1).then(o => {
message.channel.send(`You sent ${messages} messages, LEVEL UP HOME BOY! level ${o.value}`)
})
}
})
For fetching databases, fetchObject isn't a function, use fetch or get
const db = require('quick.db');
var database = require('quick.db')
exports.run = (bot, message, args, func) => {
db.fetch(level_${message.guild.id}_${message.author.id}).then(i => {
db.fetch(level_${message.guild.id}_${message.author.id}).then(o => {
message.channel.send('Messages sent: `' + (i.value + 1) + '`\nLevel: `' + o.value +'`');
})
})
}
If you've defined quick.db as db then instead of calling database, call db otherwise it just wouldn't work.
Thanks,
Chills

Discord Bot not responding after first command

So I am having some issues with creating my bot. All I am trying to have it do, is keep track of a list of players that type the command "+me" to join a "waiting list", "-me" in order to be removed from the list, and "?list" in order to display the list. I plan to add other commands later.
The issue I am having, is that the command works fine to add someone to the list, however after the first command the bot stops responding to commands. This leaves me able to add myself to the queue, but then not able to leave, no one else able to join, not able to list it, etc.
Also if you could mention a way to move the for loop I am using to display the list into a seperate function I would greatly appreaciate it. I am new to Javascript and my attempts are crashing it for some reason.
const Discord = require('discord.js');
const {prefix, token} = require('./config.json');
const client = new Discord.Client();
var rankedList = []; // Initialise an empty array
client.login(token);
client.once('ready', () =>{
console.log('Ready!');
})
client.once('message', message =>{
// Add to queue
if(message.content.startsWith(`${prefix}me`)){
console.log(message.author + "added to queue.");
message.channel.send(message.author + " added to queue.");
var temp = message.author;
rankedList.push(temp); // the array will dynamically grow
// Show queue after adding
//for (var i = 0; i < rankedList.length; i++) {
// message.channel.send(i+1 + "- " + rankedList[i]);
//}
message.channel.send(`${rankedList.map((player,index) => `${index+1} - ${player}`).join('n')}`);
}
// Remove from queue
if(message.content.startsWith(`-me`)){
console.log(message.author + "removed from queue.");
message.channel.send(message.author + " removed from queue.");
for( var i = 0; i < rankedList.length; i++){
if ( rankedList[i] === message.author) {
rankedList.splice(i, 1);
i--;
}
}
// Show queue after removing
for (var i = 0; i < rankedList.length; i++) {
message.channel.send(i+1 + "- " + rankedList[i]);
}
}
if(message.content.startsWith(`?list`)){
console.log(message.author + "displayed the queue.");
// Show list
for (var i = 0; i < rankedList.length; i++) {
message.channel.send(i+1 + "- " + rankedList[i]);
}
}
})
The issue could be you have used "once" instead of "on". The latter triggers event every time, while the former listens once.
// Add to queue
client.on('message', async (message) => {
// It's good practice to ignore other bots. This also makes your bot ignore itself and not get into a spam loop
if(message.author.bot) return;
if(message.content.startsWith(`${prefix}me`)){
var temp = message.author;
rankedList.push(temp); // the array will dynamically grow
console.log(message.author + "added to queue.");
message.channel.send(`${message.author} added to queue.
${rankedList.map((player,index) => `${index+1} - ${player}`).join('
n')}`);
}
});
You are basically sending the entire message at once. I could see that the send() function is asynchronous [ https://discord.js.org/#/docs/main/stable/class/DMChannel?scrollTo=send ]and should not be chained in a for loop like above. The above code is also more concise
I have used template literals [ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals ] to remove multiple concatenation.

Why doesn't kicking people work using discord.js

const Discord = require("discord.js"),
bot = new Discord.Client();
let pre = "?"
bot.on("message", async msg => {
var msgArray = msg.content.split(" ");
var args = msgArray.slice(1);
var prisonerRole = msg.guild.roles.find("name", "Prisoner");
let command = msgArray[0];
if (command == `${pre}roll`) {
if (!msg.member.roles.has(prisonerRole.id)) {
roll = Math.floor(Math.random()*6)+1;
msg.reply(`You rolled a ${roll}`)
} else {
msg.reply(`HaHa NOOB, you're in prison you don't get priveleges!`)
}
}
if (command == `${pre}kick`) {
var leaderRole = msg.guild.roles.find("name", "LEADER");
var co_leaderRole = msg.guild.roles.find("name", "CO-LEADER");
if (msg.member.roles.has(leaderRole.id) ||
msg.member.roles.has(co_leaderRole.id)) {
var kickUser = msg.guild.member(msg.mentions.users.first());
var kickReason = args.join(" ").slice(22);
msg.guild.member(kickUser).kick();
msg.channel.send(`${msg.author} has kicked ${kickUser}\nReason: ${kickReason}`);
} else {
return msg.reply("Ya pleb, you can't kick people!");
}
}
})
bot.login("token").then(function() {
console.log('Good!')
}, function(err) {
console.log('Still good, as long as the process now exits.')
bot.destroy()
})
Everything works except actually kicking the person. The message sends nut it doesn't kick people. For example, when I type in ?kick #BobNuggets#4576 inactive, it says
#rishabhase has kicked #BobNuggets
Reason: inactive
But it doesn't actually kick the user, which is weird, can you help me?
Change
msg.guild.member(kickUser).kick();
to
kickUser.kick();
also, make sure the bot is elevated in hierarchy
Use kickUser.kick();
I recommend using a command handler to neaten up your code. You don't want all your commands in one .js file.
Try something like this for the Ban command itself. I use this for my Bot:
client.on("message", (message) => {
if (message.content.startsWith("!ban")) {
if(!message.member.roles.find("name", "Role that can use this bot"))
return;
// Easy way to get member object though mentions.
var member= message.mentions.members.first();
// ban
member.ban().then((member) => {
// Successmessage
message.channel.send(":wave: " + member.displayName + " has been successfully banned :point_right: ");
}).catch(() => {
// Failmessage
message.channel.send("Access Denied");
});
}
});
That should work, set the role you want to use it (cAsE sEnSiTiVe) and change !ban to whatever you feel like using. If you change all "ban"s in this to kick, it will have the same effect. If this helped you, mark this as the answer so others can find it, if not, keep looking :)

Discord bot with js - for loop not working correctly

I am making a discord bot using js, but for some reason I can not get the bot to print an array properly via a for loop. The code is below
const Discord = require('discord.js');
const getJSON = require('get-json')
const BotToken = "tokenid";
const TwitchClientID = "?client_id=clientid";
const TwitchAPI = "https://api.twitch.tv/kraken/streams/";
const bot = new Discord.Client();
var channelNames = ["channel1", "channel2", "channel3"];
bot.login('botloginid');
// !Live command that itterates through channelNames array and prints whether stream is currently live or not
bot.on("message", function(message) {
if (message.content === "!Live") {
for (var i = 0; i < channelNames.length; i++) {
getJSON(TwitchAPI+channelNames[i]+TwitchClientID, function(error, response) {
if (response.stream == null) {
message.reply(channelNames[i] + ' is currently not live');
} else {
message.reply(channelNames[i] + ' is currently live');
}
});
}
}
});
If I put in a message.reply('i is ' + i); before getJSON, it prints out 0 1 2, which is correct, but if I put message.reply('i is ' + i); after getJSON, it prints out, i is 3, i is 3, i is 3. And because the array indexes are 0,1,2 , returning 3 makes the bot display 'undefined is live/not live' rather than the name of the channel. I've never had a problem with loops in the past and I cant understand why it would be changing to 3 under getJSON and not even iterating as the loop is definitely working.

Categories