I am currently working on discord bot and faced a problem where I need to limit reactions. I am trying to achieve the following goal - if the user selects reaction it should be replaced with the newest reaction. Can someone advise on how to do it?
Here is my screenshot and code of what I have at this moment.
My code:
client.on('raw', event => {
console.log(event);
const eventName = event.t;
if(eventName === 'MESSAGE_REACTION_ADD') {
if(event.d.message_id === '70цw3748527414706191') {
var reactionChannel = client.channels.get(event.d.channel_id);
if(reactionChannel.messages.has(event.d.message_id))
return;
else {
reactionChannel.fetchMessage(event.d.message_id)
.then(msg => {
var msgReaction = msg.reactions.get(event.d.emoji.name + ":" + event.d.emoji.id);
var user = client.users.get(event.d.user_id);
client.emit('messageReactionAdd', msgReation, user);
})
.catch(err => console.log(err));
}
}
}
else if(eventName === 'MESSAGE_REACTION_ADD') {
if(event.d.message_id === '703748527414706191') {
var reactionChannel = client.channels.get(event.d.channel_id);
if(reactionChannel.messages.has(event.d.message_id))
return;
else {
reactionChannel.fetchMessage(event.d.message_id)
.then(msg => {
var msgReaction = msg.reactions.get(event.d.emoji.name + ":" + event.d.emoji.id);
var user = client.users.get(event.d.user_id);
client.emit('messageReactionRemove', msgReation, user);
})
.catch(err => console.log(err));
}
}
}
});
client.on('messageReactionAdd', (messageReaction, user) => {
var roleName = messageReaction.emoji.name;
console.log(roleName);
var role = messageReaction.message.guild.roles.find(role => role.name.toLowerCase() ===
roleName.toLowerCase());
if(role) {
var member = messageReaction.message.guild.members.find(member => member.id === user.id);
if(member) {
member.addRole(role.id);
console.log("Success");
}
}
});
client.on('messageReactionRemove', (messageReaction, user) => {
var roleName = messageReaction.emoji.name;
var role = messageReaction.message.guild.roles.find(role => role.name.toLowerCase() ===
roleName.toLowerCase());
if(role) {
var member = messageReaction.message.guild.members.find(member => member.id === user.id);
if(member) {
member.removeRole(role.id);
console.log("Success");
}
}
});
Thank you for your guidance!
You can check on messageReactionAdd, if they already have another color-role, with this you would need either each color role to have a prefix or to have an array of what color-roles exist.
heres a start
client.on('messageReactionAdd', (reaction, user) => {
const guild = reaction.message.guild;
const roleName = reaction.emoji.name.toLowerCase();
console.log(roleName);
const role = guild.roles.cache.find(r => r.name.toLowerCase() === roleName);
if (role) {
const member = guild.members.cache.find(m => m.id === user.id);
//check if they already have a color role
if (alreadyColorRole) {
//either make it so he cant react until he unreacts to the role
//or automatically remove the other reaction.
reaction.remove();
} else {
member.addRole(role.id);
console.log("Success");
}
}
});
Related
/app/node_modules/discord.js/src/client/rest/RequestHandlers/Sequential.js:85
new DiscordAPIError(res.request.path, res.body, res.request.method) : err);
^
DiscordAPIError: Missing Permissions
at /app/node_modules/discord.js/src/client/rest/RequestHandlers/Sequential.js:85:15
at /app/node_modules/snekfetch/src/index.js:215:21
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
path: '/api/v7/guilds/715245634218885131/members/235148962103951360',
code: 50013,
method: 'PATCH'
}
This is the error i am facing while the bot got all the permission and is not trying the change the role of owner of someone who is higher in hierarchy.
A year ago this code was working fine but now suddenly it is not working please look at it.
//basic constants and functions
var checked;
var checking = [];
const Discord = require("discord.js");
const {usernameorid, token,usernamesp, roles, apiKey, spreadsheetId, range, unremoveableroles, refreshrate} = require("./config/discord.json");
const { google } = require("googleapis");
const connection = google.sheets({
version: "v4",
auth: apiKey
});
const client = new Discord.Client();
let oldRows = [];
//checking for errors
const logError = error => {
console.error("error log " + new Date());
console.error(error);
};
//the spreadsheet fetching
const fetchRows = async (spreadsheetId, range, sheetsConnection) => {
try {
const response = await sheetsConnection.spreadsheets.values.get({
spreadsheetId: spreadsheetId,
range: range
});
//fetching all data
const rows = response.data.values;
//dividing the data between different array using while loop
var i = 0;
var k=0;
while (i < rows.length) {
const checkrow="";
const rows123= rows[i]
//finally putting all roles together
const therolenames = rows123[1]+","+rows123[2]+","+rows123[3]+","+rows123[4];
assignRoles(rows123[0].trim(), therolenames.trim());
rows123[0]==null;
rows123[1]==null;
rows123[2]==null;
rows123[3]==null;
rows123[4]==null; rows123[1]==null;
roles[1]==null;
roles[2]==null;
roles[3]==null;
roles[4]==null;
therolenames==null;
roles.length=0;
rows123.length=0;
i++;
k++;
}
return rows;
} catch (error) {
logError(error);
}
};
const assignRoles = async (usernames, roleNames) => {
var rolenames1 = roleNames.split(",");
try {
const guildMembers = client.guilds.array()[0].members.array();
//number of all members in the group
const guildRoles = client.guilds.array()[0].roles.array();
// deleting unremovable roles from the list
const Roles2 = guildRoles.filter(Role => !unremoveableroles.includes(Role.name));
// * getting Role instances of role names
const removedRoles = guildRoles.filter(Role => unremoveableroles.includes(Role.name));
const Roles = guildRoles.filter(Role => roleNames.includes(Role.name));
//role number of all members in the group
roleNames.length=0;
// * getting GuildMember instances of usernames and setting roles
guildMembers.forEach(async member => {
const username= member.user.username + "#" + member.user.discriminator;
//check if the first column of spreadsheet matches the userid/username of discord
var UNcheck;
if (usernameorid=="UN"){
UNcheck=username
}else{
UNcheck=member.id
}
if (usernames.includes(UNcheck)) {
const notAssignedRoles = [];
Roles.forEach(role => {
//if (!member.roles.array().includes(Roles)) {
//if (!guildRoles.includes(Roles)) {
checked="no"
//Check whether the roles (discord) are in roles (spreadsheet)
if (Roles.includes(member.roles.array()[1])|| removedRoles.includes(member.roles.array()[1])|| member.roles.array()[1]==null){
}else{checked="yes" }
if (Roles.includes(member.roles.array()[2]) || removedRoles.includes(member.roles.array()[2]) || member.roles.array()[2]==null){
}else{checked="yes"; }
if (Roles.includes(member.roles.array()[3]) || removedRoles.includes(member.roles.array()[3])|| member.roles.array()[3]==null){
}else{checked="yes"; }
if (Roles.includes(member.roles.array()[4])|| removedRoles.includes(member.roles.array()[4]) || member.roles.array()[4]==null){
}else{checked="yes"; }
//Check whether the roles (Spreadsheet) are in roles (Discord)
if (member.roles.array().includes(Roles[0])|| removedRoles.includes(Roles[0]) || Roles[0]==null){
}else{checked="yes"; }
if (member.roles.array().includes(Roles[1]) || removedRoles.includes(Roles[1])|| Roles[1]==null){
}else{checked="yes"; }
if (member.roles.array().includes(Roles[2]) || removedRoles.includes(Roles[2]) || Roles[2]==null){
}else{checked="yes"; }
if (member.roles.array().includes(Roles[3])|| removedRoles.includes(Roles[3]) || Roles[3]==null){
}else{checked="yes"; }
if (checked=="yes"){
notAssignedRoles.push(role);
}
});
if (notAssignedRoles.length > 0) {
await member.removeRoles(Roles2); member.addRoles(Roles);
console.log(
"Assigned " +
notAssignedRoles.map(role => role.name) +
" to " +
username + " ["+member.id+"] on " + new Date().toString()
);
} else {
if (Roles[0]==null && Roles[1]==null && Roles[2]==null && Roles[3]==null) {
member.removeRoles(Roles2);
console.log(username + " ["+member.id+"] has all roles removed on"+ new Date().toString());
}else{
console.log(username + " ["+member.id+"] already has all the roles assigned, checked on "+ new Date().toString());
}
}
}
});
} catch (err) {
logError(err);
}
};
const extractNewEntries = (oldRows, rows) => {
let newRows = [];
if (rows.length > oldRows.length) {
newRows = rows.slice(oldRows.length);
}
newRows.forEach(row => {
oldRows.push(row);
});
return newRows;
};
const extractDiscordIDs = rows => {
return rows.map(user => user[0]);
console.log(rows.map(user => user[0]));
};
client.once(
"ready",
() => {
console.log("Bot started with these settings:");
console.log("• Spreadsheet ID: ");
console.log("• Range: " + range);
console.log("• Roles: " + roles.join(", "));
setInterval(async () => {
console.log("\nChecked for new entries on " + new Date().toString());
let rows;
try {
rows = await fetchRows(spreadsheetId, range, connection);
const newEntries = extractNewEntries(oldRows, rows);
if (newEntries.length > 0) {
console.log(`Found ${newEntries.length} new entries`);
const usernames = extractDiscordIDs(newEntries);
} else {
console.log("No new entries");
}
} catch (err) {
if (rows === undefined) console.error("Google Sheet is empty");
logError(err);
rows = [];
}
}, refreshrate); // refresh rate: 60000 milliseconds == 1 minute
},
logError
);
client.on("error", logError);
const start = async () => {
try {
await client.login(token);
} catch (err) {
logError(err);
setTimeout(start, 30000);
}
};
start();
client.on("disconnect", start);
module.exports = {
fetchRows,
assignRoles,
extractNewEntries,
extractDiscordIDs
};
const express = require("express");
const fs = require("fs");
const app = express();
app.use(express.static("public"));
const listener = app.listen(process.env.PORT, function() {
console.log("Your app is listening on port " + listener.address().port);
});
The complete code is available at
https://github.com/supreen/form2role-bot
please see if you can reproduce the error.
I had solved the problem. The problem was that
1- The role can only assign or remove the roles that are below it.
2- The bot roles that are irremovable and #everyone needs to be added in the config.json file.
They're multiple reasons for this:
The bot doesn't have the permission to manage roles
The member is higher than the member in the role hiarchy
The member is equal than the member in the role hiarchy
The bot is trying to give itself roles that he cannot manage
The bot can't manage the owner's role
Check if any of these are the actual reason you get this error
Recently I decided to update my Discord Bot from V12 to V13 and I encountered a problem with my Reaction Roles.
It only works if the bot doesn't restart. It worked perfectly on discord.js 12.5.3 and now I'm using discord.js 13.5.0. Could you guys help me with the problem?
Here is my code:
const { MessageEmbed } = require("discord.js");
const Discord = require('discord.js');
const { Client } = require('discord.js');
const client = new Client({
intents: 32767,
partials: ['MESSAGE', 'CHANNEL', 'REACTION'],
});
const config2 = require("../config2");
module.exports = async (client, message, args) => {
client.on('messageCreate', async message => {
if (message.content.startsWith("22ar")) {
const embed = new MessageEmbed()
.setColor('#FFA500')
.setTitle(`Pick the roles`)
.setDescription(`🔓 **- You unlock yourself.**
✅ **- You get access to the server.**
💜 **- You get notified for X things.**
[🔓, ✅] - obligatory.
[💜] - optional.
\`Wait at least 30 seconds and try again if you don't get the roles.\``)
const msg = await message.channel.send({ embeds: [ embed ] })
msg.react('🔓')
msg.react('✅')
msg.react('💜')
}
})
const CHANNEL = config2.ROLECHANNEL;
const UROLE = config2.UNLOCKROLE;
const MROLE = config2.MEMBERROLE;
const NROLE = config2.NOTIFYROLE;
const unlockEmoji = '🔓';
const checkEmoji = '✅';
const notifyEmoji = '💜';
client.on('messageReactionAdd', async (reaction, user) => {
if (reaction.partial) {
try {
await reaction.fetch();
} catch (error) {
console.error('Fetching message failed: ', error);
return;
}
}
if (!user.bot) {
if(reaction.message.channel.id === CHANNEL) {
if (reaction.emoji.name == checkEmoji) {
const memberRole = reaction.message.guild.roles.cache.find(r => r.id === MROLE);
const { guild } = reaction.message
const member = guild.members.cache.find(member => member.id === user.id);
member.roles.add(MROLE);
}
if (reaction.emoji.name == unlockEmoji) {
const unlockRole = reaction.message.guild.roles.cache.find(r => r.id === UROLE);
const { guild } = reaction.message
const member = guild.members.cache.find(member => member.id === user.id);
member.roles.remove(UROLE)
}
if (reaction.emoji.name == notifyEmoji) {
const notifyRole = reaction.message.guild.roles.cache.find(r => r.id === NROLE);
const { guild } = reaction.message
const member = guild.members.cache.find(member => member.id === user.id);
member.roles.add(NROLE)
}
}
client.on('messageReactionRemove', async (reaction, user) => {
if (reaction.partial) {
try {
await reaction.fetch();
} catch (error) {
console.error('Fetching message failed: ', error);
return;
}
}
if (!user.bot) {
if(reaction.message.channel.id === CHANNEL) {
if (reaction.emoji.name == checkEmoji) {
const memberRole = reaction.message.guild.roles.cache.find(r => r.id === MROLE);
const { guild } = reaction.message
const member = guild.members.cache.find(member => member.id === user.id);
member.roles.remove(memberRole);
}
if (reaction.emoji.name == unlockEmoji) {
const unlockRole = reaction.message.guild.roles.cache.find(r => r.id === UROLE);
const { guild } = reaction.message
const member = guild.members.cache.find(member => member.id === user.id);
member.roles.remove(unlockRole)
}
if (reaction.emoji.name == notifyEmoji) {
const notifyRole = reaction.message.guild.roles.cache.find(r => r.id === NROLE);
const { guild } = reaction.message
const member = guild.members.cache.find(member => member.id === user.id);
member.roles.remove(notifyRole)
}
}
}
})
}
})
}
I am not getting any error in the console and the bot continues to work as usual.
Thank you for your attention.
Messages sent before your bot started are uncached unless you fetch them first. By default, the library does not emit client events if the data received and cached is not sufficient to build fully functional objects. Since version 12, you can change this behavior by activating partials.
Official guide about this here (Listening for reactions on old messages).
I have posted a button but it only works once
but after that when I use it again
Also
How can I reply to message if I use deferUpdate it shows
Code
client.on('ready', () => {
client.user.setActivity('people and managing the server', {
type: 'WATCHING',
});
const channel = client.channels.cache.get('894171605608042496');
const row = new MessageActionRow().addComponents(
new MessageButton()
.setCustomId('openTicket')
.setLabel('Create ticket')
.setEmoji('📩')
.setStyle('SECONDARY')
);
channel
.send({
embeds: [
{
title: 'SGAS Tickets',
color: '#388e3c',
description: 'To create a ticket react with 📩',
},
],
components: [row],
})
.then(() => {
const filter = () => {
return true;
};
const collector = channel.createMessageComponentCollector({
filter,
time: 15 * 1000,
});
collector.on('collect', (i) => {
i.deferUpdate().then(() => {
Ticket.count({}, (err, result) => {
if (err) {
console.log(err);
} else {
const ticketNumber = result + 1;
const ticketString = convertNumber(ticketNumber);
const ticket = new Ticket({
tickedId: ticketString,
});
ticket.save((err) => {
if (err) {
console.log(err);
} else {
const myguild = client.guilds.cache.get('887277806386565150');
if (!myguild) {
console.log('guild not found');
return;
}
const category = myguild.channels.cache.find(
(c) =>
c.id === '887277807279947826' &&
c.type == 'GUILD_CATEGORY'
);
if (!category) {
console.log('category not found');
return;
}
myguild.channels
.create(`Ticket#${ticketString}`, {
type: 'GUILD_TEXT',
})
.then(async (myc) => {
myc.setParent(category).then(() => {
myc.send(
`Hello <#${i.user.id}>, your question will be solved here shortly`
);
i.reply({
content: `Go to <#${myc.id}>, for your question`,
ephemeral: true,
});
});
});
}
});
}
});
});
});
});
});
you are using a component collector - which expires in 15 seconds, as seen in your code. That means after 15 seconds your bot stops listening for button clicks. My recommendation is to use the interactionCreate event to listen for that button: see docs https://discord.js.org/#/docs/main/stable/class/ButtonInteraction
Example:
client.on("interactionCreate", (interaction) => {
if(!interaction.isButton()) return;
if(interaction.customId === "openTicket") {
// your ticket code here
}
});
I'm creating an Express endpoint where I validate whether the username/password is in my db (json file)
router.post('/login', (req, res) => {
let userData = req.body;
if (validateEmailAndPassword(userData.username, userData.password) {
res.send(userData);
} else {
res.status(401).send({ error: "Username/Password combination is incorrect." });
}
})
const validateEmailAndPassword = (username, password) => {
let validCreds = false;
fs.readFile('db/users.json', 'utf8', (err, data) => {
if (data) {
const stream = JSON.parse(data);
const usersFound = stream.filter(info => {
if (info.username === username && info.password ===password) { return true; }
})
if (usersFound.length >= 1) { validCreds = true; }
return validCreds;
} else {
throw Error(err);
}
})
}
'validateEmailAndPassword(userData.username, userData.password)' in line 3 of the first block of code returns 'undefined' in the if condition because it's asynchronous.
What's the best way to resolve 'validateEmailAndPassword(userData.username, userData.password)' synchronously so that I get a value of true/false without using readFileSync?
Thanks in advance!
use async await and promises
router.post('/login', async(req, res) => {
let userData = req.body;
if (await validateEmailAndPassword(userData.username, userData.password)) {
res.send(userData);
} else {
res.status(401).send({ error: "Username/Password combination is incorrect." });
}
})
const validateEmailAndPassword = (username, password) => {
let validCreds = false;
return new Promise(resolve => {
fs.readFile('db/users.json', 'utf8', (err, data) => {
if (data) {
const stream = JSON.parse(data);
const usersFound = stream.filter(info => {
if (info.username === username && info.password ===password) { return true; }
})
if (usersFound.length >= 1) { validCreds = true; }
resolve(validCreds);
return validCreds;
} else {
throw Error(err);
}
})
})
}
tada
To expand on #Estradiaz answer...
It sounds like you want to use it syncronously, so you could just make it synchronous instead of having it asyncronous and await it:
readFile -> readFileSync
const validateEmailAndPassword = (username, password) => {
let validCreds = false;
var data = fs.readFileSync('db/users.json', 'utf8');
if (data) {
const stream = JSON.parse(data);
const usersFound = stream.filter(info => {
if (info.username === username && info.password === password)
return true;
});
if (usersFound.length >= 1)
validCreds = true;
return validCreds;
} else {
throw Error(err);
}
}
I am using firestore to store the data in firebase. To get the count i am using cloud function. When i try to add / update / delete an entry in one collection it starts the infinite loop with another collection.
Example:
I am having a user table and agent table when i add/update/delete a user it should get updated in the agent table.
Though i have used separate functions for users and agent still i am getting an infinite loop.can anyone tell me how to resolve it
Query to update the user in user and agent table:
export const addUser = (values) =>
db
.collection('users')
.add(values)
.then((docRef) => {
let customer = { customer: {} };
customer.customer[docRef.id] = {
id: docRef.id,
name: values.name,
commission: values.agent.commission
};
let agentId = values.agent.id;
db.collection('agents')
.doc(agentId)
.set(customer, { merge: true });
});
Cloud function for user:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
exports = module.exports = functions.firestore
.document("users/{userUid}")
.onWrite(
(change, context) =>
new Promise((resolve, reject) => {
let dashboardId;
getDashboardId();
})
);
getDashboardId = () => {
admin.firestore().collection('dashboard').get().then((snapshot) => {
if (snapshot.size < 1) {
dashboardId = admin.firestore().collection('dashboard').doc().id;
} else {
snapshot.docs.forEach((doc) => {
dashboardId = doc.id;
});
}
return updateUser(dashboardId);
}).catch((error) => {
console.log('error is', error);
});
}
updateUser = (id) => {
admin.firestore().collection('users').where('isDeleted', '==', false).get().then((snap) => {
let usersData = {users: snap.size};
return admin.firestore().collection('dashboard').doc(id).set(usersData, {merge: true});
}).catch((error) => {
console.log('error is', error);
});
}
Cloud function for agent:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
exports = module.exports = functions.firestore
.document("agents/{agentUid}")
.onWrite(
(change, context) =>
new Promise((resolve, reject) => {
let dashboardId;
getDashboardId();
})
);
getDashboardId = () => {
admin.firestore().collection('dashboard').get().then((snapshot) => {
if (snapshot.size < 1) {
dashboardId = admin.firestore().collection('dashboard').doc().id;
} else {
snapshot.docs.forEach((doc) => {
dashboardId = doc.id;
});
}
return updateAgent(dashboardId);
}).catch((error) => {
console.log('error is', error);
});
}
updateAgent = (id) => {
admin.firestore().collection('agents').where('isDeleted', '==', false).get().then((snap) => {
let agentsData = {agents: snap.size};
return admin.firestore().collection('dashboard').doc(id).set(agentsData, {merge: true});
}).catch((error) => {
console.log('error is', error);
});
}