AngularFirebase 2 check if user exists then add to database - javascript

I want to add a new user to firebase realtime Database, i have managed to query the databse to find if the email input already exists
onSubmit(form: NgForm){
var user = this._visitorService.getIndividualVisitor(form.value.email);
user.valueChanges().subscribe(list=>{
console.log(list);
if(list.length ===0 ){
console.log('email doesnt exist, creating new user');
this._visitorService.addVisitor(form.value)
} else{
console.log('email existst');
this._visitorService.updateVisitor(form.value)
}
})
}
getIndividualVisitor(email:string){
this.list = this.firebase.list('visitors', ref => ref.orderByChild('email').equalTo(email));
return this.list;
}
The problem i have is that the user.valueChanges() is called every time the database is updated
this means that every time I add a new user the update user function is also called, what would be the correct way to do this.
I am using "angularfire2": "^5.0.0-rc.4", and "firebase": "4.8.0",

I think using Firebase Auth together with Cloud Functions would solve your issue.
Use Firebase Authentication to create a user.
Then deploy a Cloud Function which listens on the user OnCreate event.
exports.newUser = functions.auth.user().onCreate(event => {
// Add something to your database here.
});
Documentation for Cloud Function Triggers can be found here: Firebase Authentication Triggers

Related

query to firestore to check collection and document

i am a little bit new to firebase / firestore. I am using the stripe api.
Once the user hits start trial on the prebuilt stripe checkout page, then it should go to firestore and create a new collection called subscriptions with all the users information. It seems to be doing this, however, I created a page called successPage, and it basically checks to make sure that it created it.
please find the code below:
const successPage = props => {
firebase.auth().onAuthStateChanged((user) => {
if(user) {
console.log("calling success page : " + user.uid)
//checking if user is paying for subscription
firestore.collection('customers').doc(user.uid).collection('subscriptions')
.where('status', 'in', ['trialing', 'active']).get()
.then(activeSubscriptions => {
// if this is true, the user has no active subscription.
if (activeSubscriptions.empty === true) {
console.log(user.uid)
firestore.collection('customers').doc(user.uid)
.get().then(
doc => {
if (doc.exists) {
firestore.collection('customers').doc(user.uid).collection('subscriptions').get().
then(sub => {
if (sub.docs.length > 0) {
var activityStatus = "canceled"
createCheckoutSession(activityStatus)
console.log('subcollection exists');
} else {
alert("Your account has been created, but your payment details we're not successfully created. You will now be redirected to the checkout page")
createCheckoutSession()
console.log(user.uid)
console.log("does not exist!")
}
});
}
});
} else if (activeSubscriptions.size > 1){
alert("you have more then one active subscription. please manage your subscriptions and cancel one of your subscriptions to access the application")
} else {
firestore.collection("profiledata").doc(user.uid).update({
accountStatus: "active"
}).then (() => {
firestore
.collection("roger#x.ca")
.add({
to: user.email,
message: {
},
})
.then(() => console.log("email out for delivery!"));
props.history.push('/clients')
})
}
});
}
})
return (
<input type="hidden"></input>
)
}
it checks the subscriptions collection where status = to either trialing, or active, and then it checks everything inside subscriptions to see what is going on, but it for some reason it keeps redirecting to the stripe page (createCheckoutSession) even though the subscriptions collection has been created. is this a timing issue?
Stripe triggers a Webhook to your server/cloud functions when a new subscription is created and after that the document is created in Firestore. This process might take some time and meanwhile your user may have been redirected to the success page. If the document has not been created yet then you won't be able to show the transaction status.
Here's a workaround that you can do:
While creating a Stripe Checkout session on your server, you can actually create the subscriptions document but set a field called "stripe_response" to false and also add the new subscription document ID as a query parameter in the stripe success_url. So you url maybe looks something like: https://domain.ext/paymentSuccess?id=<that_document_id>,
Now when the user is on the success page, look for that specific subscription document with the ID mentioned in the query parameter. If the "stripe_response" is still false, then maybe the webhook has not done it's job yet. Just retry the request after 5 seconds and then show the status to user. Make sure you set the stripe_response to true in the webhook.
To simply step 2, you can just attach a realtime listener on the document so when the status is updated you get the response asap and don't need to rely on polling.
Coming to the 'keeps redirecting' part, can you please specify what the exact redirect situation? Where is it redirecting and all that?
It's definitely a race condition but if you follow the steps above it should take care of it. Please let me know if you need more assistance fixing this issue.

What is preferred way to show DOM elements conditioned on firebase authentication

I'm trying to build a small web-page where sign-in is controlled by Firebase Google Auth and is popped up with profile page. What is the secured and preferred way to show the profile page?
Currently I am using onAuthStateChanged to manipulate particular div which holds profile data when user is signed-in. If the user is not logged in I am using removeChild() method to remove that div from DOM and when logged in appendChild() adds back the div.
Supposing you're using firebase's native firebase.auth().onAuthStateChanged function
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});
As well as firebase.auth().currentUser to check if the user is currently logged in or not.
In that case, it's perfectly fine to use removeChild and appendChild and they do not hold any security threats, as if a user is not logged, after a page refresh all of the information will vanish.
Here's a small firebase application that shows that when the connection to the firebase is closed and removeChild is used, appendChild stops working as firebase is disconnected, thus proving the point that it's safe to use.
https://jsfiddle.net/vh9xay6e/
Note that in this example I'm not testing any authentification, just the use of firebase with removeChild and appendChild.
You can see that once the connection to Firebase is over, nothing on the frontend side can happen to change that.
Using onAuthStateChanged method we can act upon state change (sign in or Sign out)
As an example :
firebase.auth().onAuthStateChanged(user=>{
if(user){
document.getElementById("id").classList.remove('hide')
//this will populate your class which associate with above id.
} else{
document.getElementById("id_of_your_div").classList.add('hide')
}
})
I think it's okay to use removeChild and appendChild method based on firebase auth state changes in your application.
try to wire around your code by:
var userCurrent = firebase.auth().currentUser; in a function.
NOTE: Make sure you need to be sure first you signed in (as its an async operation), followed by the update user data as:
var authenticationRef = firebase.auth();
authenticationRef.onAuthStateChanged(function(user) {
if (user) {
console.log('onAuthStateChanged : '+user.displayName);
_updateUser();
} else {
console.log('Not login');
}
});
fucntion _updateUser(){
var userCurrent = firebase.auth().currentUser;
userCurrent.updateProfile({
displayName: "Karthik.S",
}).then(function() {
var displayName = userCurrent.displayName;
}, function(error) {
});
}

