I was recently creating a bot.
Right now I am trying to find out if someone could help me with my -verify (mc uuid) command. It would check a URL to see if their uuid is in the fetched object. So, if I did -verify (uuid) and it is found, it would give me a role.
Code:
const Discord = require('discord.js');
const fetch = require('cross-fetch');
module.exports = {
name: `verify`,
async execute(message, args) {
fetch("https://api.hypixel.net/guild?key=29083d9d-58cf-4a71-95be-d24f31c018b7&name=Metanoia")
.then(result => result.json())
.then(({ guild }) => {
const role = message.guild.roles.cache.get('808886143416270899');
const uuid = args[0];
if(uuid) {
//
}
})
}
}
You receive an object from the API URL. Its guild property has a members array. The array contains objects with uuids. If you want to find one with the provided uuid, you can use the .find() method that returns the value of the first element in the array that satisfies the provided testing function.
In your testing function you can test if the object's uuid is the same as the member provided uuid:
const foundElement = array.find((el) => el.uuid === uuid);
In your code it looks like this:
const fetch = require('cross-fetch');
module.exports = {
name: `verify`,
async execute(message, args) {
const role = message.guild.roles.cache.get('808886143416270899');
const uuid = args[0];
if (!uuid) {
return message.channel.send(`uuid is not provided`);
}
try {
const result = await fetch('https://api.hypixel.net/guild?key=29083d9d-58cf-4a71-95be-d24f31c018b7&name=Metanoia');
const { guild } = await result.json();
const member = guild.members.find((member) => member.uuid === uuid);
if (!member) {
return message.channel.send(`No member found with uuid ${uuid}`);
}
// you can do anything with the found member
message.channel.send('```' + JSON.stringify(member, null, 2) + '```');
} catch (error) {
console.log(error);
message.channel.send('Oops, there was an error');
}
}
}
If your execute method is already an async function, you can use async/await to fetch the results. I used that in my code above.
Related
I have a Firebase Realtime database query written using Firebase version 8 that I'm looking to migrate over to the v9 SDK.
export const getSingleDataWithQuery = async ({ key, email, criteria }) => {
if (!criteria) return;
const snapshot = await realTimeDb
.ref()
.child(key)
.orderByChild(query)
.equalTo(criteria)
.get();
const val = snapshot.val();
if (val) {
const keys = Object.keys(val);
return val[keys[0]];
}
return null;
};
In this example:
key would be the 'users' collection
the email field is looking for users by their email
and the criteria is the user's actual email (jane.doe#gmail.com)
Using Firebase's Read data once and Sorting data documentation I managed to narrow it down to perhaps being this, but I'm not sure if it's correct:
export const getSingleDataWithQuery = async ({ key, query, criteria }) => {
if (!criteria) return;
const dbRef = query(ref(realTimeDb, key), orderByChild(email), equalTo(criteria));
get(dbRef).then(snapshot => {
if (snapshot.exists()) {
const val = snapshot.val();
if (val) {
const keys = Object.keys(val);
return val[keys[0]];
}
}
});
return null;
};
Aside from the fact that you may have swapped query and email in the fragments, the only difference is in the way you handle the asynchronous database call and that likely explains the difference. Since you use then in the second snippet, the function doesn't actually return a promise and so calling it with await it in the caller won't have any effect.
To make those the same again, use await in the second snippet too, instead of then:
export const getSingleDataWithQuery = async ({ key, query, criteria }) => {
if (!criteria) return;
const dbRef = query(ref(realTimeDb, key), orderByChild(email), equalTo(criteria));
const snapshot = await get(dbRef); // 👈
if (snapshot.exists()) {
const val = snapshot.val();
if (val) {
const keys = Object.keys(val);
return val[keys[0]];
}
}
return null;
};
I am trying to iterate over an array of comments and need to grab the commenter's uid for each comment. I am a beginner to JavaScript and need a little bit of help with the following use case:
I need to grab the uid for each comment and then run a .getUser() method which will return the user's email address that is associated with the user's uid. Since .getUser() returns a promise (method reference link), I need to await somewhere in this loop. How to do so? Is this even a good approach?
(Note: My end goal is to eventually attach the email addresses to a to property in a msg object where I will then send out email notifications.)
Example data for comments:
[
{
id: 1,
uid: 'RGaBbiui'
},
{
id: 2,
uid: 'ladfasdflal'
},
{
id: 3,
uid: 'RGaBbiui'
},
{
id: 4,
uid: 'RGaBbiui'
},
{
id: 5,
uid: 'ladfasdflal'
},
{
id: 6,
uid: 'ladfasdflal'
}
]
Cloud function example:
export const sendCommentNotification = functions.firestore
.document('users/{uid}/posts/{postId}/comments/{commentId}')
.onCreate(async (snapshot, context) => {
try {
const commentsQuery = await admin
.firestore()
.collection(
`users/${context.params.uid}/posts/${context.params.postId}/comments`
)
.get()
const commentsArr = []
commentsQuery.forEach((documentSnapshot) =>
commentsArr.push(documentSnapshot.data())
)
const commentsArrUids = new Set(commentsArr.map((c) => c.uid))
console.log(commentsArrUids)
const emailAddresses = []
commentsArrUids.forEach((uid) =>
emailAddresses.push(admin.auth().getUser(uid)) // how to use await here?
)
...
const msg = {
to: //TO DO..put email addresses here..
...
You cannot use await in a forEach loop. You could use await in a for-loop but they won't run simultaneously as in Promise.all().
You can just await all the promises at once using Promise.all():
Returned values will be in order of the Promises passed, regardless of completion order.
const emailAddresses = []
commentsArrUids.forEach((uid) => {
emailAddresses.push(admin.auth().getUser(uid))
})
const data = await Promise.all(emailAddresses)
Data will be an array of UserRecord.
Then you can use the .map() method to get an array of all the emails.
const emails = data.map((user) => user.email)
The code can be written like this to make it easier:
const commentsDocs = await admin.firestore().collection(`users/${context.params.uid}/posts/${context.params.postId}/comments`).get()
const userIds = commentsDocs.docs.map(comment => comment.userId)
const usersReq = userIds.map(u => admin.auth().getUser(u.uid))
const emails = (await Promise.all(usersReq))).map((user) => user.email)
Use for loop instead.
for (let i = 0; i < commentsArrUids.length; i++) {
let user = await new Promise((resolve, reject) => {
admin.auth().getUser(commentsArrUids[i]).then((user) => {
resolve(user);
});
};
emailAddresses.push(user);
}
I will replace forEach with for of and the promises is in series. Also, I rewrite some of your codes as they are redundant.
export const sendCommentNotification = functions.firestore
.document("users/{uid}/posts/{postId}/comments/{commentId}")
.onCreate(async (snapshot, context) => {
try {
const comments = await admin
.firestore()
.collection(
`users/${context.params.uid}/posts/${context.params.postId}/comments`
)
.get();
const uids = new Set();
for (const comment of comments) {
uids.add(comment.data().uid);
}
const emailAddresses = [];
for (const uid of uids) {
const res = await admin.auth().getUser(uid);
emailAddresses.push(res);
}
} catch (err) {
console.log(err);
}
});
I need to use one of the basic TypeORMCrudService methods, for example, createOne, I got the body as dto(I guess) but the second parameter is the CrudRequest. Should I redefine its methods or what?
if I understand what you mean:
if you use repositoryT it's so easy to do it:
your controller should be like this:
#Get(':id')
async findOne(#Param('id', ParseIdPipe) id: number) {
return await this.unitService.findOne(id);
}
your service should be like this:
async findOne(id: number, ...relations: string[]): Promise<Entity> {
const record = await this.repository.findOne(id, { relations });
this.checkNotFound(record);
return record;
}
you can use :
const record = await this.repository.findOne(id, { relations });
const record = await this.repository.create({dto});
const record = await this.repository.find();
const record = await this.repository.delete(id);
const record = await this.repository.update(id, {dto});
So my goal is to get the uuid from a Minecraft username via the Mojang api and then run it through the Hypixel Skyblock api. My problem is that I cant use the variable ${jsonsbid.id} inside JSON.stringify. I'm quite new to coding and I cant seem to get it working.
I'm using the Discord.js api to send out the JSON result as message.
import { key } from './config.json';
client.on('message', message => {
const prefix = '!skyblock ';
const skyblock = message.content.slice(prefix.length);
const fetch = require('node-fetch');
if (!message.content.startsWith(prefix) || message.author.bot) return; {
try {
fetch(`https://api.mojang.com/users/profiles/minecraft/${skyblock}`)
.then(response => response.json())
.then(jsonsbid => fetch(`https://api.hypixel.net/Skyblock/profiles?uuid=${jsonsbid.id}&key=${key}`))
.then(responsesb => responsesb.json())
.then(jsonsb => message.channel.send(`Coins: ${JSON.stringify(jsonsb.profiles[0].members.${jsonsbid.id}.coins_purse)}`)) //this is the line i need to get working
} catch (err) {
message.channel.send('A error occured')
}
};
Well I hope you can help me so I can learn more about coding and js.
You could create a cache called jsonsbidCache in your bot that stores the jsonsbid JSON result by the key skyblock. You can then later access it in the final .then call.
If you only need to reference jsonsbid.id, then you could modify this to only cache said id value.
import { key } from './config.json';
const mojangApiUrl = 'https://api.mojang.com';
const skyblockApiUrl = 'https://api.hypixel.net/Skyblock';
const displayCoins = (member) => {
return `Coins: ${JSON.stringify(member.coins_purse)}`;
};
const jsonsbidCache = new Map(); // Cache
client.on('message', message => {
const prefix = '!skyblock ';
const skyblock = message.content.slice(prefix.length);
const fetch = require('node-fetch');
if (!message.content.startsWith(prefix) || message.author.bot) {
return;
}
try {
fetch(`${mojangApiUrl}/users/profiles/minecraft/${skyblock}`)
.then(response => response.json())
.then(jsonsbid => {
jsonsbidCache.set(skyblock, jsonsbid); // Cache it
return fetch(`${skyblockApiUrl}/profiles?uuid=${jsonsbid.id}&key=${key}`)
})
.then(responsesb => responsesb.json())
.then(jsonsb => {
const memberId = jsonsbidCache.get(skyblock).id;
const member = jsonsb.profiles[0].members[memberId];
message.channel.send(displayCoins(member))
})
} catch (err) {
message.channel.send('A error occured');
}
}
Here is how my database is structured:
challenges table &
users table
Here is the error I'm getting: error image
I want to use the "created_by" field which is also a document id for the users table, where I want to retrieve both the display name and the photo URL.
I'm not all the way sure how promises work and I have a feeling that is why I'm struggling, but the code I have thus far is below:
Data Retrieval:
UsersDao.getUserData(ChallengesDao.getChallenges().then(result => {return result['author'][0]})).then(result => {console.log(result)})
Challenges DAO:
export default class ChallengesDao {
static async getChallenges() {
const db = require('firebase').firestore();
// const challenges = db.collection('challenges').limit(number_of_challenges)
// challenges.get().then(())
const snapshot = await db.collection('challenges').get()
const names = snapshot.docs.map(doc => doc.data().name)
const createdBy = snapshot.docs.map(doc => doc.data().created_by)
const highScores = snapshot.docs.map(doc => doc.data().high_score.score)
return {challengeName: names, author: createdBy, score: highScores}
}
Users DAO:
const db = require('firebase').firestore();
export default class UsersDao {
static async getUserData(uid: string) {
let userData = {};
try {
const doc = await db
.collection('users')
.doc(uid)
.get();
if (doc.exists) {
userData = doc.data();
} else {
console.log('User document not found!');
}
} catch (err) {}
return userData;
}
}
You're getting close. All that's left to do is to call getUserData for each UID you get back from getChallenges.
Combining these two would look something like this:
let challenges = await getChallenges();
let users = await Promise.all(challenges.author.map((uid) => getUserData(uid));
console.log(challenges.challengeName, users);
The new thing here is Promise.all(), which combines a number of asynchronous calls and returns a promise that completes when all of them complete.
Your code looks a bit odd to me at first, because of the way you return the data from getChallenges. Instead of returning three arrays with simple values, I'd recommend returning a single array where each object has three values:
static async getChallenges() {
const db = require('firebase').firestore();
const snapshot = await db.collection('challenges').get();
const challenges = snapshot.docs.map(doc => { name: doc.data().name, author: doc.data().created_by, score: doc.data().high_score.score });
return challenges;
}
If you then want to add the user name to each object in this array, in addition to the UID that's already there, you could do:
let challenges = await getChallenges();
await Promise.all(challenges.forEach(async(challenge) => {
challenge.user = await getUserData(challenge.author);
});
console.log(challenges);