How to keep track of the number of times a user has been mentioned? - discord

In my bot, I have a message counter that stores the number of times a user sent a message in the server.
I was trying to count how many times a user got mentioned in the server. Does anyone know how could I do it?

You can use message.mentions.members (or message.mentions.users) to see the mentions in a message. You can store the number of mentions for every user: every time they are mentioned, you increase the count.
var mention_count = {};
client.on('message', message => {
for (let id of message.mentions.users.keyArray()) {
if (!mention_count[id]) mention_count[id] = 1;
else mention_count[id]++;
}
});
Please note that mention_count will be reset every time you restart your bot, so remember to store it in a file or in a database to avoid losing it.
Edit: below you can see your code applied to mentions: every time there's a mention to count, it gets stored in the level value of the score.
client.on('message', message => {
if (!message.guild) return;
for (let id of message.mentions.users.keyArray()) if (id != message.author.id) {
let score = client.getScore.get(id, message.guild.id);
if (!score) score = {
id: `${message.guild.id}-${id}`,
user: id,
guild: message.guild.id,
points: 0,
level: 0
};
score.level++;
client.setScore.run(score);
}
});

Related

Flink session window not working as expected

The session window in Flink is not working as expected on prod env (same logic works on local env). The idea is to emit the count of 'sample_event_two' for a specific user Id & record id incase if there is at least one event of type 'sample_event_one' for the same user Id & record id. ProcessingTimeSessionWindows with session gap of 30 mins is used here and ProcessWindowFunction has the below logic (I am doing a keyby user Id and record Id fields before setting the window size),
public void process(
String s,
Context context,
Iterable<SampleEvent> sampleEvents,
Collector<EnrichedSampleEvent> collector)
throws Exception {
EnrichedSampleEvent event = null;
boolean isSampleEventOnePresent = false;
int count = 0;
for (SampleEvent sampleEvent : sampleEvents) {
if (sampleEvent.getEventName().equals("sample_event_one_name")) {
Logger.info("Received sample_event_one for userId: {}");
isSampleEventOnePresent = true;
} else {
// Calculate the count for sample_event_two
count++;
if (Objects.isNull(event)) {
event = new EnrichedSampleEvent();
event.setUserId(sampleEvent.getUserId());
}
}
}
if (isSampleEventOnePresent && Objects.nonNull(event)) {
Logger.info(
"Created EnrichedSampleEvent for userId: {} with count: {}",
event.getUserId(),
event.getCount());
collector.collect(event);
} else if (Objects.nonNull(event)) {
Logger.info(
"No sampleOneEvent event found sampleTwoEvent with userId: {}, count: {}",
event.getUserId(),
count);
}
}
Though there is sample_event_one present in the collection (confirmed by verifying if the log message "Received sample_event_one" was present) and the count is calculated correctly, I don't see any output event getting created. Instead of EnrichedSampleEvent being emitted, I see log message "No sampleOneEvent event found sampleTwoEvent with userID: "123, count: 5". Can someone help me fix this?
Your ProcessWindowFunction will be called for each key individually. Since the key is a combination of user id and record id, it's not enough to know that "Received sample_event_one" appears in the logs for the same user. Even though it was the same user, it might have had a different record id.

REACT JS - Firestore: How to check documents to validate existing documents and avoid duplicate documents

