Firebase Ondisconnect - javascript

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.

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.

I'm working on a web app involving firebase firestore, and I want to query just 1 specific field

I'm building a web app that involves using firebase firestore to keep track of users. I am also using firebase authentication on this web app. I have a collection of users and a document for each user. Currently, I am still testing this so I am the only user. One of the fields is account type. It is either standard or admin. I want only admins to be able to sign in. I am trying to do this by finding the document associated with that user and seeing if the account type is admin. Here is my code.
auth.onAuthStateChanged(user => {
if (user) {
if (//Add Code Here) {
setupUI(user);
} else {
auth.signOut;
};
} else {
setupUI();
};
I have already tried this:
auth.onAuthStateChanged(user => {
if (user) {
if (db.collection('users').get(auth.currentUser.uid).type == 'admin') {
setupUI(user);
} else {
auth.signOut;
};
} else {
setupUI();
};
It didn't work. I have watched so many youtube videos and looked at so many web pages, trying to figure it out, but I have seen nothing useful to me. I am fairly new to firebase auth, so I have no idea what to do. I looked at the firebase docs, but they confused me too. I am also pretty new to javascript.
Edit #1:
I edited my code so that the program will work properly. Now, when I open the page, the console shows this: subscribe.ts:239 ReferenceError: accountType is not defined
at Object.next (auth.js:7).
I think this is because I create that constant inside the function and then try to reference it outside the function. How do I create a variable inside a function that I can reference outside a function?
I now have this code:
auth.onAuthStateChanged(user => {
if (user) {
const docRef = db.collection('users').doc(auth.currentUser.uid);
docRef.get().then(function(doc) {
const accountType = doc.data().type;
});
if (accountType == 'admin') {
setupUI(user);
} else {
auth.signOut;
};
} else {
setupUI();
};
});

What is the correct way to load data from thousands of users without slowing down our vue.js and firebase app?

We recently launched an application for a company that provides staff for music festivals using vue.js and a firebase realtime database. We have about 2,000 users and currently 8 events that they can apply for. Each user has profiles and admins can manage their events and hires from the app. The app fires up right away, but the data in "getInitialUserState" takes a long time to populate. I'm worried that once we have 5K or 10K users, load time will only get worse.
In our App.vue file:
created () {
this.$store.dispatch("getInitialState")
this.$store.dispatch("getInitialEventsState")
}
Then in Users.vue:
created () {
this.$store.dispatch("getInitialUserState")
}
In our store:
getInitialState({ commit }) {
firebase.auth().onAuthStateChanged(function(user) {
console.log(user);
const db = firebase.database();
db.ref('users/').child(user.uid).on('value', (snap)=>{
let u = snap.val();
u.id = user.uid
commit('setUser', u);
})
})
},
getInitialUserState({commit}, payload){
const db = firebase.database()
db.ref("users").once("value", (snap) => {
let data = []
for(var key in snap.val()){
let user = snap.val()[key]
user.id = key
data.push(user)
}
commit('setUsers', data)
commit('setUsersMap', snap.val());
})
},
and:
getInitialEventsState({ commit }) {
let db = firebase.database();
db.ref("/events").on("value", function (snapshot) {
let data = []
for (var key in snapshot.val()) {
let event = snapshot.val()[key];
if(event.title){
event.id = key
data.push(event)
}
}
commit("setLoadedEvents", data)
commit("setEventsMap", snapshot.val());
})
}
We've tried adding v-cloak to different elements so don't render without all of the correct data, but that either doesn't work or we are doing it wrong. I've also tried loading data at different lifecycle hooks, but that doesn't make any difference either.
What I want to happen is for my data (as a logged-in user) and for event data to load immediately. Then, EITHER for the "Users" data to only load if the user in a admin (so it won't slow down the experience for regular users), or for Users data to load asynchronously and without interfering with the rest of the app. Currently, while the Users data is loading, the page is effectively frozen and you can't click to go to any other pages.
Firebase should be fast. We are using firebase hosting as well. I'm hoping you guys can at least point us in the right direction.
What is the correct way to load data from thousands of users without slowing down the user experience?
Thanks!

AngularFirebase 2 check if user exists then add to database

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

Firebase User Already Logged In

I have a firebase app that I can log into from various devices, but I'd like to disconnect the other connections if I make a new one using the same account.
I saw this bit of code but I think this might be for the old version:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});
This looks like the right idea - if this gets called I could show a graphic saying, "Oops looks like you signed in on another device." then fire a disconnect while allowing the other connection to proceed?
This isn't something you'll be able to handle with auth alone, as the tokens are generated and stored independently and there's no concept of "device sessions" that can be queried against. However, you could do something like this:
var deviceId = generateARandomDeviceIDAndStoreItInLocalStorage();
firebase.auth().signInWithPopup(/* ... */).then(function(user) {
var userRef = firebase.database().ref('users').child(user.uid);
return userRef.update({
deviceId: deviceId
});
});
firebase.auth().onAuthStateChanged(function(user) {
var userRef = firebase.database().ref('users').child(user.uid);
userRef.child('deviceId').on('value', function(snap) {
if (snap.val() !== deviceId) {
// another device has signed in, let's sign out
firebase.auth().signOut();
}
});
});
IMPORTANT CAVEAT: This is not a secure, enforceable way to guarantee only one device is logged in at once. Rather it is a client-driven way to generally achieve the goal of only one device being signed in.

Categories

Resources