Issues with the Documents in Mongoose (JavaScript) - javascript

So I'm making a bot for discord but I'm having some issues with Mongoose. So what I want is basically, the user sends a message to save a Document with some of his info, but if there is already a Document with his info it will stop the process with return. So I tried this:
function main(message){
// So first user sends a message to store some data about him
let author = message.author //this is discord.js syntax, basically it returns the author of a message
let id = author.id //also discord.js syntax, returns the id from the user, in this case the author variable above
let check = logUser.findOne({userId : [id]}).exec().then(res => {
if (res) return true;
else return false;
})} // So if there is a Document with the id of the author of the message it will return true, else it returns false
if (check === true) return console.log("This User has already a Document with his info saved");
//so if the user has already a Document with his info it will return and stop the action of saving his Data
//everything from this point is basic Mongoose Syntax, to make a Document with User data
const theUser = new logUser({
_id : mongoose.Types.ObjectId(),
userName : author.username,
userId : author.id,
currency : 0
})
theUser.save()
.then(result => console.log(result))
.catch(err => console.log(err))
console.log(`User ${author.username} was stored into the database!`)
}
It fails in the if statement that checks if the user has a Document with his info already. I've tried multiple things but it doesn't work.
I think that the solution for this problem has to do with async functions but I'm not sure, and I don't know that much about async processes.
Thanks in advance!

The problem is that your treating logUser.findOne as synchronous. Perform the check in findOne callback like so:
function main(message){
// So first user sends a message to store some data about him
let author = message.author //this is discord.js syntax, basically it returns the author of a message
let id = author.id //also discord.js syntax, returns the id from the user, in this case the author variable above
logUser.findOne({userId : [id]}).exec().then(res => {
let check = Boolean(res);
if (check === true)
return console.log("This User has already a Document with his info saved");
const theUser = new logUser({
_id : mongoose.Types.ObjectId(),
userName : author.username,
userId : author.id,
currency : 0
});
theUser.save()
.then(result => {
console.log(result);
console.log(`User ${author.username} was stored into the database!`)
})
.catch(err => console.log(err))
});
}
Are you purposely wrapping the id in an array? I don't know your schema but it seems odd and may contributing to your issues. userId : [id]
You may want to consider async/await to reduce callbacks. You can also look into using a unique index to avoid multiple requests in the future. Using a unique index will throw an error when trying to save the same document twice.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await
https://docs.mongodb.com/manual/core/index-unique/

Related

guildBanAdd can not read property 'id' of undefined

I am trying to send a message to my audit logs every time someone gets banned from the server. This command works when someone joins the server, but it does not work when someone is banned, or unbanned.
This is the current code in the index.js file:
bot.on('guildBanAdd', async (member) => {
let channels = JSON.parse(
fs.readFileSync("././database/moderationChannel.json", "utf8")
);
let modchannel = channels[member.guild.id].channel;
let modChannel = bot.channels.cache.find(channel => channel.id === `${modchannel}`);
modChannel.send(`${member} was banned!`);
});
What I want to happen is when the member is banned the message is sent to the modCannel. Is there anyway that this can happen?
As Caramiriel mentioned in their comment, guildAddBan first parameter is the guild the ban occurred in and the second one is the user that was banned. There is no member parameter.
Another thing, as you store the channel IDs in the moderationChannel.json file. you can use channels.cache.get() instead of .find(). .get() should be preferred, as it gets an element with the specified key (the channel ID in this case).
You'll also need to replace member with user in modChannel.send() and check if modChannel exists. Check the snippet below:
bot.on('guildBanAdd', async (guild, user) => {
let channels = JSON.parse(
fs.readFileSync('././database/moderationChannel.json', 'utf8')
);
let channelId = channels[guild.id].channel;
let modChannel = bot.channels.cache.get(channelId);
if (!modChannel) {
return console.log(`No moderation channel found with ID ${channelId}`);
}
modChannel.send(`${user} was banned!`);
});

Trying to fetch a member based on their nickname/displayname. Discord.js BOT

