How to split command - javascript

So I have a poll command, it will gonna &poll [pollEvent] [agreeStatement] [disagreeStatement]
Here's my code
if (command === 'poll') {
let pollMessage = args[0]
let aggree = args[1];
let disagree = args[2];
const agreeEmoji = '<a:verified:753654287338569778>'
const disagreeEmoji = '<:no:753654286134542447>'
if (!pollMessage) return message.reply("What are you going to poll?")
if (!aggree) return message.reply('Please insert the aggree statement')
if (!disagree) return message.reply("Please insert the disagree statement")
const pollEmbed = new Discord.MessageEmbed()
.setTitle('Poll!')
.setColor('#00FF2A')
.addFields(
{ name: pollMessage, value: `
<a:verified:753654287338569778> ${aggree}
<:no:753654286134542447> ${disagree}`}
)
message.delete();
let msg = await message.channel.send(pollEmbed);
await msg.react('753654287338569778')
await msg.react('753654286134542447')
const filter = (reaction, user) => reaction.emoji.id === '753654287338569778' || reaction.emoji.id === '753654286134542447'
const result = await msg.awaitReactions(filter, {time: 5000}).then((collected) => {
if (msg.reactions.cache.get('753654287338569778').count-1 <= 0 || msg.reactions.cache.get('753654286134542447').count-1 <= 0) return message.channel.send("No one voted sorry this poll is aborted")
let resutEmbed = new Discord.MessageEmbed()
.setTitle('Voting Complete!')
.setColor('#00FF2A')
.addFields(
{name: pollMessage, value: `<a:verified:753654287338569778> ${aggree} => ${collected.get('753654287338569778').count-1}
<:no:753654286134542447> ${disagree} => ${collected.get('753654286134542447').count-1}`}
)
msg.edit(resutEmbed)
msg.reactions.removeAll()
})
}
But the problem is, when I said &poll Should I go outside? Yes No it will shown like, because I want to be like &poll Should I go outside? Yes No then the bot will add Yes and No as the agree and disagree statement and make Should I go outside? as poll event message, any ideas?

Seems like the Array Destructuring and the rest operator ES6s features will come handy for your command.
You can "destructure" your args Array elements and give each one a variable name by doing the following:
// where: let [word1, word2, ...rest] = args
// is the same as:
let [word1, word2, ...rest] = ['Should', 'I', 'go', 'outside', 'yes', 'no'];
By doing this you can start working with the command entries, no matter how long these would be. Here rest is also declared as a variable and contains the "rest" of the elements that weren't named:
console.log( rest );
// will prompt •> ['go', 'outside', 'yes', 'no']
If you want to enable personalized responses per poll, your implementation could be upgraded to:
let [...question, option_a, option_b] = args;
Which would be fine for this case, although I would advise against making the command's answer options personalized if you're just looking to implement a yes / no poll.
If in the future you would like to offer more than two answer choices, you could design the command to detect them after a special character like:
&poll What's the coolest pet: dog, cat, panda
(Special character being : here)
You may also want to consider performing an Array.join() method and String.split() to process your command entry as the ...rest operation way would only work for single worded answer options: sure / nah, and errors would come out if you get an entry like:
&poll Should I go outside?: sure thing nah
as option_a will contain thing / and option_b contain nah

Related

How would I get the number of bans a person has done?

