cant synchronize correctly with realtime database of firebase - javascript

As part of my studies I need to develop web-app (javasript language) Where we work with firebase realtime database.
currently inside the database,I have a tree of users objects that representing all the users who registered to the system. And what I'm trying to do is a simple user login function.
After the user entered his username and his password, I created an array to enter the entire user tree from a database. The problem is that when im calling the function from the Firebase it's not enough to ended.. and what happens is that the array remains empty and you can not verify that the user is registered on the system.
now I have used a temporary solution that Im using setTimeout function,I understand that this is wrong programming, and also i do not want the user to wait 2 seconds every time he wants to login to the system.
Can someone please help me? how to do it right without the setTimeout function?
I want that the function of the Firebase ends so only then start with the Authentication process.
Here is the code I wrote so far,
var correntUser;
var userlist = [];
var usersRef = database.ref('users');
// Query that inserts all users keys and names to an array.
usersRef.orderByChild("username").on("child_added", function(snapshot)
{
userlist.push({userKey:snapshot.key,username:snapshot.val().username,password:snapshot.val().password});
});
setTimeout(function()
{
//check if user exist in userlist.
for(var i=0; i<userlist.length;i++)
if (userlist[i].username == usernameArg && userlist[i].password == passwordArg)
correntUser = userlist[i].userKey;
if(correntUser == undefined)
{
//check if undefined
alert("wrong username or password");
document.getElementById("username").value = "";
document.getElementById("password").value = "";
return;
}
mainPage.addHeader();
},2000);
thank you all.