Hi am i trying to take a user specified nickname for a member and fetch that members and get additional information about that user. Right now i have confirmed the ARGS[0] sent by the user is correct but i am getting a NULL response to the matched user. Not sure what i am missing. Thanks
This is my current code. Just trying to get the match working right now. I also need to consider if the person doesnt have a nickname to check the username. Or think would displayname property be better. Thanks
if(command === "memberinfo") {
let sentNickname = args[0];
message.channel.send(`Sent Nickname: ${sentNickname}`);
const discordserver = client.guilds.get(DragonTS); // Define server to get information from
discordserver.fetchMembers() // Fetch guild members
.then() //.then(console.log)
.catch(console.error);
}
let matchedMember = discordserver.members.find(m => m.nickname === sentNickname);
message.channel.send(`Matched Member ${matchedMember}`);
Looks like some parts of your code aren't executed. You need to put all your code into the .then():
if(command === "memberinfo") {
let sentNickname = args[0];
message.channel.send(`Sent Nickname: ${sentNickname}`);
const discordserver = client.guilds.get(DragonTS); // Define server to get information from
discordserver.fetchMembers() // Fetch guild members
.then((serverWithFetchedMembers) => {
let matchedMember = serverWithFetchedMembers.members.find(m => m.nickname === sentNickname);
message.channel.send(`Matched Member ${matchedMember}`);
}) //.then(console.log)
.catch(console.error);
}
It will wait for the fetchMembers() function and execute your code after it!

How to check for a certain channel /role by a certain user

I want my bot to be able to check...
If a channel my bot made matches a certain name...
OR
If a role my bot made matches a certain name...
THEN
The bot would return the action with the message Mod mail is already activated here!
Here's my code
var mg = message.guild
const mythings = mg.channels.filter(chane => chane.client.user.id === `595840576386236437` && chane.name === 'modmail' &&chane.type === `text`);
const mythings2 = mg.channels.filter(chane => chane.client.user.id === `595840576386236437` && chane.name === 'qanda' &&chane.type === `text`);
const mythings3 = mg.roles.filter(role => role.client.user.id === `595840576386236437` && role.name === 'ModMail');
console.log(mythings)
if(mythings) return message.channel.send(`Rejected! There's possible fragments of modmail already set up here!`)
if(mythings2) return message.channel.send(`Rejected! There's possible fragments of modmail already set up here!`)
if(!mythings3) return message.channel.send(`Rejected! There's possible fragments of modmail already set up here!`)
NOTE
I am doing in this in discord.js-commando, not discord.js so this is not in my index.js file so my only limitation is I can't refer to the client variable. Directory is ~/commands/extras/modmail.js/ instead of ~/index.js/ What I mean by this is I cannot start with the client variable because it will return to me as undefined, but something like channel.client would be allowed because it's defining the creator of the channel the messgae was sent in.
What went wrong
Here's what went wrong.
Bot doesn't find the channel channel
Bot returns
OR
Bot finds channel
Bot continues to make all the channels and roles.
I expect: Bot can search the guild for a channel that meets client.id AND name expectations and then return. Also, Bot can search the guild for a role that meets the owner (my(Referring to me being the bot)) id AND name and then return also.
The actual result is the bot returning when it's not supposed to, e.g. Bot returns when it doesn't find a channel when it is supposed to create one. (I cut out the code for it though)
Collection.filter() will always return a new Collection. Therefore, your first condition is always returning true and executing the return statement because the variable exists.
Either check the size property of the Collection, or use Collection.find() which will only return an element if the predicate function returns true.
Also, you'll have to go through the Audit Logs to check the creator of a channel. The instantiator is the client that created the instance of the object, which is not equivalent to actually creating the channel itself.
// Async context (meaning within an async function) needed to use 'await'
try {
const channelLogs = await mg.fetchAuditLogs({ user: '595840576386236437', type: 10 });
const myChannels = channelLogs.entries.filter(e => e.target && ['modmail', 'qanda'].includes(e.target.name) && e.target.type === 'text');
const roleLogs = await mg.fetchAuditLogs({ user: '595840576386236437', type: 30 });
const myRole = roleLogs.entries.find(e => e.target && e.target.name === 'Modmail');
if (myChannels.size !== 0 || myRole) {
return await message.channel.send('Rejected! There\'s possible fragments of modmail already set up here!');
}
} catch(err) {
console.error(err);
}

