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.
Related
I'm making a discord.js bot that has commands that can have different parameters, such as mc!start vanilla, mc!start tekkit. Only singular string entries are allowed, as that's what I made it to do. But, if the user does not input a parameter, and just does mc!start, I want it to say that you cannot leave the parameter blank, but when I input only mc!start, the script gives me the "TypeError: Cannot read property 'toLowerCase' of undefined" error. I've been trying to do assignment functions and other things like that, but no cigar. Here is a splice of the code.
client.on('message', (message) => {
const messagearray = message.content.trim().split(' ');
const command = messagearray[0];
const minecraft_server = messagearray[1].toLowerCase();
if(command === (`${prefix}help`)) {
message.channel.send('Current Commands: !help, !start(Vanilla, Tekkit, Pixelmon, FarmingValley), !shutdown, !randomsong');
}
else if(command === (`${prefix}start`)) {
if(mcVersions.indexOf(minecraft_server) === -1) {
// more code
Check whether the array element is set before trying to call methods of it.
const minecraft_server = messagearray[1] ? messagearray[1].toLowerCase() : "";
Instead of "" at the end you could provide a default server.
I have a chained AXIOS call that is being called from an array. I need to have the second call finish before the first one makes another API request and the process works fine. My only problem is that I can't reference anything from inside the response of the second chain. I need to update either the calling array(arr) a public array this.excelData.results or even a deep copy of the original array. Every time I get an error saying:
err = TypeError: Cannot read property 'ORCID' of undefined at eval (webpack-
internal:///./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-
loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-
loader/lib/index.js?!./src/views/examples/ExcelWorksheet.vue?vue&type=script&lang=js&:410:49) at
NodeList.forEach (<anonymous>) at eval (webpack-internal:///./node_modules/cache-
loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-
loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/views/examples/ExcelWorksheet.vue?
vue&type=script&lang=js&:381:28) at NodeList.forEach (<anonymous>) at eval (webpack-
internal:///./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-
loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-
loader/lib/index.js?!./src/views/examples/ExcelWorksheet.vue?vue&type=script&lang=js&:378:33)
I have tried adding this or self but nothing seems to help. As I debug in a browser I can see all of the elements of the array but I can't read them in code or change them. Is there something special that I need to do so that I can use the data from the second AXIOS call in the original array?
lookUpORCID(){
this.pubmedArticles=[];
this.makeRequestsFromArray(this.excelData.results);
},
makeRequestsFromArray(arr) {
var self = this
let index = 0;
function request() {
let authorName = arr[index]["Last_Name"]
let linkGetIdList = 'https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?';
linkGetIdList += 'tool=biosketch&db=pubmed&retmode=json&retmax=200&';
linkGetIdList += 'term=' + authorName +'[AU] ';
return axios.get(linkGetIdList).then((res) => {
index++;
let idlist = res.data.esearchresult.idlist
const passID = idlist.join(',')
if (idlist.length > 0) {
var getXmlLink = 'https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?';
getXmlLink += 'db=pubmed&retmode=xml&id=${passID}';
return axios.get(getXmlLink).then((response) => {
// parse document
const parser = new DOMParser()
const xmlDoc = parser.parseFromString(response.data, 'text/xml') // Get ALL XML content
// Do Stuff
**This is the spot that I need to change value in array**
let xyz = arr[index]["ORCID"]
return request();
})
}
if (index >= arr.length) {
return 'done'
}
});
}
return request();
},
You are able to access the arr or the error would have been: cannot read property index of undefined.
You have incremented index after the first request & the arr has the value undefined at the incremented index, so the error says Cannot read property 'ORCID' of undefined.
You can try console.log(arr[index]) before let xyz = arr[index]["ORCID"] to verify above.
I am calling an API endpoint for one of Steam's games through their web api using axios and promises in Node.js. Each JSON response from the endpoint returns 100 match objects, of which only about 10 to 40 (on average) are of interest to my use case. Moreover, I have observed that the data tends to be repeated if called many times within, say, a split second.
What I am trying to achieve is get 100 match_ids (not whole match objects) that fit my criteria in an array by continuously (recursively) calling the api until I get 100 unique match_ids that serve my purpose.
I am aware that calling the endpoint within a loop is naive and it exceeds the call limits of 1 request per second set by their web api. This is why I've resorted to recursion to ensure that each promise is resolved and the array filled with match_ids before proceeding on. The issue I am having is, my code does not terminate and at each stage of the recursive calls, the values are the same (e.g. last match id, the actual built up array, etc.)
function makeRequestV2(matchesArray, lastId) {
// base case
if (matchesArray.length >= BATCH_SIZE) {
console.log(matchesArray);
return;
}
steamapi
.getRawMatches(lastId)
.then(response => {
const matches = response.data.result.matches;
// get the last id of fetched chunk (before filter)
const lastIdFetched = matches[matches.length - 1].match_id;
console.log(`The last Id fetched: ${lastIdFetched}`);
let filteredMatches = matches
.filter(m => m.lobby_type === 7)
.map(x => x.match_id);
// removing potential dups
matchesArray = [...new Set([...matchesArray, ...filteredMatches])];
// recursive api call
makeRequestV2(matchesArray, lastIdFetched);
})
.catch(error => {
console.log(
"HTTP " + error.response.status + ": " + error.response.statusText
);
});
}
makeRequestV2(_matchIds);
// this function lies in a different file where the axios call happens
module.exports = {
getRawMatches: function(matchIdBefore) {
console.log("getRawMatches() executing.");
let getURL = `${url}${config.ENDPOINTS.GetMatchHistory}/v1`;
let parameters = {
params: {
key: `${config.API_KEY}`,
min_players: `${initialConfig.min_players}`,
skill: `${initialConfig.skill}`
}
};
if (matchIdBefore) {
parameters.start_at_match_id = `${matchIdBefore}`;
}
console.log(`GET: ${getURL}`);
return axios.get(getURL, parameters);
}
}
I'm not exceeding the request limits and all that, but the same results keep coming up.
BATCH_SIZE is 100 and
_matchIds = []
I would start with replacing the line:
matchesArray = [...new Set([...matchesArray, ...filteredMatches])];
with this one:
filteredMatches.filter(item => matchesArray.indexOf(item) === -1).forEach(item=>{
matchesArray.push(item)
})
What you were doing was that you effectively replaced the matchesArray var inside your function with new reference. I mean the var that you sent in function parameter from outside was no longer the same var inside the function. If you use matchesArray.push - you do not change the var reference though and the var in outer scope is accurately updated - just as is your intention.
This is the reason why _matchIds remains empty: each time there is a call to makeRequestV2, the inner variable matchesArray becomes 'detouched' from outer scope (during assignment statement execution) and although it gets populated, the outer scoped var still points to the original reference and stays untouched.
I'm making a Discord bot using discord.js, and I'm starting to add JSON stuff to it, so that I can store info for individual users, in a separate file. However, I keep getting an error that says planet is not defined, at the line that says if (bot.log[mentionedGuyName].planet == undefined) {. There are some variables, modules etc. in here that haven't been declared or whatnot, but that's only because if I put all my code on here, it would be pages long. My JSON file is called log.json.
The general purpose of this code block, if it helps, is to see if the user already has a "planet". If so, the bot finds gets that value from the JSON file, and sends it to the channel. If not, then it picks a random one (code I didn't put here because of size)
I think I understand at least kind of why the error is occurring (the planet property isn't defined), but I'm not sure how to fix it. If anyone knows how to declare a JSON property or whatever is going on here, I and my server would be most grateful. Thanks in advance!
Here's my JavaScript file:
let mentionedGuy = message.mentions.members.first();
let mentionedGuyName = null;
let noMentions = message.mentions.members.first() == false ||
message.mentions.members.first() == undefined;
if (noMentions) return;
else mentionedGuyName = mentionedGuy.user.username;
if (message.content.startsWith(prefix + "planet")) {
if (message.content.length > 7) {
if (bot.log[mentionedGuyName].planet == undefined) {
bot.log[mentionedGuyName] = {
planet: jMoon
}
fs.writeFile('./log.json', JSON.stringify(bot.log, null, 4), err => {
if (err) throw err;
});
message.channel.send(targeting);
message.channel.send(coords);
} else {
message.channel.send(bot.log[mentionedGuyName].planet);
}
}
}
Change it so it checks the typeof
if(typeof <var> == 'undefined') //returns true if undefined
Noting that typeof returns a string
Source
So here's the problem. I have a REST API that handles a booking creation, however, before saving the booking inside mongo it validates if there is a clash with another booking.
exports.create = function(req, res) {
var new_type = new Model(req.body);
var newBooking = new_type._doc;
//check if the new booking clashes with existing bookings
validateBooking.bookingClash(newBooking, function(clash){
if(clash == null) // no clashes, therefore save new booking
{
new_type.save(function(err, type) {
if (err)
{
res.send(err); //error saving
}
else{
res.json(type); //return saved new booking
}
});
}
else //clash with booking
{
//respond with "clashDate"
}
});
};
Here you have the validation function to check if there is a clash with bookings on the same day:
exports.bookingClash = function (booking, clash) {
//find the bookings for the same court on the same day
var courtId = (booking.courtId).toString();
Model.find({courtId: courtId, date: booking.date}, function(err, bookings) {
if(err == null && bookings == null)
{
//no bookings found so no clashes
clash(null);
}
else //bookings found
{
//for each booking found, check if the booking start hour falls between other booking hours
for(var i = 0; i<bookings.length ; i++)
{
//here is where I check if the new booking clashes with bookings that are already in the DB
{
//the new booking clashes
//return booking date of the clash
clash(clashDate); //return the clashDate in order to tell the front-end
return;
}
}
//if no clashes with bookings, return null
clash(null);
}
});
};
So, ALL of this works with one single new booking. However, now I want to be able to handle a recursive booking (booking that is made weekly). I have recreated the "create" function and call the validateBooking.bookingClash function inside a for loop.
Unfortunately, when I run this, it calls the bookingClash function perfectly, but when it reaches the line making the search in the database:
Model.find({courtId: courtId, date: booking.date}, function(err, bookings)
It does not wait for the callback and before handling the response "clash", makes i++ and continues.
How can I make it work and wait for the callback?
var array = req.body;
var clashes = [];
for(var i = 0; i<array.length;i++)
{
validateBooking.bookingClash(array[i], function(clash)
{
if(clash)
{
clashes.push(clash);
}
else{
console.log("no clash");
}
}
}
Seems like a basic async call problem, for loops do not wait for callbacks to be called.
You could use async 'series' function for exmaple instead of the for loop. This way each find will get called after the previous one.
Mongoose also has a promise based syntax which can help you : http://mongoosejs.com/docs/promises.html
You Can use async eachSeries
async.eachSeries(users, function iterator(user, callback) {
if(something) {
//thing you want to do
callback();
} else {
callback();
}
}
Since you are using callback functions there are two ways you could try to solve this:
1) use some external library that allows you to perform an asynchronous map operation and run all the checks for each clash. Once they are done check the combined results for a clash and proceed accordingly
I would suggest using the async library
your code would look something like:
async.map(array,(entry,callback) => validateBooking.bookingClash(entry,callback),(error,mappingResults)=>{...})
2) you could try to change this function to a recursive one
`function recursiveValidation(arrayToCheck,mainCallback){
if(arrayToCheck.length === 0) {
return cb(null} // end of array without errors
}
validateBooking.bookingClash(_.head(arrayToCheck), function(clash)
{
if(clash)
{
return mainCallback(clash);
}
return recursiveValidation(_.tail(arrayToCheck),mainCallback);
}
}`
The above code is just a mockup but it should show the point.
The _ is lodash
No need to changing anything in your code except the declaration use let instead of var and your loop should work.
var array = req.body;
var clashes = [];
`
for(**let** i = 0; i<array.length;i++)
{
validateBooking.bookingClash(array[i], function(clash)
{
if(clash)
{
clashes.push(clash);
}
else{
console.log("no clash");
}
}
}`
You have to understand the difference between let and var. Also why var cannot be used for running async code inside a loop.
Learn about let: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
I found the way to get this done after trying all of your answers.
What I had to do was this:
validateBooking.singleBooking(new_type._doc, newBookingClubId, function (clash) {
if (clash == null) // no clash
{
validatorArray.push(0);
if(validatorArray.length == array.length) //has received everything from mongo
{
console.log("Clashes: " + clashes.toString());
if(validatorArray.indexOf(1) > -1) //contains a clash
{
var error = {
code: 409,
message: "409 Conflict",
clashes: clashes
};
errorsHandler.handleError(error, res);
}
This way, I created an array called "validatorArray" that was called every time I received something back from Mongo.
This way I could easily compare the length of the array of bookings and the validatorArray length. When they were equal, it meant that it had received everything back from mongo and could send back the response.
Thanks for the help!