There is no need to manually check all users and see if there is a match with the attempted login credentials when Firebase provides built-in authentication. Password-based accounts require email addresses, although you can combine the username with any domain name to satisfy that requirement as suggested here.
You did not explain what your database structure looks like under the users path, but one way to handle that is to incorporate the user's unique id that gets returned as part of the createUserWithEmailAndPassword password:
function createAccount(email, password) {
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(function(userData) {
// account created successfully
usersRef.child(userData.uid).set({
email: email,
creation_date: new Date(),
...
})
}
.catch(function(error) {
...
})
}
Then for login attempts:
function login(email, password) {
firebase.auth().signInWithEmailAndPassword(email, password)
.then(function(userData) {
// login successful
mainPage.addHeader();
})
.catch(function(error) {
alert("wrong username or password");
document.getElementById("username").value = "";
document.getElementById("password").value = "";
})
}

Related

How to add new members in Group using Firebase

I am developing the app which has grouping function.
Now I have the problem about adding new member in group.
Like Slack, in group creating onboarding flow user can decide group name and add members which don't use the app yet.
As adding members function, I want to use inviting mail link using firebase dynamic links.
Data structure is below
User
- id
- name
- email
Group
- id
- groupName
- members[]
Group's members array has user id.
But when someone creates new group, it is possible that new users don't register the app yet.
So they don't have user id property in the app.
How do I fix this problem?
When someone creates new group, should I develop sign up functions new user using Firebase auth? This means then new member has automatically user id, and adding those to members property.
Or should group member array have mail address instead of user id.
Please tell me. I'm happy with Swift or JavaScript you will teach me.
Thank you.
UPDATE
After reading your comment I would propose another approach.
When the Group creator user adds users to a group, if a user does not already exists you could, from the front-end, call a Callable Cloud Function (CF) that creates a temporary Firestore document in a specific collection. The ID of this document will be the (future) userId.
Then, still in this same Cloud Function, you send an email to the email address (you need to generate yourself the email, for example with the email extension) with a link containing the userId as query string value.
Example of code for this first CF:
exports.provisionNewAccount = functions
.https.onCall(async (data, context) => {
try {
// You can check that the caller is authenticated
// if (context.auth.uid) {execute the rest of the code} else {throw an error}
// New user email
const userEmail = data.email;
// Generate the new user docID
const fakeDocRef = admin.firestore().collection('_').doc();
const requestId = fakeDocRef.id;
// Create the doc in a specific collection
await admin.firestore().collection('usersCreationRequests').doc(requestId).set({ email: userEmail, treated: false });
// Generate the link to include in the email
const linkURL = 'https://your.app/register.html?requestId=' + requestId
// Send the email by creating a doc in the Extension collection
await db
.collection("emails")
.add({
to: userEmail,
message: {
subject: "....",
html: `Click to create your account` // adapt the html to add some text
},
});
return {result: 'OK'}
} catch (error) {
console.log(JSON.stringify(error));
throw new functions.https.HttpsError('internal', JSON.stringify(error));
}
});
You call it as explained here, by passing the future user's email.
When the email recipient clicks on the link, you open a specific page of your web app that shows a set of fields for the future user to enter his password, display name etc. Then on clicking on a sign-in button in this page you call a Callable Cloud Function passing it the Firestore document ID plus the field values (you get the document ID from the query string).
As shown below, this Cloud Function creates the user in the Authentication service (using the Admin SDK) and flag the Firestore document as treated. Upon getting back the Cloud Function result in the web app you authenticate the user (you have his email and password, since he/she entered it in the form).
exports.createNewAccount = functions
.https.onCall(async (data, context) => {
try {
const userEmail = data.email;
const userId = data.userId;
const userPassword = data.password;
const userDisplayName = data.displayName;
// Fetch the user doc created in the first CF
const snapshot = await admin.firestore().collection('usersCreationRequests').doc(userId).get();
const treated = snapshot.get('treated');
const email = snapshot.get('email');
if (!treated && userEmail === email) {
const createUserPayload = {
email,
emailVerified: false,
password: userPassword,
displayName: userDisplayName
};
const userRecord = await admin.auth().createUser(createUserPayload);
return { result: 'OK' }
} else {
return { result: 'User already created' }
}
} catch (error) {
console.log(JSON.stringify(error));
throw new functions.https.HttpsError('internal', JSON.stringify(error));
}
});
I’m actually using this exact approach for a B2B collaborative web app in which users can invite new users by email.
INITIAL ANSWER
(Totally different from the update)
So they don't have user id property in the app… How do I fix this
problem? When someone creates new group, should I develop sign up
functions new user using Firebase auth?
You can use the Anonymous Authentication mode, it exactly corresponds to your needs:
You can use Firebase Authentication to create and use temporary
anonymous accounts to authenticate with Firebase. These temporary
anonymous accounts can be used to allow users who haven't yet signed
up to your app to work with data protected by security rules. If an
anonymous user decides to sign up to your app, you can link their
sign-in credentials to the anonymous account so that they can continue
to work with their protected data in future sessions.
When signing-in with Anonymous Authentication a userId (uid) will be created and later you will be able to convert an anonymous account to a permanent account
I always use userId to achive this kind of feature, you can use anonymous authentication to get userId after user click invite link, Then if needed unlock more feature with furter authentication(add more provider).
If you only using mail address without authentication, It's hard to write rules for prevent user access unwanted data, Like anyone knew your email are able to access your account.

Why is firebase creating a random identifier between parent and child?

I'm playing around with a firebase web app and having some difficulty diagnosing where something is coming from.
I am trying to simply push some data to my project under the heading of the uid created when authentication takes place. The authentication works fine and it is returning the uid correctly however, when values are passed it seems to be adding a second layer before the actual values.
function registerAccount() {
var firebase = app_firebase;
var firebaseRef = app_firebase.database(); //database reference
var user = firebase.auth().currentUser;
uid = user.uid;
var ref = firebaseRef.ref('User').child(uid); //referencing node
var userName = document.getElementById("txtUsernameInput").value;
if (user) {
// User is signed in.
var data = { //data being added
Username: userName,
}
window.location = 'myHome.aspx';
} else {
// No user is signed in.
console.log("Cannot get UID");
}
ref.push(data);
}
I am expecting the data entry to show with the child of user to be the uid taken from the authentication (this is working) then have the passed values immediately in the uid without the seemingly auto generated child between the uid and the values.
Image shows the unwanted field being generated
[See here][1]
André Kool's suggestion in a comment:
Change ref.push(data); to ref.set(data);
worked.

Dynamically creating member pages

I am new to website creation and I am using login/membership features. How would I dynamically create a new, permanent web page (profile page) for a member once they sign up?
//where I would use the code
//Javascript
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
//Navigate to the User's page, which does not yet exist
var url = "http://example.com/" + user.uid;
window.location = url;
} else {
// No user is signed in.
}
});
The answer is in the docs.
https://firebase.google.com/docs/auth/web/manage-users#get_a_users_profile
I suggest having a read of some FireBase documentation, you'll likely need to find out about how FireBase routing works (assuming you're using it as a server)
However, for your requirements (i.e. a user profile page), you can just grab the data and display it at a general profile URL.
var user = firebase.auth().currentUser;
var name, email, photoUrl, uid;
if (user != null) {
name = user.displayName;
email = user.email;
photoUrl = user.photoURL;
uid = user.uid; // The user's ID, unique to the Firebase project. Do NOT use
// this value to authenticate with your backend server, if
// you have one. Use User.getToken() instead.
}