I'm trying to validate if I already have add a book of the same name AND grade (course) I'm not 100% sure if && works as AND in REACT but I think it does cause didn't got any complaints in the code anyways moving on to the issue:
const register = (e) => {
e.preventDefault();
const docRef = db.collection('libros').doc();
docRef.get().then((doc) => {
if (doc.id.descripcion == descripcion && doc.id.grado == grado)
{
window.alert("Book exist already")
}
else {
docRef.set({
materia: materia,
descripcion: descripcion,
editorial: editorial,
grado: grado,
precio: precio,
id: docRef.id
}).then((r) => {
window.alert("Book added")
})}
})
}
This is the snip code of where I'm having the issue my idea is to loop through all the documents I have in that collection I'm not sure if i'm writing it correctly (clearly not cause is not working).
The idea is that Documents have a field called Description and course (descripcion and grado) and I want to compare the documents first to check if they have the same description and course, like they can have the same description but not the same grade or the same grade but not the same description
(which I think I have that logic correctly) : doc.id.descripcion == descripcion && doc.id.grado == grado
But it doesn't seem to be even running through that code, any tips are welcome and from what I understand is suppose to loop and check every document.
Edit: Forgot to add how it looks in the firebase and the input
This will never find any duplicates:
const docRef = db.collection('libros').doc();
docRef.get().then((doc) => {
if (doc.id.descripcion == descripcion && doc.id.grado == grado) {
window.alert("Book exist already")
}
...
The reason for this is that the first line creates a reference to the new doc. The next line then tries to load that doc, which will never give you any data.
The doc.id.descripcion anddoc.id.grado are also wrong, and should probably be doc.data().descripcion anddoc.data().grado. But that doesn't matter too much, since you'll never get a document from get() anyway, since you're trying to load a document from a reference you just created and never wrote to.
To ensure something is unique in Firestore, use it as the ID of the documents. So if you want the book name and grade to be unique, create the document ID from the book name and grade, instead of asking Firestore to generate a unique ID for you:"
const docId = descripcion + grado;
const docRef = db.collection('libros').doc(docId);
docRef.get().then((doc) => {
if (doc.exists) {
window.alert("Book exist already")
}
...

Is it possible to make a variable dedicated to a certain author Discord.js?

I'm making a store bot and I ran into some SetInterval errors. I want to make it so each variable has the user's id so when I run a different command, it will know which interval to stop. (If that makes sense).
Here is my code:
if(message.content.startsWith(`!open`) {
var cashier1[message.author.id] = function () {
BalanceJSON[message.author.id].bal += 10
Fs.writeFileSync(`./DB/balance.json`, JSON.stringify(BalanceJSON));
}
setInterval(cashier1[message.author.id], 5000);
}
All this code is in a bot.on('message', message => { })
I wanna be able to stop an certain player's interval with clearInterval(cashier1[message.author.id])
The function setInterval returns a unique id which can be used to clear the interval again (See the example for more information).
The solution to your problem is to store the unique id of the interval in some object or database and use that to clear the interval again. See the example code below:
// Create an object to store the intervals.
const cashierIntervals = {};
// Inside your message handler.
// Some dummy if statement for demonstration purpose.
if (message.content === 'setInterval') {
// Create the setInterval and store the unique id in the cashier intervals object.
// You should probably add more checks to see if there is already an interval stored for this author id etc.
cashierIntervals[message.author.id] = setInterval(() => {
BalanceJSON[message.author.id].bal += 10;
Fs.writeFileSync(`./DB/balance.json`, JSON.stringify(BalanceJSON));
}, 5000);
} else if (message.content === 'clearInterval') {
// Clear the interval based on the author id.
// Again, probably add more checks to see if the author id has an interval stored etc.
clearInterval(cashierIntervals[message.author.id]);
// Delete the stored interval entry from the global intervals object.
// Not necessary but it keeps the intervals object small.
delete cashierIntervals[message.author.id];
}
Create an object that takes an id as a key. Your value will be the function you want to interval
Your main file:
const cashier1 = {
// Template for your key:values
'999999999': yourRepeatingFunction(),
}
// Lets say message.author.id returns '999999999'
// Doing setInterval(cashier1[message.author.id], 5000) Will call yourRepeatingFunction()

Split Message of More than 2000 characters Discord.js

I am making a role list command but turns out I have too many roles. Anyway to split the message into more. The roles are stored in an array. Btw I only want roles starting with A.
const roles = message.guild.roles.cache.filter(c => c.name.startsWith('A'))
Here is the error in console
Invalid Form Body content: Must be 2000 or fewer in length.
module.exports = {
name: 'rolelist',
description: 'Sends A List Of Roles Availible In The Server',
execute(message, args, client) {
if (!message.content.startsWith(prefix) || message.author.bot) return;
const roles = message.guild.roles.cache.filter(c => c.name.startsWith('A'))
if (colors.size < 1) {
return message.channel.send('There are no roles starting with the letter A');
}
message.channel.send(roles.array().join(` \n`), {split:true,})
},
};
Accoding to the docs you can split the messages:
.send(data, { split: true })
If you weren't already aware, .send() takes 2 parameters: the content
to send, and the message options to pass in. You can read about the
MessageOptions type here. Using split: true here will automatically
split our help message into 2 or more messages in the case that it
exceeds the 2,000 character limit.
https://discordjs.guide/command-handling/adding-features.html#a-dynamic-help-command

In Firebase, is there a way to get the number of children of a node without loading all the node data?

You can get the child count via
firebase_node.once('value', function(snapshot) { alert('Count: ' + snapshot.numChildren()); });
But I believe this fetches the entire sub-tree of that node from the server. For huge lists, that seems RAM and latency intensive. Is there a way of getting the count (and/or a list of child names) without fetching the whole thing?
The code snippet you gave does indeed load the entire set of data and then counts it client-side, which can be very slow for large amounts of data.
Firebase doesn't currently have a way to count children without loading data, but we do plan to add it.
For now, one solution would be to maintain a counter of the number of children and update it every time you add a new child. You could use a transaction to count items, like in this code tracking upvodes:
var upvotesRef = new Firebase('https://docs-examples.firebaseio.com/android/saving-data/fireblog/posts/-JRHTHaIs-jNPLXOQivY/upvotes');
upvotesRef.transaction(function (current_value) {
return (current_value || 0) + 1;
});
For more info, see https://www.firebase.com/docs/transactions.html
UPDATE:
Firebase recently released Cloud Functions. With Cloud Functions, you don't need to create your own Server. You can simply write JavaScript functions and upload it to Firebase. Firebase will be responsible for triggering functions whenever an event occurs.
If you want to count upvotes for example, you should create a structure similar to this one:
{
"posts" : {
"-JRHTHaIs-jNPLXOQivY" : {
"upvotes_count":5,
"upvotes" : {
"userX" : true,
"userY" : true,
"userZ" : true,
...
}
}
}
}
And then write a javascript function to increase the upvotes_count when there is a new write to the upvotes node.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.countlikes = functions.database.ref('/posts/$postid/upvotes').onWrite(event => {
return event.data.ref.parent.child('upvotes_count').set(event.data.numChildren());
});
You can read the Documentation to know how to Get Started with Cloud Functions.
Also, another example of counting posts is here:
https://github.com/firebase/functions-samples/blob/master/child-count/functions/index.js
Update January 2018
The firebase docs have changed so instead of event we now have change and context.
The given example throws an error complaining that event.data is undefined. This pattern seems to work better:
exports.countPrescriptions = functions.database.ref(`/prescriptions`).onWrite((change, context) => {
const data = change.after.val();
const count = Object.keys(data).length;
return change.after.ref.child('_count').set(count);
});
```
This is a little late in the game as several others have already answered nicely, but I'll share how I might implement it.
This hinges on the fact that the Firebase REST API offers a shallow=true parameter.
Assume you have a post object and each one can have a number of comments:
{
"posts": {
"$postKey": {
"comments": {
...
}
}
}
}
You obviously don't want to fetch all of the comments, just the number of comments.
Assuming you have the key for a post, you can send a GET request to
https://yourapp.firebaseio.com/posts/[the post key]/comments?shallow=true.
This will return an object of key-value pairs, where each key is the key of a comment and its value is true:
{
"comment1key": true,
"comment2key": true,
...,
"comment9999key": true
}
The size of this response is much smaller than requesting the equivalent data, and now you can calculate the number of keys in the response to find your value (e.g. commentCount = Object.keys(result).length).
This may not completely solve your problem, as you are still calculating the number of keys returned, and you can't necessarily subscribe to the value as it changes, but it does greatly reduce the size of the returned data without requiring any changes to your schema.
Save the count as you go - and use validation to enforce it. I hacked this together - for keeping a count of unique votes and counts which keeps coming up!. But this time I have tested my suggestion! (notwithstanding cut/paste errors!).
The 'trick' here is to use the node priority to as the vote count...
The data is:
vote/$issueBeingVotedOn/user/$uniqueIdOfVoter = thisVotesCount, priority=thisVotesCount
vote/$issueBeingVotedOn/count = 'user/'+$idOfLastVoter, priority=CountofLastVote
,"vote": {
".read" : true
,".write" : true
,"$issue" : {
"user" : {
"$user" : {
".validate" : "!data.exists() &&
newData.val()==data.parent().parent().child('count').getPriority()+1 &&
newData.val()==newData.GetPriority()"
user can only vote once && count must be one higher than current count && data value must be same as priority.
}
}
,"count" : {
".validate" : "data.parent().child(newData.val()).val()==newData.getPriority() &&
newData.getPriority()==data.getPriority()+1 "
}
count (last voter really) - vote must exist and its count equal newcount, && newcount (priority) can only go up by one.
}
}
Test script to add 10 votes by different users (for this example, id's faked, should user auth.uid in production). Count down by (i--) 10 to see validation fail.
<script src='https://cdn.firebase.com/v0/firebase.js'></script>
<script>
window.fb = new Firebase('https:...vote/iss1/');
window.fb.child('count').once('value', function (dss) {
votes = dss.getPriority();
for (var i=1;i<10;i++) vote(dss,i+votes);
} );
function vote(dss,count)
{
var user='user/zz' + count; // replace with auth.id or whatever
window.fb.child(user).setWithPriority(count,count);
window.fb.child('count').setWithPriority(user,count);
}
</script>
The 'risk' here is that a vote is cast, but the count not updated (haking or script failure). This is why the votes have a unique 'priority' - the script should really start by ensuring that there is no vote with priority higher than the current count, if there is it should complete that transaction before doing its own - get your clients to clean up for you :)
The count needs to be initialised with a priority before you start - forge doesn't let you do this, so a stub script is needed (before the validation is active!).
write a cloud function to and update the node count.
// below function to get the given node count.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.userscount = functions.database.ref('/users/')
.onWrite(event => {
console.log('users number : ', event.data.numChildren());
return event.data.ref.parent.child('count/users').set(event.data.numChildren());
});
Refer :https://firebase.google.com/docs/functions/database-events
root--|
|-users ( this node contains all users list)
|
|-count
|-userscount :
(this node added dynamically by cloud function with the user count)

Resources