Is there a way to detect msg reactions on a specific msg? - javascript

I'm making a new system on my server, i need a way to detect reactions on some msgs, so the user will react to run a function like send msg or something else...
I tried to use reaction collector, but i can't deal with it, this method will not gonna work with old msgs.
I need something simple, to build my system on, so i can use different functions like message.channel.send or message.guild.createChannel, with the ability to detect the msg content, this one is very important.

Reaction collectors can indeed work on messages that have already been sent prior to the client's login. However, these messages must be kept track of and fetched.
Example System (did not test, just an example)
messages.json:
[
{
"guild": "guildIDhere",
"channel": "channelIDhere",
"message": "messageIDhere",
"filter": "(reaction, user) => reaction.emoji.name === '😄' && user.id !== client.user.id;",
"options": { "max": 1 },
"callback": "collected => console.log(collected);"
}
]
index.js:
const messages = require('./messages.json'); // Path may vary
const fs = require('fs');
client.on('ready', () => {
const deleteQueue = [];
for (let i = 0; i < messages.length; i++) {
const guild = client.guilds.get(messages[i].guild);
if (!guild) {
deleteQueue.push(i);
continue;
}
const channel = guild.channels.get(messages[i].channel);
if (!channel) {
deleteQueue.push(i);
continue;
}
const message = channel.fetchMessage(messages[i].message);
if (!message) {
deleteQueue.push(i);
continue;
}
message.createReactionCollector(eval(messages[i].filter), messages[i].options)
.then(eval(messages[i].callback))
.catch(console.error);
}
if (deleteQueue.length > 0) {
for (let i = 0; i < deleteQueue.length; i++) messages.splice(deleteQueue[i], 1);
fs.writeFileSync('./message.json', JSON.stringify(messages));
console.log(`${deleteQueue.length} message(s) are no longer available.`);
}
});
Creating a collector later on:
message.channel.send('React with :smile:')
.then(m => {
const filter = ...;
const options = ...;
const callback = ...;
m.createReactionCollector(filter, options)
.then(callback)
.catch(...);
messages.push({
guild: message.guild.id,
channel: message.channel.id,
message: message.id,
filter: `${filter}`,
options: options,
callback: `${callback}`
});
fs.writeFileSync('./messages.json', JSON.stringify(messages));
})
.catch(console.error);

I think u can use RethinkDB to save messages.
RethinkDB is a Realtime Database, and a simple way to detect realtime messages.
https://www.rethinkdb.com/

Related

The words my bot is told are not remembered in the database. I am using MongoDB atlas for my bot's database, and my bot uses discord.js

