Is there an easy way to mass-remove a user's role with a Discord.JS bot? - discord.js

I've got a verification bot for my server with linked roles. I've currently got it to remove all roles manually one by one, but of course this is inefficient and it only works for about 5/6 roles before stopping for a few seconds and continuing. What I'd like to try is some sort of discUser.removeRoles kind of thing, if that's possible.
Or is there a way to only try removing a role if the person has it? My code just does discuser.removeRole for every binded rank.
UPDATE
I got a notification about this question, so wanted to update it with a new solution for anyone else who finds this:
Create a table of your role ids. (e.g var giveThese = [])
guildMember.roles.add(giveThese,"Reason / Description"
For removing, you can replace roles.add with roles.remove

From what I understand from the question you're looping through every member of the guild and removing the role from each one of them.
To me, the most efficient way to do it is to take from the role the list of the members that have it (with Role.members) and then looping through that list.
You can do something like this:
let roleID = '1234...'
let role = guild.roles.fetch(roleID).then(role => {
role.members.forEach(member => member.roles.remove(roleID))
})
This is the most efficient way I can think for doing that since Discord currently has no way of "bulk removing" roles from users.

I was able to figure out a solution by looping over an external json file that holds all of the roles' data.
In the main file where you are trying to remove the roles, use a for in loop that loops over the json file containing all of the role names. Within the loop put the remove role method in there.
Here's an example of the .json file:
[
{
"role_name": "very slightly red",
"color": "#ffcccc",
"color_tier": "vs"
},
{
"role_name": "very slightly orange",
"color": "#ffedcc",
"color_tier": "vs"
},
{
"role_name": "very slightly yellow",
"color": "#ffffcc",
"color_tier": "vs"
}
]
And here's the code that removes the roles in bulk:
const vs_json = require("../vs_colors.json");
for (var key in vs_json) {
if (vs_json.hasOwnProperty(key)) {
console.log(
key +
" -> " +
vs_json[key].role_name
);
memberData.roles.remove(
getRole(
vs_json[key].role_name
)
);
}
}

Related

?members command for my discord bot - discord.js

So I've been trying to create a ?members command which lists all the users with a role.
So far I've got this:
if (message.content.startsWith("?members")) {
let roleName = message.content.split(" ").slice(1).join(" ");
let membersWithRole = message.guild.members.filter(member => {
return member.roles.find("name", roleName);
}).map(member => {
return member.user.username;
})
const embed = new Discord.RichEmbed({
"title": `Members in ${roleName}`,
"description": membersWithRole.join("\n"),
"color": 0xFFFF
});
return message.channel.send(embed);
}
So, it works if you type the exact name of the role, but not when you ping it or type the first word. I've been trying for hours to figure out how to do it, and I figured I should ask for help.
Thanks in advance!
Pings get translated into a code as they come through, there is a lot of information on how to parse them in the official guide After it's parsed into a role id you can just use members.roles.get() because that is what they are indexed by.
As for finding a partial name, for that you are going to have to run a function on your find and use String.includes.
return member.roles.find(role => role.name.includes(roleName));
This will also work for find the whole name of course, so it can replace your existing line.
However, this may result in more than one role. This is also true for searching by the entire role name, however, as there are no restrictions on duplicate named roles. For this you may want to invert you design and search through message.guild.roles first for any matching roles, then search for members with the roles found.

Setting arrays in Firebase using Firebase console

I am using Firebase console for preparing data for a demo app. One of the data item is attendees. Attendees is an array. I want to add a few attendees as an array in Firebase. I understand Firebase does not have arrays, but object with keys (in chronological order). How do I do that for preparing sample data? My current Firebase data looks like the below.
The Firebase Database doesn't store arrays. It stores dictionaries/associate arrays. So the closest you can get is:
attendees: {
0: "Bill Gates",
1: "Larry Page",
2: "James Tamplin"
}
You can build this structure in the Firebase Console. And then when you read it with one of the Firebase SDKs, it will be translated into an array.
firebase.database().ref('attendees').once('value', function(snapshot) {
console.log(snapshot.val());
// ["Bill Gates", "Larry Page", "James Tamplin"]
});
So this may be the result that you're look for. But I recommend reading this blog post on why Firebase prefers it if you don't store arrays: https://firebase.googleblog.com/2014/04/best-practices-arrays-in-firebase.html.
Don't use an array, when you actually need a set
Most developers are not actually trying to store an array and I think your case might be one of those. For example: can "Bill Gates" be an attendee twice?
attendees: {
0: "Bill Gates",
1: "Larry Page",
2: "James Tamplin",
3: "Bill Gates"
}
If not, you're going to have to check whether he's already in the array before you add him.
if (!attendees.contains("Bill Gates")) {
attendees.push("Bill Gates");
}
This is a clear sign that your data structure is sub-optimal for the use-case. Having to check all existing children before adding a new one is going to limit scalability.
In this case, what you really want is a set: a data structure where each child can be present only once. In Firebase you model sets like this:
attendees: {
"Bill Gates": true,
"Larry Page": true,
"James Tamplin": true
}
And now whenever you try to add Bill Gates a second time, it's a no-op:
attendees["Bill Gates"] = true;
So instead of having to code for the uniqueness requirement, the data structure implicitly solves it.
To add arrays manually using Firebase Realtime DB console:
Use double " " instead of single ' ' quotes
Which provides this structure:
After writing my other answer I realized that you might simply be looking how to add push IDs in the console.
That's not a feature at the moment. Most of is either use different types of keys when entering test data or have a little JavaScript snippet in another tab to generate the keys and copy/paste them over.
Please do request the feature here, since you're definitely not the first one to ask.
firebase array ?yeah, i have same problem with you few weeks ago, but i found it in here. Finally i can use it with my ChartJS.
function jamToArray(snapshot) {
const returnArr = [];
snapshot.forEach(function(childSnapshot) {
const item = childSnapshot.val().time;
returnArr.push(item);
});
return returnArr;
};
firebase.database().ref('sensor').limitToLast(10).on('value', function(snapshot) {
const jam = jamToArray(snapshot);
});

Structuring user data by email address or by user ID

I want to have the users in the database structured in a way that makes it easier for a human to read and manage. Using the users email address as the property name instead of the User ID:
Users:
"Users" : {
"emailaddress#domain.com":{
"id": "DK66qu2dfUHt4ASfy36sdfYHS9fh",
"name": "A Display Name",
"groups": {
"moderators": true,
"users": true
}
},
{...}
}
So that if I have a list of users in a group, they can be read as a list of emails and not a list of user IDs.
Groups Such as:
"Groups": {
"moderators":{
"name": "moderator",
"members": {
"emailaddress#domain.com": true,
"emailaddress2#domain.com": true
}
}
}
Groups Instead of:
"Groups": {
"moderators":{
"name": "moderator",
"members": {
"DK66qu2dfUHt4ASfy36sdfYHS9fh": true,
"K2fkHYQDFOge3Hw7SjRaGP3N2sdo": true
}
}
}
However, using rules to verify a property of the user (such as their group), would require me to maintain two list of users, one like the list above, and another essentially a table of key-value pairs of ID's and email addresses so I can get the users email address from their uid.
Pseudo-code rule: Users[UsersKeyVal[auth.uid]].groups.moderator == true
With firebase, what would be considered the most acceptable practice? What are the pros and cons of both?
Please do not store user data under their email address! This will be BIG TROUBLE later.
Your users node should follow the 'standard' Firebase design pattern
users
uid_0
name:
gender:
etc
uid_1
name:
gender:
etc
The bottom line is that in general, it's best to disassociate the dynamic data stored in the node from the key of the node.
Why?
Suppose you build a complex structure with all kinds of links and references to frank#mycoolcompany.com and then #mycoolcompany.com gets acquired by #mynotsocoolcompany.com. Well, you will then have to go in and rebuild every reference to franks's email in the entire database. ugh.
Then what if there are 100 or 1000 users #mycoolcompany.com! Ouch.
If you disassociate the data, like my per above suggested structure, you just change the email address within the node and everything else... just works!
PLEASE, read this answer on stack overflow - written by a Firebaser and addresses your question
Firebase data structure and url
In my opinion there is no problem with your data structure.
According to the Doc
This is a necessary redundancy for two-way relationships. It allows you to quickly and efficiently fetch your members memberships
Also using the generated UId from firebase or your custom Id (here your e-mail) doesn't change the way firebase works. You just have to make sure your e-mail are unique.

Can I check if a value is only pushed if a certain field value is not filled already?

I am trying to make a Meteor app to let users push a value to the database. It works ok, but there a small issue. As soon a certain user has pushed his information, i don't want to let the same user create another entry. Or this must be blocked, or the value the user is pushing must be overwritten for the value he is posting the second time. Now I get multiple entry's of the same user.
Here is my code. Hope you can help me here. Thanks in advance.
Estimations.update(userstory._id, {
$addToSet: {
estimations: [
{name: Meteor.user().username, estimation: this.value}
]
}
});
From the mongo docs
The $addToSet operator adds a value to an array unless the value is
already present, in which case $addToSet does nothing to that array.
Since your array elements are objects the value is the entire object, not just the username key. This means a single user can create multiple name, estimation pairs as long as the estimation value is different.
What you can do is remove any value for the user first, then reinsert:
var username = Meteor.user().username;
Estimations.update({ userstory._id },
{ $pull: { estimations: { name: username }}}); // if it doesn't exist this will no-op
Estimations.update({userstory._id },
{ $push: { estimations: { name: username, estimation: this.value }}});
By way of commentary, you've got a collection called Estimations that contains an array called estimations that contains objects with keys estimation. This might confuse future developers on the project ;) Also if your Estimations collection is 1:1 with UserStorys then perhaps the array could just be a key inside the UserStory document?

Should I always add new objects to list of objects via $push()?

I'm creating a data structure for Firebase and AngularFire consisting of Users, Posts, and Comments. I was under the impression that the key/id for users would be the username, and that the key/id for comments and posts would be the auto-generated firebase key.
I've been working my through the angularfire documentation and am confused about the auto-generated keys (name()) that is added to an object when the $push() method is used.
Looking at some examples on the firebase website I see that an example of a Users object does not have the auto-generated key -- the key for an individual user is the username -- but at the same time a key is added whenever you add an object to the array via $push
My question is:
1) Should I always be using the firebase auto-generated keys? And if not, then how do I add a new user since $push() automatically creates the key, and $set() would reset all of my users?
2) What is the relationship between $id and name()?
Example Data
From https://www.firebase.com/docs/web/guide/saving-data.html
The docs show the following Users object:
{
"users": {
"alanisawesome": {
"date_of_birth": "June 23, 1912",
"full_name": "Alan Turing"
},
"gracehop": {
"date_of_birth": "December 9, 1906",
"full_name": "Grace Hopper"
}
}
}
How would I add more users without resetting my current users with $set() or adding the angularfire id with push()?
And then a Posts object with the generated id:
{
"posts": {
"-JRHTHaIs-jNPLXOQivY": {
"author": "gracehop",
"title": "Announcing COBOL, a New Programming Language"
},
"-JRHTHaKuITFIhnj02kE": {
"author": "alanisawesome",
"title": "The Turing Machine"
}
}
}
Thanks very much.
The short answer: you probably don't want to use push to store your users.
If you're getting your key from another source, like a uid from Simple Login, you will almost certainly want to use the uid to organize your users and their data in your firebase.
This is because, your users' ongoing sessions always provide you with that same uid which you can use to look up their user data and their stuff.
And you can safely use set in this case without resetting all of your users if you set based on that known user id.
But what I think you're getting at is, So in general, when do you set vs push?
A typical blog might look something like this in Firebase:
{
'users' : {
// uid from Simple Login, that you used with set()
'google-1234' : {
'displayName' : 'Jane Smith',
...
}
, ...
},
'posts' : {
// a blog post ID you pick and use for set()
'blog-post-id-i-use-in-the-url' : {
'title' : 'Blog Post Title',
'contents' : 'Four score and seven...'
}, ...
}
'postComments' {
'blog-post-id-i-use-in-the-url' : {
// Firebase generated ID done with push()
'_fe31ca1' : {
// uid from simple login (assuming comments require auth)
'commenterUserId': 'google-5678',
'commentBody': 'cats back for everyone!'
} ... other comments ...
}
}
}
In this example we use set when inserting new users and posts because we get a good unique ID from another source. These IDs are good because they allow us to easily recall the content later based on that ID.
We use push for comments, though. We don't have a good ID from another source, and order does matter, so we let Firebase generate a key for us. This works out OK because most of the time we're working with comments relative to an entry, so we can just grab them all as needed.
Following what mimmming said, I found a solution to this.
Have your add user function take an id as a parameter. this will be the authData.uid for the user you want to save.
Then append that id to the firebase link to make a new user using set.
Any other user you add using set will not wipe this since it is an entire new branch of your database under users. No firebase unique id too.
$scope.addUSer = function(id){
//pass the id in, andd append it to the end of your url link
var usersRef = new Firebase("https//<your fire base>.firebaseio.com/Users/"+id);
usersRef.set($scope.newUserData);
};

Resources