As part of a bot I am making, I am making a config command which allows users to toggle certain features in their servers. To do this, I am using a simple JSON file called config.json to store the ID of the server along with several boolean variables to represent the features:
{
"servers": [
{
"id": INSERT_ID,
"delete": true
},
{
"id": INSERT_ID,
"delete": true
},
{
"id": INSERT_ID,
"delete": false
}
]
}
I am trying to get it so when the config command is run, the bot looks through this list to find the server which matches the ID of the server the message came from. I have made this code to do this:
let data = fs.readFileSync(__dirname + "/config.json");
let config = JSON.parse(data);
let found = false;
for(let server of config.servers) {
if (server.id === message.guild.id.toString()) {
found = true;
if (server.delete) {
server.delete = false;
message.reply("`Message Delete` has been toggled to `False`");
} else {
server.delete = true;
message.reply("`Message Delete` has been toggled to `True`");
}
}
}
if (!found) {
message.reply("I couldn't find this server in the database!");
}
let newData = JSON.stringify(config)
fs.writeFileSync(__dirname + "/config.jsom", newData);
If I console.log the message.guild.id it prints a number which matches the strings stored in my JSON file, however the IF statement if (server.id === message.guild.id) evaluates to false and I am not sure why.
I know your question has already been answered in the comments, but I just wanted to mention a different way of achieving the same result (and I also wanted to post a full answer to the question).
Instead of using a for/of loop to find the item that matches your specified criteria (matching guild IDs), you can simply utilize arrays' built-in find method to do so. Here's an example of how that would look in your code:
let found = config.servers.find(server => server.id == message.guild.id);
if (found) {
if (found.delete) {
found.delete = false;
message.reply("`Message Delete` has been toggled to `False`");
} else {
found.delete = true;
message.reply("`Message Delete` has been toggled to `True`");
}
}
else {
message.reply("I couldn't find this server in the database!");
}
I personally find this method to be cleaner than using the for/of loop by reducing the overall number of embedded conditionals/loops. And this code functions the same as your current code (in fact, the method probably utilizes a for/of loop itself). Of course, the main solution to the problem you were having is that you should use == instead of === due to their differing meanings in javascript, and it is also worth noting that you do not need to call toString() on message.guild.id when using ==.
Related
let adminMap = new Map()
async function orionCheck(interaction, adminMap) {
const guild = await client.guilds.fetch(General.SERVER.ID)
const members = await guild.members.fetch()
var memberList = [];
members.forEach(member => memberList.push(member.user.id));
for (let i = 0; i < memberList.length; i++) {
if (members.get(memberList[i]).roles.highest.permissions.has("ADMINISTRATOR")) adminMap.set(members.get(memberList[i]).user.id, {BPM: 0, KPM: 0}) //console.log(members.get(memberList[i]).user.id)
}
var orionObjects = {
banObject: ["API/Orion Objects/OrionData.json", "Ban", "BPM", adminMap.get(interaction.user.id).BPM],
kickObject: ["API/Orion Objects/Kickbject.syrex", "Kick", "KPM", adminMap.get(interaction.user.id).KPM]
}
var objectPick = orionObjects.unknown;
if (interaction.commandName == 'ping' && General.SERVER.CHANNELS.LOGS !== "") {
objectPick = orionObjects.banObject;
if (client.orion == undefined) {
client.orion = adminMap;
console.log(client.orion.get(interaction.user.id), "client.orion made")
} else {
client.orion.set(client.orion.get(interaction.user.id).BPM, client.orion.get(interaction.user.id).BPM++)
console.log(client.orion.get(interaction.user.id))
//console.log(client.orion)
}
} else return; //ping and topic cmds are used as placeholder for ban and kick
if (interaction.commandName == 'topic' && General.SERVER.CHANNELS.LOGS !== "") {
} else return;
}
client.on('interactionCreate', async interaction => {
if (!interaction.isCommand()) return;
orionCheck(interaction, adminMap);
});
this is code for every time a command is executed, it adds 1 to your specific user on a map which is what the map is there for. the client.orion is set to the map so that it remembers it each time the command is executed and makes the map globally executable. the if statement is checking if the client.orion was already made and if its undefined it makes it. pretty simple. but the problem is, for some reason on startup, you execute the command. it makes the client.orion then you execute it again and it does the else statement since now client.orion already exists and it adds one to the array. but when you execute it a third time, it stays at one as shown
https://i.imgur.com/Uve78bx.png
This isn't a solution to your particular problem (but maybe it can provide some clues on what I was referring to in comments.)
On a Map object, set takes two parameters, the key and the value.
You have this line in your else block:
client.orion.set((interaction.user.id).BPM, client.orion.get(interaction.user.id).BPM++)
Notice that the "key" is undefined because (interaction.user.id).BPM doesn't exist.
You should have this line instead:
client.orion.set(interaction.user.id, client.orion.get(interaction.user.id).BPM++)
I thought it was strange when tested your code both ways (as undefined, and as defined) and got the same results. But whats really going on is that the set() is doing no work when the key passed to it is undefined. Instead the code in the value parameter is doing work (even though set() is not):
client.orion.get(interaction.user.id).BPM++
ALSO:
Your value parameter to set() has a logical error in that it's supposed to be an object. You are passing a integer to it. You didn't encounter what unexpected results this will create because so far your set() isn't doing work due to the undefined key.
I created a site (dashboard) with NextJs which allows a Discord user to connect with his account. So I was able to recover the different guilds of the user but I would like to sort them to keep only the one where he has (at least) the MANAGE_GUILD perm or if he is the owner of the guilds.
I started to create a function to sort the guilds but it doesn't seem to work
export function guildsperm(guilds) {
guilds.map((guilds) => {
if (guilds.owner === true) {
return guilds;
} else if (guilds.permissions <= 0x0000000020) {
return guilds;
} else {
return;
}
});
}
The doc : https://discord.com/developers/docs/topics/permissions#permissions
The way to check for the permissions is not to operate on them with "<.>,=" but rather with bitwise operators, as described in your docs!
For example, your specific case should be to change
else if (guilds.permissions <= 0x0000000020)
into
else if (guilds.permissions & 0x0000000020 == 0x0000000020)
Try it out and let us know if it works.
I have this code:
const args = message.content.split(" ");
args.shift();
var mention = message.mentions.users.first()
const subject = args[0];
if (!subject) {
return message.say(`*you wand projects a stream of water*`)
} else if (subject === mention) {
return message.say(`*Your wand projects a stream of water at ${mention} and they are now soaked*`)
and I am trying to get it to pick up the mention.users.first() variable called mention so people can specify to shoot the spell at someone. I can't quite figure out how to get it to be checked. I've tried a couple of things like:
} else if (subject === mention) {
} else if (subject === 'mention') {
} else if (subject === {mention}) {
I knew this one probably wouldn't work but I tried it:
} else if (subject === ${mention}) {
I can't figure out if I'm not wording it properly or if it is just the wrong way to do entirely. Any pointers or ideas would be appreciated.
Well a role mention in <Message>.content would take the form of <#&ID>, it will be a sstring, discord.js already has a static property of the regex needed to validate role mentions which is: /<#&(\d{17,19})>/g, so now you just have to test if the string passes:
const regex = /<#&(\d{17,19})>/g;
if(regex.test(subject)) {
}
Also like I said you can get this regex by the static property
https://discord.js.org/#/docs/main/v12/class/MessageMentions?scrollTo=s-ROLES_PATTERN
const {MessageMentions} = require("discord.js");
const regex = MessageMentions.ROLES_PATTERN;
bot.on('message', message => {
if (message.content === 'spam') {
message.channel.send('spam');
while (message.channel.send('spam')) {
if (message.content === 'stop spam') {
return message.channel.send('stopped');
}
}
}
});
im still fairly new to javascript so im not sure if this is even possible the way ive been trying to do it ive looked through w3schools developers.mozilla and even a few questions that are already on here; ive tried using do while, and for loops and ive tried multiple versions of the code i have up there
the ultimate goal is if a user sends the word 'spam' the bot should continuously send the word 'spam' and keep doing so till the bot is turned off or a user sends the words 'stop spam'
Here are some things you should know about the code you're working with:
message.channel.send returns a Promise, so you can't put that in a while loop, because you need to have something that is true or false (a Boolean).
Right now you're trying to check if a message's content is equal to 'stop spam' while you're inside the if-statement checking if the content is equal to 'spam' - So you'll never get inside the inner if-statement.
I would recommend practicing basic javascript a bit more, then moving to Node.js, then coming back to Discord.js - However, it might be cool for you to see a spammer work, so I wrote a some spam code you could use - check this out:
First, create a new file named spamCtrl.js that looks like this (see comments in code for descriptions of what's going on):
let spamming = false;
let spamChannel = undefined;
// spam function repeats until variable spamming is false
function spam() {
return new Promise((resolve, reject) => {
// add check to make sure discord channel exists
if (!spamChannel)
reject('Channel is undefined!');
// send message on spam channel
spamChannel.send('spam')
.then(msg => {
// wait 100 ms until sending next spam message
setTimeout(() => {
// continue spamming if spamming variable is true
if (spamming) {
spam()
.then(resolve) // not entirely necessary, but good practice
.catch(console.log); // log error to console in case one shows up
}
// otherwise, just resolve promise to end this looping
else {
resolve();
}
}, 100)
})
.catch(console.log);
});
}
// public functions that will be used in your index.js file
module.exports = {
// pass in discord.js channel for spam function
setChannel: function(channel) {
spamChannel = channel;
},
// set spam status (true = start spamming, false = stop spamming)
setStatus: function (statusFlag) {
// get current status
let currentStatus = spamming;
// update spamming flag
spamming = statusFlag;
// if spamming should start, and it hasn't started already, call spam()
if (statusFlag && currentStatus != statusFlag) {
spam();
}
},
// not used in my commands, but you may find this useful somewhere
getStatus: function() {
return spamming;
}
};
Next, import that file into your index.js file (Must be in the same directory as your spamCtrl.js file - unless you change the require statement below).
// in index.js file, get controller for spam messages
let spamCtrl = require('./spamCtrl');
Final step: In your index.js file (or wherever you're handling your spam commands) set up your commands (this can be renamed as you like):
// 2 commands together make spamming work :)
case '?SPAM':
spamCtrl.setChannel(message.channel);
spamCtrl.setStatus(true);
break;
case '?STOP-SPAM':
spamCtrl.setStatus(false);
break;
Let me know if you would like any additional explanations on anything, or if you want to see some tweaks here 'n there.
Try using a variable instead. You cannot use message.channel.send('spam') for the while loop.
var spam = false;
if (message.content === 'spam') {
if (message.author.id !== bot.user.id) { // Replace bot with the instance of your bot Client.
spam = true;
} else {
if(spam) {
message.channel.send('spam');
}
}
if (message.content === 'stop spam') {
if(spam) {
message.channel.send('stopped');
}
spam = false;
}
}
I have a data like this:
"customers": {
"aHh4OTQ2NTlAa2xvYXAuY29t": {
"customerId": "xxx",
"name": "yyy",
"subscription": "zzz"
}
}
I need to retrive a customer by customerId. The parent key is just B64 encoded mail address due to path limitations. Usually I am querying data by this email address, but for a few occasions I know only customerId. I've tried this:
getCustomersRef()
.orderByChild('customerId')
.equalTo(customerId)
.limitToFirst(1)
.once('child_added', cb);
This works nicely in case the customer really exists. In opposite case the callback is never called.
I tried value event which works, but that gives me whole tree starting with encoded email address so I cannot reach the actual data inside. Or can I?
I have found this answer Test if a data exist in Firebase, but that again assumes that you I know all path elements.
getCustomersRef().once('value', (snapshot) => {
snapshot.hasChild(`customerId/${customerId}`);
});
What else I can do here ?
Update
I think I found solution, but it doesn't feel right.
let found = null;
snapshot.forEach((childSnapshot) => {
found = childSnapshot.val();
});
return found;
old; misunderstood the question :
If you know the "endcodedB64Email", this is the way.:
var endcodedB64Email = B64_encoded_mail_address;
firebase.database().ref(`customers/${endcodedB64Email}`).once("value").then(snapshot => {
// this is getting your customerId/uid. Remember to set your rules up for your database for security! Check out tutorials on YouTube/Firebase's channel.
var uid = snapshot.val().customerId;
console.log(uid) // would return 'xxx' from looking at your database
// you want to check with '.hasChild()'? If you type in e.g. 'snapshot.hasChild(`customerId`)' then this would return true, because 'customerId' exists in your database if I am not wrong ...
});
UPDATE (correction) :
We have to know at least one key. So if you under some circumstances
only know the customer-uid-key, then I would do it like this.:
// this is the customer-uid-key that is know.
var uid = firebase.auth().currentUser.uid; // this fetches the user-id, referring to the current user logged in with the firebase-login-function
// this is the "B64EmailKey" that we will find if there is a match in the firebase-database
var B64EmailUserKey = undefined;
// "take a picture" of alle the values under the key "customers" in the Firebase database-JSON-object
firebase.database().ref("customers").once("value").then(snapshot => {
// this counter-variable is used to know when the last key in the "customers"-object is passed
var i = 0;
// run a loop on all values under "customers". "B64EmailKey" is a parameter. This parameter stores data; in this case the value for the current "snapshot"-value getting caught
snapshot.forEach(B64EmailKey => {
// increase the counter by 1 every time a new key is run
i++;
// this variable defines the value (an object in this case)
var B64EmailKey_value = B64EmailKey.val();
// if there is a match for "customerId" under any of the "B64EmailKey"-keys, then we have found the corresponding correct email linked to that uid
if (B64EmailKey_value.customerId === uid) {
// save the "B64EmailKey"-value/key and quit the function
B64EmailUserKey = B64EmailKey_value.customerId;
return B64UserKeyAction(B64EmailUserKey)
}
// if no linked "B64EmailUserKey" was found to the "uid"
if (i === Object.keys(snapshot).length) {
// the last key (B64EmailKey) under "customers" was returned. e.g. no "B64EmailUserKey" linkage to the "uid" was found
return console.log("Could not find an email linked to your account.")
}
});
});
// run your corresponding actions here
function B64UserKeyAction (emailEncrypted) {
return console.log(`The email-key for user: ${auth.currentUser.uid} is ${emailEncrypted}`)
}
I recommend putting this in a function or class, so you can easily call it up and reuse the code in an organized way.
I also want to add that the rules for your firebase must be defined to make everything secure. And if sensitive data must be calculated (e.g. price), then do this on server-side of Firebase! Use Cloud Functions. This is new for Firebase 2017.