I know I ask a lot of questions, but I need to figure this out.
I made a MongoDB atlas database and wrote code that connects my database to my bot. However, after shutting off my bot, it doesn't remember any words that are told to it. Here's my code (sensitive stuff removed):
const Discord = require("discord.js");
const { Client, Intents, MessageEmbed } = require('discord.js');
const client = new Client({ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MEMBERS, Intents.FLAGS.GUILD_BANS, Intents.FLAGS.GUILD_EMOJIS_AND_STICKERS, Intents.FLAGS.GUILD_INTEGRATIONS, Intents.FLAGS.GUILD_WEBHOOKS, Intents.FLAGS.GUILD_INVITES, Intents.FLAGS.GUILD_VOICE_STATES, Intents.FLAGS.GUILD_PRESENCES, Intents.FLAGS.GUILD_MESSAGES, Intents.FLAGS.GUILD_MESSAGE_REACTIONS, Intents.FLAGS.GUILD_MESSAGE_TYPING, Intents.FLAGS.DIRECT_MESSAGES, Intents.FLAGS.DIRECT_MESSAGE_REACTIONS, Intents.FLAGS.DIRECT_MESSAGE_TYPING],
});
const TOKEN = ""
const fetch = import('node-fetch')
const possibleAnswers = ['Im sad :(', 'Im annoyed', 'Im happy!','Im okay']
const possibleMeals = ["Eat some fruit!","Eat some icecream!","Eat a salad!","Eat some spahgetti!","Go out to a restaurant of your choice"]
const possibleCodeInfo = ["Arrays indexes start at 0 in most languages, but some start at 1, like Julia!",
"Else if statements allow for mutliple conditions!",
"Many AI's require a database during its creation!",
"Lua is a frontend and backend language!",
"C# is 22 years old!",
"People used to use punchcards to code!",
"Objects store data in properties!",
"React allows you to write javascript in HTML!",
"HTML is not a coding language, its a markup language!",
"Unity uses C# for its engine!"]
const mongoose = require("mongoose");
const { Database} = require("D:/discordbot2/memorysave.json")
if (!Database) return;
mongoose.connect("mongodb+srv://user:<password>#uwubot.jr4ot.mongodb.net/?retryWrites=true&w=majority", {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => {
console.log("The client is now connected to the database.")
}).catch((err) => {
console.log(err)
})
let chain = {}
function generateChain(str){
const textArr = str.split(' ');
let x = textArr.indexOf("<#998859763385389137>")
if (x != -1) textArr.splice(x, 1)
for (let i = 0; i < textArr.length; i++) {
let word = textArr[i].toLowerCase().replace(/[\W_]/, "")
if (!chain[word]) chain[word] = []
if (textArr[i + 1]) chain[word].push(textArr[i + 1].toLowerCase().replace(/[\W_]/, ""))
}
}
function generateSentence(chain){
const words = Object.keys(chain)
let word = words[Math.floor(Math.random() * words.length)]
let output = ''
for (let i = 0; i < (Math.floor(Math.random() * words.length)); i++){
output += word + ' '
word = words[(Math.floor(Math.random() * words.length))]
if (!word || !chain.hasOwnProperty(word)) {
word = words[Math.random() * Math.floor(Math.random() * words.length)]
}
}
return output
}
client.on("ready", () => {
console.log(`Logged in as ${client.user.tag}!`)
// slash command stuff
const guildId = '847395379019513876'
const guild = client.guilds.cache.get(guildId)
let commands
if (guild) {
commands = guild.commands
} else {
commands = client.application?.commands
}
})
client.on("message", msg => {
if (msg.mentions.users.first() == client.user) {
generateChain(msg.content)
msg.reply(generateSentence(chain))
}
switch (msg.content){
case('how are you?'):
msg.reply(possibleAnswers[Math.floor(Math.random()*possibleAnswers.length)]);
break;
case('what should i eat?'):
msg.reply(possibleMeals[Math.floor(Math.random()*possibleMeals.length)]);
break;
case('tell me a code fact'):
msg.reply(possibleCodeInfo[Math.floor(Math.random()*possibleCodeInfo.length)]);
break;
//end
}
})
client.on('interactionCreate', async (interaction) => {
if(!interaction.isCommand()) return;
})
client.login(TOKEN)
Did I write my code wrong? Am I used something thats deprecated? I appreciate any help that can be offered, because I am stumped.
That's because you are just creating a connection to your database. You aren't telling mongoose to save or load anything.
First of, you need to create a Schema, which is a model of how the data will be saved in mongoose.
In another file, do this:
const mongoose = require(`mongoose`);
const Schema = mongoose.Schema({
userID: String,
words: Array,
})
module.exports = mongoose.model(`userWords`, Schema)
In your original file:
Import the schema at the top of the file: const schema = require('your_path/Schema.js')
In the place where you want to get the data:
// Load the data for that user
const savedUserWords = await schema.findOne({userID: msg.author.id)}
// if there is no data you will need to create it first
if(!savedUserWords) {
// create an Array with the words that the user has told.
const usedWords = ["word_1", "word_2", "word_3"];
// Then create the schema and pass the words.
const createSchema = new schema({
userID: msg.author.id,
words: usedWords
})
// Save the schema
createSchema.save().catch(err => console.log(err));
}
// If there is already existent data for that user, you can get the saved words by doing:
const userData = savedUserWords.words
// If you want to add new words to the already existent data, you can do it this way:
savedUserWords.words.push("word");
savedUserWords.save().catch(err => console.log(err));

Get count of member's messages in channel in discord.js

Is there any way how to count messages of specified user in specified Discord channel in discord.js? When I use:
const countMyMessages = async (channel, member) => {
const messages = await channel.messages.fetch()
const myMessages = message.filter(m => m.author.id === member.id)
console.log(myMessages.size)
}
Only 50 messages are fetched, so I can't count all messages of user. And option limit can have max value 100. /guilds/guild_id/messages/search API on the other hand is not available for bots.
You will need to use a storage system to keep this kind of statistics on Discord.
I recommend you to use SQLite at first (like Enmap npm package).
I can quickly draw a structure for you based on this one.
const Enmap = require("enmap");
client.messages = new Enmap("messages");
client.on("message", message => {
if (message.author.bot) return;
if (message.guild) {
const key = `${message.guild.id}-${message.author.id}`;
client.messages.ensure(key, {
user: message.author.id,
guild: message.guild.id,
messages: 0
});
client.messages.inc(key, "messages");
// Do your stuff here.
console.log(client.messages.get(key, "messages"))
}
});

Firebase real time database - subscription .on() does not trigger on client

I have a collection of notes in my Firebase realtime database.
My code is set to subscribe to modifications in the /notes path of the database.
When updating a note in the Firebase web console my client gets the updates, but when another client updates the note via ref.update() the data is not pushed to my client.
When updating in the Firebase web console, I am performing the update from one browser and watching the update in another browser.
How can this be? See code below.
export const startSubscribeNotes = () => {
return (dispatch, getState) => {
const uid = getState().auth.uid
const dbPath = 'notes'
database.ref(`${dbPath}`)
.orderByChild(`access/members/${uid}`)
.equalTo(true)
.on('value', (snapshot) => {
console.log('notes .on()')
let updatednotes = []
console.log('Existing notes', existingnotes)
snapshot.forEach( (data) => {
const note = {
id: data.key,
...data.val()
}
updatednotes.push(note)
})
dispatch(setnotes(notes))
})
}
}
What I have noticed is that if I change my access rules in the Firebase database I am able to get the updates, but can no longer restrict read access.
"notes": {
//entry-level access
".read": "
auth.uid !== null //&& query.equalTo === auth.uid
",
I can then loop all notes and collect the ones I should only be able to read.
const uid = getState().auth.uid
database.ref('notes')
.on('value', (snapshot) => {
const notes = []
snapshot.forEach((data) => {
const noteData = data.val()
if(noteData.access){
const authorArray = (noteData.access.author) ? [noteData.access.author] : []
const members = (noteData.access.members) ? noteData.access.members : {}
const membersArray = Object.keys(members)
const allUsers = authorArray.concat(membersArray)
const accessGranted = allUsers.includes(uid)
if(accessGranted){
const note = {
id: data.key,
...data.val()
}
notes.push(note)
}
}
})
if(notes.length > 0){ dispatch(setNotes(notes)) } //Dispatch if not empty
})
How can I apply the access rules and still get the updates pushed to my client?
I have checked that all clients can write to the database at /notes
Any help much appreciated!

How to tell if a message mentions any user on the server?

I want to, with discord.js, tell if any given message mentions any user on the server.
Message.mentions is what you're looking for: you can either check .users or .members. If there's at least one element in one of these collections, then someone has been mentioned:
client.on('message', message => {
if (message.mentions.members.first()) // there's at least one mentioned user
else // there's no mentioned user
});
Keep a map of users and match with incoming messages
const Discord = require('discord.js')
const client = new Discord.Client()
const map = {}
client.on('message', msg => {
if (msg.content.indexOf('#') !== -1) {
const users = msg.content.match(/#[a-z\d]+/ig)
users.forEach((user) => {
if (map[users.slice(1)]) {
console.log(`${users.slice(1)} mentioned in server`)
}
})
}
})
client.on('ready', () => {
setInterval (function (){
for(u in Bot.users){
map[client.users[u].username] = true
}
}, 10000)
})
client.login('token')

Discord bot - Purge command not working discord.js-commando

I have created a discord bot recently using node js which when I do !purge, responds with Unknown command, do !help to view a list of command but after saying it, it is purging the messages. That is, it works well but posting that error message. I don't know what's the problem please help me
const commando = require('discord.js-commando');
const bot = new commando.Client();
const prefix = '!';
bot.on('message', message => {
let msg = message.content.toUpperCase();
let sender = message.author;
let cont = message.content.slice(prefix.length).split(" ");
let args = cont.slice(1);
if (msg.startsWith(prefix + 'PURGE')) {
async function purge() {
message.delete();
if (isNaN(args[0])) {
message.channel.send('Please input a number of messages to be deleted \n Syntax: ' + prefix + 'purge <amount>');
return;
}
const fetched = await message.channel.fetchMessages({limit: args[0]});
console.log(fetched.size + ' messages found, deleting...');
// Deleting the messages
message.channel.bulkDelete(fetched)
.catch(error => message.channel.send(`Error: ${error}`));
}
purge();
}
});
bot.login('MY BOT TOKEN HERE');
Right now you're using the discord.js-commando library. Any reason you decided to use that library? It looks like you're just using standard discord.js functions like bot.on, message.channel.send, message.channel.fetchMessages, message.channel.bulkDelete...
You should be good just useing the standard discord.js library, starting your code with this:
const Discord = require('discord.js');
const bot = new Discord.Client();
You can find this code on the main "Welcome" page of Discord.js
Edit:
I'm still not sure why you're using discord.js-commando, but that doesn't matter. Here's an example command I came up with using the discord.js-commando library:
const commando = require('discord.js-commando');
class PurgeCommand extends commando.Command {
constructor(client) {
super(client, {
name: 'purge',
group: 'random', // like your !roll command
memberName: 'purge',
description: 'Purge some messages from a Text Channel.',
examples: ['purge 5'],
args: [
{
key: 'numToPurge',
label: 'number',
prompt: 'Please input a number ( > 0) of messages to be deleted.',
type: 'integer'
}
]
});
}
run(msg, { numToPurge }) {
let channel = msg.channel;
// fail if number of messages to purge is invalid
if (numToPurge <= 0) {
return msg.reply('Purge number must be greater than 0');
}
// channel type must be text for .bulkDelete to be available
else if (channel.type === 'text') {
return channel.fetchMessages({limit: numToPurge})
.then(msgs => channel.bulkDelete(msgs))
.then(msgs => msg.reply(`Purge deleted ${msgs.size} message(s)`))
.catch(console.error);
}
else {
return msg.reply('Purge command only available in Text Channels');
}
}
};
module.exports = PurgeCommand
I'd also recommend using a new type instead of integer so you can validate the user's response and make sure they enter a number greater than 0.
If you need help setting up an initial discord.js-commando script, I'd take a look at this repo provided by the Discord team: https://github.com/discordjs/Commando/tree/master/test
You might wanna use this. This purge command is intended for discord.js v11.5.1 and I haven't tested to see if it works on v12, but I think this might work for you. I should say that THIS DELETES ALL THE CONTENT INSIDE THE CHANNEL (Nested command)
exports.run = (bot, message, args) => {
let filter = m => message.author.id === message.author.id;
message.channel.send("Are you sure you wanna delete all messages? (y/n)").then(() => {
message.channel.awaitMessages(filter, {
max: 1,
time: 30000,
errors: ['time']
})
.then(message => {
message = message.first();
if (message.content.toUpperCase() == "YES" || message.content.toUpperCase() == "Y") {
message.channel.bulkDelete(100);
} else if (message.content.toUpperCase() == "NO" || message.content.toUpperCase() == "N") {
message.channel.send("Terminated").then(() => {message.delete(2000)});
} else {
message.delete();
}
})
.catch(collected => {
message.channel.send("Timeout").then(() => {message.delete(2000)});
});
}).catch(error => {
message.channel.send(error);
});
};

Categories

Resources