Firebase equalto is returning null

I'm trying to check if a value named 'status' is equal to 'verkoper'.
But in this case it stills returns null, or what i wrote in my code "it does not works , even when it says 'verkoper' in the database.
Picture of the database structure
While the database rules are set like this
In my sign up, I push the name of the ref key equal as the uid like this, so I can easily check every user:
const uid = firebase.auth().currentUser.uid;
firebase.database().ref().child('accounts').child(uid).set({
So after that done, I try to check if the currentuser's status is equal to "verkoper"
let user_id = firebase.auth().currentUser.uid;
console.log(user_id);
const ref = firebase.database().ref(`accounts/${user_id}`);
ref.orderByChild('status').equalTo('verkoper').once('value').then((userSnapshot) => {
if (userSnapshot.exists()) {
//allow user perform action
console.log('it works');
}else {
console.log('it does not work');
// do not allow
}
}).catch((error) => {
console.error(error);
});
I hope this was enough information to figure out what the problem might be

Discord.js - Getting users last activity?

I'm trying to find out if its possible to get the time/information of users last activity retrospectively using discord.js
Say I have something like
client.guilds.find('id', 'SERVER ID').fetchMembers().then(members => {
const role = members.roles.find('name', 'Newbies')
role.members.forEach(member => {
console.log(member.user.lastMessage) // null
})
})
Unless the member has posted, since the client is listening, the lastMessage is always null.
Is there a way to find the last activity? or a workaround, like a query to return all the users messages, which I can then take the most recent one from?
Effectively I want to know what date/time the user last posted so we can monitor non-contributing accounts.
Thanks
After looking thought the documentation I didn't find something neither so I came up with a manual search function.
Basically, it will scan every channels until finding a message from X user, or the end of the messages in the channel. It then compare the last messages of the users from every channels and print the last one.
It can be very long if the user hasn't write since a long time. Of course, you have to check lastMessage before trying this.
I would add a time limit maybe. Because if you have thousand of messages, the function will run eternally.
You can stop the function if the last message found is in the accepted time to not be kick/do whatever.
I made the search stop if the first message found in the pack of fetched messaged is older than the ban limit, however, if the first message is not older, remember that it means for the other, so we still need to check them (it can be avoided by checking the last message of the pack as well).
async function fetchMessageUser(chan, id, res) {
let option = {};
if (typeof res !== 'undefined'){
option = {before: res.id};
}
return await chan.fetchMessages(option)
.then(async msgs => {
if (msgs.size === 0){
return {continue: false, found: false};
};
if ((Date.now() - (msgs.first().createdTimestamp)) > 86400000 ) { // 1 day
return {continue: false, found: false};
}
let msgByAuthor = msgs.find(msg => {
return msg.author.id === id;
});
if (msgByAuthor === null){
return {continue: true, id: msgs.last().id};
} else {
return {continue: false, found: true, timestamp: msgByAuthor.createdTimestamp};
}
})
.catch(err => console.log('ERR>>', err));
}
client.on('message', async (msg) => {
let timestamp = [];
for (let [id, chan] of msg.guild.channels){
if (chan.type !== 'text'){ continue; }
let id = '587692527826763788'; // id of the user, here a non verified account
let res;
do {
res = await fetchMessageUser(chan, id, res);
} while(res.continue);
if (res.found) {
timestamp.push(res.timestamp);
}
}
console.log(timestamp);
let first = timestamp.sort((a,b) => (b-a))[0];
console.log(new Date(first));
});
A better variant would be to run it for an array of users, checking all 50 last messages from every channel, and associating each users with his most recent messages if he wrote one, and doing this until all the messages in all the channels are too old to avoid a kick/whatever. And then do something for all the users who don't have an associated messages.
I think what you need is one of Discord's built in features, namely: pruning. This feature will grab inactive members and lets you kick them. Luckily, discord.js has an API call for it and even lets you get the number of members first without actually kicking them by setting the dry parameter to true. The feature will also allow you to specify the amount of days a user has to be inactive.
Have a look at the docs: https://discord.js.org/#/docs/main/stable/class/Guild?scrollTo=pruneMembers
Hope that helps out!

Categories