I'm looking for a way to get the number of bans a moderator has done, here is what I have so far. I'm guessing I have to loop thru each ban?
let targetMod = message.mentions.users.first()
message.guild.bans.fetch().then((bans) => {
bans.forEach((ban) => {
//My problem is here, I dont know how to check who did the ban
})
})
The moderator is not actually provided in the info. You will need to check the audit logs for this (will only go back to a certain time, it's not fully accurate)
let logs = await message.guild.fetchAuditLogs()
logs = logs.entries.filter(e => e.action === "MEMBER_BAN_ADD")
logs = logs.entries.filter(e => e.executor?.id === targetMod.id)
console.log(logs.size) //should be the rough amount of bans

How can I return a list of substrings contained within a string that match an array?

I'm trying to rewrite a Python discord bot in Javascript for obvious reasons. I'm trying to set up a 'banned word' list, so if someone says a word in that list, the message will be deleted and they'll get a warning. Easy enough. My code for that is:
bot.on('messageCreate', message => {
const bannedwords = ['word1', 'word2'];
if (bannedwords.some(term => message.content.includes(term))) {
message.delete();
message.author.send(`Woah there buddy! You can't say that.`)
}
});
My question is: How can I return a list of the matching substrings?
So: if a person sends "My name is person1 and I think person3 is bad" when the bannedwords list says ['person1', 'person2', 'person3', 'person4'] I want the function to return ['person1', 'person3']. How can I do this?
In python, I used [word for word in bannedwords if word in message.content] if that helps any.
You can use Array#filter() to return what bannedwords were found in message.content. This will return an array of matches.
bot.on('messageCreate', message => {
const bannedwords = ['word1', 'word2'];
const matches = bannedwords.filter(term => message.content.includes(term));
if (matches.length) {
message.delete();
message.author.send(`Woah there buddy! You can't say that.`)
console.log(`The banned words used were ${matches.join(', ')}`);
}
});
Documentation on Array.prototype.filter()

Is there some kind of find method on Arrays that returns [item | undefined] rather than item | undefined?

Here is some code from I project I am working in:
const profile = userdataDocs
.filter(isValidUserdataDocument)
.find((document: ICouchDBDocumentDoc) => document._id === profileId);
if (profile) {
return {
id: hashSensitive(profile._id, environment),
type: profile.type,
creationDate: profile.creationDate,
updatedDate: profile.updatedDate,
entityVersion: profile.entityVersion,
};
}
Here is how I would like to have my code look:
return userdataDocs
.filter(isValidUserdataDocument)
.filter((document: ICouchDBDocumentDoc) => document._id === profileId)
.map((profile: ICouchDBDocumentDoc) => ({
id: hashSensitive(profile._id, environment),
type: profile.type,
creationDate: profile.creationDate,
updatedDate: profile.updatedDate,
entityVersion: profile.entityVersion,
}))
.slice(0, 1);
But I get feedback from the rest of my team that I should not use filter because it will continue searching after having found an item. Premature optimization in mind, but still a pretty valid and popular opinion.
Is there some other array method (or altogether different solution) that I can use to write code the way I want, with 'pipes', without getting the performance penalty of moving from find to filter?
Also let me know if I am an idiot and should let go of the pipe dream (pun intended).
Let me start that I like the first solution. In my opinion, it looks good.
But if you are really desperate for a solution that fulfills your pipe dream
const array = [10, 20, 30];
function singleMapFind(args, fn) {
const currentArray = args[2];
const duplicate = [...currentArray];
currentArray.splice(1, currentArray.length - 1);
return duplicate.find(fn);
}
const modified = array.map((...args) => singleMapFind(args, (e) => e > 20));
I would never use it though. Wish you luck with the PR.

Discord bot delete command

My main goal is for someone with message managing permissions to type a command for deleting a message but be able to specify how many messages they'd like to delete.
I have tried messing with variables but I don't have much knowledge on them, usually ending in some errors. I've tried replacing the value of messages deleted (the 2) with the variable with success but I'm clueless when it comes to changing the variable with a message.
if(message.member.hasPermission('MANAGE_MESSAGES')) {
if(message.content.startsWith(`${prefix}delete`)) {
message.channel.bulkDelete(2)
}
}
I will suppose you have it on message event.
This is one of many ways you can do it:
if(message.content.startsWith(`${prefix}delete`)) {
const user = message.mentions.users.first();
// Parse Amount
const amount = !!parseInt(message.content.split(' ')[1]) ? parseInt(message.content.split(' ')[1]) : parseInt(message.content.split(' ')[2])
//Check if it the amount for message to delete where declared
if (!amount) return message.reply('Must specify an amount to delete!').then(msg => msg.delete(15000));
// Fetch 100 messages (will be filtered and lowered up to max amount requested)
message.channel.fetchMessages({
limit: 100,
}).then((messages) => {
//I declare the messages like that with amount + 1 to delete the command itself
messages = messages.array().slice(0, amount + 1);
//And finally buldDelete deletes the desired amount
message.channel.bulkDelete(messages).then(messages => console.log(`Bulk deleted ${args[0]} messages`))
.catch(console.error);
});
You would need to split message.content, which will return an array that I'll name args for this example. Then, args[1] should be the number you are looking for.
const prefix = '#'
const args = message.content.split(' ')
if(message.member.hasPermission('MANAGE_MESSAGES')) {
if(message.content.startsWith(`${prefix}delete`)) {
message.channel.bulkDelete(args[1])
}
}
Et voilà ! You just need to make sure that args[1] is a number now.

Work with returning Neo4j nodes in a javascript project

in my javascript project i use long cypher queries. The beginning of the queries are quite similar. Can i use the node return of one function in a new querie somehow? I use neo4j-driver and the community neo4j version. To simplify my problem i changed the querie in my example.
const doSomething1 = async() =>{
let query = [
'MATCH (person:Person)',
'RETURN person'
].join('\n');
let _person = await session.run(query,{});
return _person;
};
const doSomething2 = async() =>{
let _person = await doSomething1();
let query = [
'WITH {_testPerson} as _testPerson',
'WHERE _testPerson.age = 18',
'RETURN person'
].join('\n');
let _resultTestPerson = await session.run(query,{
_testPerson: _person,
});
return _resultTestPerson;
};
I expect that the "doSomething2" function will return all nodes that are age 18.
Try looking into the UNWIND operator: it takes an array and lets you run a query on each element in it. Your second query might look something like this:
UNWIND {arrayOfPeople} AS person
WHERE person.age = 18
RETURN person
On a side note, the example you gave could be written as one pretty simple query. Maybe your actual problem could be solved in just one query:
MATCH (p:Person)
WHERE p.age = 18
RETURN p
Since doSomething1 already got all the Person nodes, doSomething2 does not need to make another neo4j query.
Instead, doSomething2 should just iterate through the doSomething1 results and filter for the nodes of interest.

Categories