Get custom attribute from User class on Parse.com [JavaScript]

I'm working on a website with Parse.com and JavaScript. I have my "User" class, but I have added more fields than those that come by default.
I want to get one specific attribute from my User class (IdGroup) when user logs in, so I'm trying to capture the IdGroup using user object when login has been succesfully.
I have tried this:
Parse.User.logIn(username, pass, {
success: function (user) {
//var idGroup = user.get("IdGroup");
localStorage.setItem("parseUser", true);
localStorage.setItem("guestUser", false);
localStorage.setItem("username", username);
user.fetch().then(function (fetchedUser) {
var idGroup = user.get("IdGroup");
localStorage.setItem("IdGroup", idGroup);
});
window.location.href = 'index.html';
},
error: function (user, error) {
alert('Invalid username or password!');
}
});
This doesn't work.
If anyone could give me a hand, I will really appreciate.
Thanks!!
I would have assumed that the user was already fetched at login.
But your callback function passes in the object fetchedUser, and you're accessing the user object. So, var idGroup = fetchedUser.get("IdGroup"); is probably what you're looking for.

How do I validate input with MongoDB?

I have a simple little user registration form that looks like this:
// POST Register new user
exports.new = function(req, res) {
var db = require('mongojs').connect('localhost/busapp', ['users']);
db.users.ensureIndex({email:1}, {unique: true})
function User(email, username, password, dateCreated) {
this.email = email;
this.username = username;
this.password = password;
this.dateCreated = new Date();
this.admin = 0;
this.activated = 0
}
if (req.body.user.password !== req.body.user.passwordc) {
res.send('Passwords do not match');
} else {
var user = new User(req.body.user.email, req.body.user.username,
req.body.user.password);
// TODO: Remove this after we clarify that it works.
console.log(user.email + " " + user.username + " " +
user.password);
// Save user to database
db.users.save(user, function(err, savedUser) {
if (err) {
res.send(err);
} else {
console.log("User " + savedUser.email + " saved");
}
});
}
}
But I'm having trouble validating information submitted, like unique values, is empty, that sort of thing, so nobody can send post requests to the database to bypass the jQuery validation functions. I've read through the docs but I cannot seem to get it right. I tried setting a ensureIndex, but, that doesn't seem to work. Any information on how to validate the input on the database side would be great thanks!
One of the strengths/features of MongoDB is flexible schema. MongoDB does not impose any specific contraints on fields types. In general with web applications, you should try to do validation as early as possible .. so first at the client (JavaScript) level, then the application, and as a last resort in the database server.
MongoDB validation
MongoDB can do a limited amount of validation such as ensuring a unique index. Any data validation such as required fields or field types (string, integer, ..) should be done in your application code.
Clientside/application validation
You could use jQuery validation, but that would only be effective in the client (browser view). Any validation should also be done in your application code/model, otherwise disabling JavaScript in the browser would be a simple way to insert invalid data.
why cant you do stuff like password != "". as for unique values you should do use the find or findOne functions to see if that name exists in the db.
i would highly recommend installing mongoose. it is really useful as it allows you to create schemas. so if you are familiar with MVC, in your models, you would have user.js which contains the schema for the user. basically it gives guidelines on how the user object will be stored in the database. in your controllers, you would try to do what you are doing in the code you have above. you would do a user = require(user.js) and then you would do user.find() or user.findOne() to find that thing in the database. for example. if the username was already in the database, then its not unique. so dont add him.

Categories

Resources