So i working with firebase auth and database in order to set new user to data base, if set successful i want to set claims for that user.
So it means i have a promise within a promise:
function setUser(user){
// no need for the database code before this, but userRef is set properly
return userRef.set(user)
.then(succ => {
return firebase.firebase.auth().setCustomUserClaims(user.key, {admin: true})
.then(() => {
console.log("setting claims")
return true;
});
})
.catch(err => {
return err
})
}
calling function:
app.post("/register_user",jsonParser,async (req, res) => {
var user = req.body.user;
let result = await fireBase.setUser(user);
res.send(result);
})
What happens is that i get the set on the database but claims are not set nor i can i see the log. I know its a js question and not firebase one. I tried many different ways (with await) but non worked.
firebase.firebase does not seem correct. You need to be using the admin object which can be initialised using const admin = require('firebase-admin'); This is not part of the firebase db sdk, but the admin one. You can also use the userRef.uid as that gives you the id of the document of the user, if that is what you want, else use your user.key
return admin.auth().setCustomUserClaims(userRef.uid, {
admin: true
}).then(() => {
//on success
});
Related
After creating a node.js, express, mongoDb REST api for a social media web app with almost all basic social media actions (login, signup, add a post, delete a post, delete account, follow users ...),
I'm currently facing a problem, where after implementing bookmarking a post feature, I'm unable to come up with a solution to remove a bookmarked post from another user's bookmarked posts page, after the first user deletes his account. I'll provide my code below:
(P. S. Bookmarks is an array inside User model. I'd also like to mention the steps that I initially intended for the task:
Get current user by ID
Then get all posts created by this user, which returns an array, so I mapped it to get each Posts id
After that I fetched all users accross the app, and initially intended to compare the posts that live inside bookmarks array inside each user to the posts that the current user have created. Then I'd pull these same posts out of the bookmarks array from each of these users.
--> I think the logic that I've analyzed is maintainable, but it's just not working with me. This is the Code below:
export const deleteUser = async (req, res) => {
try {
let user = await User.findById(req.params.userId)
const userPosts = await Post.find({ creatorId: user._id })
const allUsers = await User.find()
const myPostsIds = userPosts.map((post) => post._id.toString())
//This is the section I've implemented for my task, but obviously
something isn't right
await Promise.all(
myPostsIds.forEach((id) =>
allUsers.map((user) => {
user.bookmarks.includes(id) &&
user.updateOne({ $pull: { bookmarks: id } })
})
)
)
await Post.deleteMany({ creatorId: user._id })
await user.remove()
res.status(200).json({
message: "Account has been deleted successfully!",
})
} catch (err) {
errorHandler(res, err)
}
}
As mentioned in my comments, the value you pass to Promise.all is no array of Promise/array of async functions.
The 2nd error is inside the (currently) forEach function at the .map() you are not returning anything in the map-call.
So this should do it:
// first convert all ids to a promise
await Promise.all(myPostsIds.map(id => new Promise(resolve => {
// during this, await every test and update
return Promise.all(allUsers.map(user => new Promise(resolve => {
// if it includes the id, cast the update and then resolve
if (user.bookmarks.includes(id)) {
// if found, resolve the promise for this user after the change
user.updateOne({ $pull: { bookmarks: id } }).then(resolve)
} else {
// resolve directly if not found.
resolve()
}
// when all users are done for this id, resolve the Promise for the given id
}))).then(resolve)
})))
An easier to read and shorter method would be:
for (const id of myPostIds) {
for (const user of allUsers) {
if (user.bookmarks && user.bookmarks.includes(id)) {
await user.updateOne({ $pull: { bookmarks: id } });
}
}
}
I was developing an app which I like implements Firebase as Authenticating system.
My problem comes when I try to set up the Authentication with Google provider when I try to modify the colletion of firestore where the users are saved. My code is the following:
export const loginWithGoogle = () => {
const navigation = useNavigation();
useEffect(() => {
setTimeout(() => {
navigation.navigate('/RegisterScreen');
}, 10000);
}, []);
return () => {
return firebase
.auth()
.signInWithPopup(Providers.google)
.then(async result => {
//console.log(result.credential.accessToken);
const user = result.user;
console.log(user);
//This 2 lines below doesn't work to get the colletion.
db.('users').setItem('userid', user!.uid);
collection.(db,'users').setItem('photoURL', user!.photoURL);
//TODO if userid exists IN USERS db then use update IF NULL use set
await db.collection('users').doc(user!.uid).update({
// id: user.uid,
name: user!.displayName,
email: user!.email,
phone: user!.phoneNumber,
photoURL: user!.photoURL,
});
})
.then(() => {
navigation.navigate('ProtectedScreen');
})
.catch(err => {
console.log(err);
});
};
};
So I guess that my error comes from unknowledge of how to manage data saved on firestore.
If you can help take thanks in advance !
There are some thing we need to clear here:
You can just merge the data. There is no need to read/get it from Firestore to check if it is there and save it onyl if it's not. You will be charged for reads and writes. In the end it's cheaper to always just write without checking if something exists.
Also this code here:
db.('users').setItem('userid', user!.uid);
collection.(db,'users').setItem('photoURL', user!.photoURL);
especially with the db.( and collection.( doens't look good. Even if it is it's not for getting data but for saving it.
Could you pls clarify witch Firebase SDK you use: version 8 or 9. Also pls check a little bit the docs here.
I am using Firebase authentication to store users. I have two types of users: Manager and Employee. I am storing the manager's UID in Firestore employee along with the employee's UID. The structure is shown below.
Firestore structure
Company
|
> Document's ID
|
> mng_uid: Manager's UID
> emp_uid: Employee's UID
Now I want to perform a query like "Retrieve employees' info which is under the specific manager." To do that I tried to run the below code.
module.exports = {
get_users: async (mng_uid, emp_uid) => {
return await db.collection("Company").where("manager_uid", "==", mng_uid).get().then(snaps => {
if (!snaps.empty) {
let resp = {};
let i = 0;
snaps.forEach(async (snap) => {
resp[i] = await admin.auth().getUser(emp_uid).then(userRecord => {
return userRecord;
}).catch(err => {
return err;
});
i++;
});
return resp;
}
else return "Oops! Not found.";
}).catch(() => {
return "Error in retrieving employees.";
});
}
}
Above code returns {}. I tried to debug by returning data from specific lines. I got to know that the issue is in retrieving the user's info using firebase auth function which I used in forEach loop. But it is not returning any error.
Thank you.
There are several points to be corrected in your code:
You use async/await with then() which is not recommended. Only use one of these approaches.
If I understand correctly your goal ("Retrieve employees' info which is under the specific manager"), you do not need to pass a emp_uid parameter to your function, but for each snap you need to read the value of the emp_uid field with snap.data().emp_uid
Finally, you need to use Promise.all() to execute all the asynchronous getUser() method calls in parallel.
So the following should do the trick:
module.exports = {
get_users: async (mng_uid) => {
try {
const snaps = await db
.collection('Company')
.where('manager_uid', '==', mng_uid)
.get();
if (!snaps.empty) {
const promises = [];
snaps.forEach(snap => {
promises.push(admin.auth().getUser(snap.data().emp_uid));
});
return Promise.all(promises); //This will return an Array of UserRecords
} else return 'Oops! Not found.';
} catch (error) {
//...
}
},
};
I have a database triggered function, that triggers when a team administrator adds new members to his team. The function is supposed to create authentication in Firebase and an object, where the new user can store his personal settings.
My problem is, that when a lot of members are added simultaneously via an import feature, my function doesn't always complete. Since they seem to be triggered alright when I look at the log, I suspect my implementation of chained promises to be the error cause. Here is a copy of the code. Please help me correct the errors.
// When a team adds a new member, we should also create authentication and a record for his user data...
exports.createNewUserAndAuthOnNewMember = functions
.database
.ref('/Members/{team}/{memberId}/createNewUser')
.onCreate(event => {
const memberRef = admin.database().ref('/Members/'+event.params.team+'/'+event.params.memberId);
memberRef.once('value')
.then((memberSnap) => {
const memberEmail = memberSnap.child('email').val();
const preferredLanguage = memberSnap.child('preferredLanguage').val();
// Creating authentication for new system user...
//since we want to update the /user object later on even if the authentication creation fails (because user already exists), this promise is inside the top promise chain
admin.auth().createUser({
uid: event.params.memberId,
email: memberEmail,
emailVerified: false,
password: '[random password generated]',
disabled: false
})
.then(function(userRecord) {
console.log("Successfully created new user:", userRecord.uid);
return preferredLanguage;
})
.catch(function(error) {
console.log("Error creating new user:", error);
return preferredLanguage;
});
})
.then(preferredLanguage => {
// Creating the personal user object in the database
admin.database().ref('/users/'+event.params.memberId).update({'team': event.params.team, 'preferredLanguage': preferredLanguage});
})
.then(() => {
//we did the job and should remove the trigger from the member object in the database
memberRef.child('createNewUser').remove();
})
.then(() => {
console.log('Created /users/'+event.params.memberId);
return true;
});
});
This should work:
exports.createNewUserAndAuthOnNewMember = functions
.database
.ref('/Members/{team}/{memberId}/createNewUser')
.onCreate(event => {
let preferredLanguage;
const memberRef = admin.database().ref('/Members/' + event.params.team + '/' + event.params.memberId);
return memberRef.once('value')
.then((memberSnap) => {
const memberEmail = memberSnap.child('email').val();
preferredLanguage = memberSnap.child('preferredLanguage').val();
// Creating authentication for new system user...
//since we want to update the /user object later on even if the authentication creation fails (because user already exists), this promise is inside the top promise chain
return admin.auth().createUser({
uid: event.params.memberId,
email: memberEmail,
emailVerified: false,
password: '[random password generated]',
disabled: false
})
})
.then(() => {
// Creating the personal user object in the database
return admin.database().ref('/users/' + event.params.memberId).update({'team': event.params.team, 'preferredLanguage': preferredLanguage});
})
.then(() => {
//we did the job and should remove the trigger from the member object in the database
return memberRef.child('createNewUser').remove();
})
.catch(error => {
console.log(error);
//...
});
});
You have to return the promise in each then() when chaining them, and you only need one catch at the end of the chain.
In addition, note that you are using the "old" syntax for Cloud Functions. Since version 1.0.+ there is a new syntax, see https://firebase.google.com/docs/functions/beta-v1-diff
I need to utilize a key stored in my firebase using the user's firebase user id.
The steps to my function are the following:
1) Get the Firebase User ID after authentication
2) Using the Firebase User ID, pull the stored API Key value (which I saved in a node: app/{Firebase User Id})
3) Using the stored API Key value, run my last function
After doing some research, I've come to the conclusion that I should use Javascript Promise Chaining to the below code, which I'm having a difficult time doing
firebase.initializeApp({databaseURL: "{}"});
var dbRef = firebase.database();
function pull_api_key_from_firebase_after_auth(func){
firebase.auth().onAuthStateChanged((user) => {
if (user) {
var app_ref = dbRef.ref('app').child(user.uid);
app_ref.on("child_added", function(snap) {
dictionary_object = snap.val()
api_key = dictionary_object.api_key
func(api_key)
})
}
});
}
function final_function(api_key){
console.log('processing final function')
}
pull_api_key_from_firebase_after_auth(final_function)
Alternatively, I'd like to make api_key a global variable as such:
function pull_api_key_from_firebase_after_auth(func){
firebase.auth().onAuthStateChanged((user) => {
if (user) {
var app_ref = dbRef.ref('app').child(user.uid);
app_ref.on("child_added", function(snap) {
dictionary_object = snap.val()
api_key = dictionary_object.api_key
localStorage.setItem('api_key',api_key)
})
}
});
}
api_key = localStorage.getItem('api_key')
final_function(api_key)
However I cant figure out how to make final_function as well as my other functions wait until api_key is defined
You must use firebase.auth().onAuthStateChanged to get the uid bcs .auth.currentUser.uid will NOT be available on page load. It shows up a microsecond after (it's asynchronous).
To do what you want simply build out a promise function and call it within .onAuthStateChanged and .then do your other function. You custom promise might look like:
function fetchUserData(){
return new Promise(function(resolve, reject){
var db = firebase.firestore(); // OR realtime db
db.collection("users").get().then(function(snap) {
resolve (snap);
}).catch(function(error) {
reject (error);
});
});
}
Within .onAuthStateChange just do something like:
fetchUserData().then((snap) => {
// do your thing
})
.catch((error) => {
console.log(error);
});