Firebase Ondisconnect

I am new to firebase backend. I want to implement firebase onDisconnect functionality on backend. I have 100 or so authorised firebase users and each one will have a unique id generated by firebase. How can I know which user is not connected right now. I have seen examples and everyone is telling this code;
admin.database().ref().child(".info/connected").on("value", function (snap) {
connected = snap.val() === true;
if (connected) {
} else {
}
});
How can I get that unique firebase id associated with each user using above code or how i can know which is disconnected?
First of all while user open application at that time set one entry with their current state like
users :
{
"784823468sugfsdjf":"online",
"3223232fdfdfdffdf":"online",
"y32y32y32y32y3y23":"online",
"3b2jg434jg343g4h3":"offline"
}
Now update all user's status using
admin.database().ref().child(".info/connected").on("value", function (snap) {
connected = snap.val() === true;
if (connected) {
updated(uid,"Online");
} else {
updated(uid,"offline");
}
});
By this way you will get all user's current state.

Event triggered when changing a user Firebase Authentication

Detect events from a user Firebase Authentication
In my application developed in Angular along with Node.js and Firebase I need to detect events occurring in users. As inclusion, change and exclusion.
Is there a way to detect when a user is deleted, changed, or inserted through a function created in Cloud Functions?
I know that you can detect database events with a function created in Cloud Functions. I would like to detect when a user is changed, deleted or entered when the operation is done through Firebase Console > Project > Authentication.
Something in that sense:
exports.userChanged = functions.user
.onCreate((snapshot, context) => {})
OnDelete()
OnCreate()
OnChange()
What is the best way to do this?
There is onCreate and onDelete, you can read it from the docs.
For the update case, you should rely on the RTD. Actually, you could rely completely on the RTD.
//Create a user on the rtd
functions.auth.user().onCreate((user) => {
return usersRef.child(user.uid).set(user);
});
//Update the user by listening to a change on the RTD
functions.database.ref('/users/{uid}')
.onWrite((change, context) => {
//If you needed it you can update the user
admin.auth().updateUser(uid, {
});
//if some condition, then delete it
admin.auth().deleteUser(uid)
//do more
});
Using the update user option you can even disable the account, take a look at this other answer
You can use the admin sdk inside of Functions directly, this is the doc

#ionic change the data key in firebase

I'm trying to update/add data on firebase. I used the Facebook login and I want to use the UserID as a key for the new data aded.
(check pict below)
The userID that I want to use it:
I want to replace that key with the userID:
fblogin(){
this.facebook.login(['email'])
.then(res=> {
const fc = firebase.auth.FacebookAuthProvider.credential(res.authResponse.accessToken);
firebase.auth().signInWithCredential(fc)
.then(fs => {
this.facebook.api('me?fields=id,name,email,first_name,picture.width(720).height(720).as(picture_large)', []).then(profile => {
this.newuser = {name: profile['first_name'] ,email: profile['email'],picture: profile['picture_large']['data']['url'],phone:''}
this.navCtrl.push(HomePage);
console.log(fs.uid);
this.db.list('/users/'+ fs.uid).update(this.newuser);
});
I got this error in compilation:
supplied parameters do not matchany signature of call target
In this line: this.db.list('/users/'+ fs.uid).update(this.newuser);
Any help?
The FB error looks correct. You cant update on the uid as the user has been saved with a unique FB id
You do not show the code that created the users record in the database, but what i think you want to do is set and object when you first save the users record. However this could be an issue because the user could be saved before the return of the uid. I cant tell with your code snippet. Regardless, I will write the code that i think will work if the users/ record is created at the time that of registration.
The service
async signupUser(email: string, password: string) {
try {
const result = await this.afA.auth.createUserWithEmailAndPassword(email, password);
return result;
} catch (err) {
console.log('error', err);
}
}
So this initially creates a user without facebook, The key here is that the users FB uid was created and is held in the returned result
The component
this.authData.signupUser(email,password).then(userData => {
console.log(userData) // <- this is result
}
Then we create a record in FB with the uid returned
this.db.object(`users/${userData.uid}/`).set(data);
.set(data) is whatever data you want to save in the users/uid namespace.
So basically you need to create that user table with its uid namespace when the user first registers. Then you can update the user with the uid returned from the facebook fs.uid
With your current code you could find the user based on the email ( because the email should be unique to all users) and then update ...
with lodash is it just
let foundUser = find(this.db.list('users'),{ 'email' : fs.email }
// and then update based on the object key
this.db.list('/users/'+ Object.keys(foundUser)).update(this.newuser);
i fixed the problem by using:
this.db.object('/users/'+ fs.uid).update(this.newuser);
instead of :
this.db.list('/users/'+ fs.uid).update(this.newuser);
And it works correctly !
Thanks all for help.

Categories

Resources