Creating multiple users in Firebase at the same time - java

Well, not exactly at the same time. More like one after the other, in a for-loop.
Problem: So in some instances, the code I used did manage to create multiple accounts but it often gives me the error that the user is null and fails to write to the database.
The code:
Database db = FirebaseDatabase.getInstance().getReference();
String password = "1234567"; // Same password for all accounts
ArrayList emailArray = new ArrayList(); // For example, 20 premade emails
for (int i = 0; i < emailArray.size(); i++){
mAuth.createUserWithEmailAndPassword((String) emailArray.get(i), password).addOnCompleteListener(new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (mAuth.getCurrentUser() != null) {
String userId = mAuth.getCurrentUser().getUid(); // This value is returning null
// Writing a bunch of things to the database for each user
db.child(userId).child("name").setValue(...)
...
mAuth.signOut();
}
}
});
}
I think I may have to use an AuthStateListener but I am unsure and I don't know how to implement it. How would I go about accomplishing this? Please let me know if I should include anything else in my post. Thank you!

You should not use the client-side Android SDK to create multiple users like this. There's a significant chance that your app will be flagged for abuse, and locked out of the system.
For administrative use-cases, use the Admin SDK in a trusted environment.
On a code level, the problem occurs because there's only one value for mAuth.getCurrentUser() and you're trying to create all the users in parallel. You'll need to wait for each createUserWithEmailAndPassword to be completed, before starting on the next one. But as said above: this approach is flawed to begin with, so I don't recommend pursuing this path further.

Related

Firestore - Custom objects for nested collection

The question may sound weird. I have the following custom Object that I named ItemUser:
private UserInfo user_info;
private List<UserAchievement> user_achievements;
Both fields have getters and setters. My Firestore's database looks like this:
I would like to get the List size instead of re-calling the database and getting the size of the collection from a separated call that would consume much resources and take a lot of time (3-4s).
Firstly I'm getting the data using this:
mDB.collection("COLLECTION_NAME").document("USER_ID").get()
Inside the onCompletedListener I'm getting the custom object as the following:
ItemUser mUser = task.getResult().toObject(ItemUser.class);
Now, when I'm trying to get the size of the user_achievements, a NullPointerException popups saying I can't get the size of a null reference.
Therefore the user_achievements is null. I think the way I'm defining user_achievements in my custom Object is the reason for this exception.
The question is: How could this be possible done without recalling the database to count only the size?
I have the main custom Object ItemUser and its children are 'healthy' except user_achievements because of the way it's defined - List<UserAchievement>.
So, any suggestions to overpass this issue?
How could this be possible done without recalling the database to count only the size?
No, because Cloud Firestore is a real-time database and items can be added or deleted, so to get the size of a list you need to query the database and use a get() call.
If you want to count the number of documents beneath a collection (which can be added to a list), please see my answer from this post in which I have explained that task.getResult().size() can help you solve the problem.
Edit:
mDB.collection("COLLECTION_NAME").document("USER_ID").get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
int size = task.getResult().size();
Log.d(TAG, String.valueOf(size));
}
}
});

Download user from Firebase, Messenger app

I'm trying to write messenger app using Firebase.
In database I have a few entries, which are User.class objects. I'm trying to write function which can download User object from database. I though that it'd be better to build separate class (UserManager) for this task, because I don't like making mess in code. But there is a problem, because in onCreate method I need to use User object to download some additional info from database to create conversation list, so downloading user from server should be done before that. Also if user is not in database, it should create and push User to database using FirebaseAuth (I've got that working).
Should I build class extending AsynchTask, and there put downloading user, and then updating UI with the data downloaded after user ?
How do I know if the user was already downloaded. Probably I should build some listener but I don't know how to do that.
Additional question:
If I use this reference with value listener, do i get a user object or some value from inside of the object?
DatabaseReference userReference = FirebaseDatabase.getInstance().getReference().child("users/" + mUserID);
Here is my database:
Each entry key is userID from FirebaseAuth for easier implementation.
I've been cracking my head on this for a few days and tried different approaches. I'll apriciate any help. I think, that some code or a scheme would be a huge help.
How do I know if the user was already downloaded?
You can add a flag to each user with the value of false and once you have downloaded the user object, to set the value to true but this is not how things are working with Firebase. You cannot know when a user from the database is completed downloaded becase Firebase is a realtime database and getting data might never complete. That's why is named a realtime database because in any momemnt the data under that User object can be changed, properties can be added or deleted.
You can use a CompletionListener only when you write or update data and you'll be notified when the operation has been acknowledged by the Database servers but you cannot use this interface when reading data.
If I use this reference with value listener, do i get a user object or some value from inside of the object?
If the value that you are listening to is a User object, then you'll get a User object. If the value is another type of object, which can also be a String (which is also an object) then you'll get that type of object, which can also be a String object. Remember, that only the keys in a Firebase database are always strings.
Maybe this part of my code will help you figure out:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("users")
.child(mUserID);
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User user = dataSnapshot.getValue(User.class);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.e(TAG, "DatabaseError: " + databaseError.getMessage());
}
});

Parse Increment feature doesn't increment over value of 1

I've been trying to get a registration/login form going on in my android application, and I've been trying to do so with the help of the Parse Core by storing users' information as an Object.
I've gotten everything to work perfectly. Well...almost.
The only thing that I need to do now is to add a unique user ID for every user registered and increment it by 1 everytime a new user registers.
I've tried using the Users.increment("userID", 1);, and it works, but it doesn't go over the value 1.
This is what I'm trying to do:
This is my registration form code:
ParseObject Users = new ParseObject("Users");
Users.increment("userID", 1);
Users.put("first_name", firstname);
Users.put("last_name", lastname);
Users.put("email", email);
Users.put("password", password);
Users.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
//User registered successfully.
Toast.makeText(RegisterActivity.this, "Registration successful."
, Toast.LENGTH_SHORT).show();
//Take user to LoginActivity.
startActivity(new Intent(RegisterActivity.this, LoginActivity.class));
} else {
//User registration failed.
Toast.makeText(RegisterActivity.this, "Registration failed."
, Toast.LENGTH_SHORT).show();
//Show error.
e.printStackTrace();
}
}
});
Thank you for your time.
When you write ParseObject user = new ParseObject("Users"); you are defining a new row of the table, so if you call increment() you will be incrementing just that row's value.
If you want to do something different I can help you out. The answer is different based on what you want to do:
keep a total count of users;
add a unique identifier to each user;
...
and why you want to do it. Note that each user has already a unique identifier, in the objectId field, and that can be helpful in most, if not all, applications.
Ok, now I have seen your second screenshots and understand what you are trying to achieve. That is surely possible, but I would discourage it. For example, let's say you manage to write working code. What happens if..:
The user with userID = 1 deletes his account? Are you going to scale down the userIDs of all the users that registered after (userID = 2, 3, ...)? That is hard and mostly useless.
Two or more users register at the same time? That would determine serious synchronization issues and you could end up having two (or more) users with the same userID.
So my answer is: what you want is possible only with hard work, and probably useless. If you give additional info about why you want to do that, we can find a better way.

xpages: referencing a view from a different database/application

I am very new to xpages. I have been searching the web for an answer to my question for a while now. Seems like the answer should be simple.
I have been playing around with a snippet of code that I got from Brad Balassaitis's excellent Xcellerent.net site that populates a list of "jumptoitems" for a viewpanel dynamically. The code is run from the beforeRenderResponse event of the xpage.
var viewName = getComponent('viewPanel1').getData().getViewName();
var vw = database.getView(viewName);
var colNum = 1;
var cols:Vector = vw.getColumns();
for (var i=0; i < cols.length; i++) {
if (cols[i].isSorted() && !cols[i].isHidden()) {
colNum = i + 1;
break;
}
}
var letters = #DbColumn(null, viewName, colNum);
var options = #Trim(#Unique(#UpperCase(#Left(letters, 1))))
viewScope.put('jumpToOptions', options);
It works beautifully - but I want to modify the code to reference a view in a different database. In the post Brad says that the code can be "enhanced" to accomplish this. But I have been experimenting and searching for a while and cannot accomplish the enhancement.
Thanks for any help.
--Lisa&
In your second line, you establish a handle on the view by viewName you pull from the component viewPanel1. Your call is database.getView(viewName). This amounts to a programmatic reference of NotesDatabase.getView(). If you get a handle on the other database you want to connect to, they you can invoke the same .getView() call on that handle.
First, establish your connection to the other database; this is done via the session keyword (which is a NotesSession), as such:
var extDB = session.getDatabase(dbName)
As Howard points out, that session keyword is the current user's session and will be subject to all ACL rights/assignments/roles as that user. If you need to elevate privileges to programmatically expose additional data, you can do so with the sessionAsSigner keyword (which is also a NotesSession, just with the credentials of the signer, yourself, or you can have the NSF signed as the server ID, to give it even higher privileges).
Then proceed as usual with your extDB handle in place of the database keyword (which is about the same as session.getCurrentDatabase()); like so:
var vw = extDB.getView(viewName)
The NotesDatabase.getView() call will return null if a View by that name doesn't exist in that NSF, so you'll want to ensure that it's there and programmatically check for and handle a null return.
[Edit]
Since you're using the ported # function of #DbColumn as it is, to use the approach as Frantisek Kossuth suggests may be easy, but relies on the NotesSession of the current user. To override that user's (lack of) privileges and get full visibility of all documents' values in the separate NSF, you would still need to get a handle on the columnValues for the View as shown above, using the sessionAsSigner keyword.
[/Edit]
Based on your code you need to specify database in #DbColumn formula, too.
var letters = #DbColumn([database], viewName, colNum);
You can read about it here or there...
Aside of documented formats you can use API format "server!!database" as single string value.

How to store data in field from database in Spring MVC

I have a problem which is related to logic than a technology, here is a scenario, (I am using Spring + Hibernate)
I need to read some data from database to return back to page on every get request, but I thought some hack here that what if using some script someone reload page very frequently, this will cause that many calls to server, for this I thought to read data and put them in global variables or class variable, by doing so i end up writing very weird code many global variable and stupid way to give them initial value like for a variable user-status which is a byte type variable I have given -2 as initial value so that my inner logic can understand no value is set for this variable from database, below is my code
#Controller
/* #Secured("hasRole('ROLE_USERS')") */
#RequestMapping("member")
public class ApplyRoles {
#Autowired
private UserInformationForAccessApplication checkUserStatus;
// we will initialize variables to avoid auto-initialize by constructor
private byte userStatus = Constant.IntializationOfGlobalVariable.GLOBALINIT,
requesttype = Constant.IntializationOfGlobalVariable.GLOBALINIT,
access = Constant.IntializationOfGlobalVariable.GLOBALINIT;
Map<String, Object> accessnrole;
Map<String, String> country;
Map<String, String> roleArray;
#Autowired
StudentEnrollmentApplication enrollmentApplication;
#Autowired
SystemProperties systemProperties;
#Autowired
EmployeeEnrollmentApplicationResume employeeEnrollmentApplicationResume;
#Autowired
AccessEnrollmentProcessing accessEnrollmentProcessing;
private String role = Constant.IntializationOfGlobalVariable.ROLENOTSET,
fname, lname;
#RequestMapping(value = "/user", method = RequestMethod.GET)
public String checkingUserStatus(Model model, HttpSession session,
Authentication authentication) {
String sessionemail = "yashprit#gmail.com";// (String) session
// .getAttribute(Constant.SessionAttributes.LOGGEDINUSER);
// first check global value, if found set than don't fetch from database
if (userStatus == Constant.IntializationOfGlobalVariable.GLOBALINIT) {
// get user status from MySQL Database
userStatus = checkUserStatus.checkStatus(sessionemail).get(0);
if (!(userStatus == Constant.UserRoleApplicationStatus.NOTAPPLIED)) {
access = checkUserStatus.checkStatus(sessionemail).get(1);
model.addAttribute(Constant.SystemName.ACCESS, access);
}
}
if (!(userStatus >= Constant.UserRoleApplicationStatus.NOTAPPLIED || userStatus <= Constant.UserRoleApplicationStatus.REJECTED)) {
model.addAttribute("error", "User status is not avaible");
return "redirect:error/pagenotfound";
} else if (userStatus == Constant.UserRoleApplicationStatus.NOTAPPLIED) {
if (requesttype == Constant.IntializationOfGlobalVariable.GLOBALINIT) {
// get request type from MongoDB database
requesttype = checkUserStatus.getRequestType(sessionemail);
}
if (!(requesttype == Constant.RequestType.NORMALEBIT || requesttype == Constant.RequestType.INVITEBIT)) {
model.addAttribute("error",
"Facing Technichal Issue, Please try again");
return "redirect:error/pagenotfound";
}
if (requesttype == Constant.RequestType.INVITEBIT) {
if (!(Byte.parseByte((String) accessnrole
.get(Constant.SystemName.ACCESS)) == Constant.Access.USERBIT)) {
accessnrole = checkUserStatus
.getAccessAndRole(sessionemail);
}
if (accessnrole.get(Constant.SystemName.ACCESS).equals(
Constant.Database.ERRORMESSAGE)
|| accessnrole.get(Constant.SystemName.ROLE).equals(
Constant.Database.ERRORMESSAGE)) {
model.addAttribute("error",
"Facing Technichal Issue, Please try again");
return "redirect:error/pagenotfound";
}
model.addAttribute(Constant.SystemName.ACCESSNROLE, accessnrole);
model.addAttribute(Constant.SystemName.REQUESTTYPE, requesttype);
}
}
model.addAttribute(Constant.SystemName.USERSTATUS, userStatus);
return "member/user";
}
}
to avoid global variable i thought of suing cookies, because I don't want to call database on every page reload in same session, once its loaded for a session than I don't have to call to database.
Anything that can help to to redesign above part of code is much appreciated
thanks
There are really 2 things that you are considering, and correctly me if I'm wrong, but:
Caching on the server (in your Java application) to avoid doing a database lookup multiple times for the same data.
Avoid the client (browser) from sending multiple requests to the server.
The first can be resolved using caching which is available in spring uses annotations on any given method. The documentation is available here.
The second is a bit more tricky and I' leave it for now unless you discover a performance problem. It's again possible to do in Spring and takes advantage of the HTTP protocol and caching controls available in the HTTP header to inform the browser how long to cache responses.
What you are thinking about is called a "cache". It is a standard Computer Science way of doing things and they have been doing research on how to use caches for as long as there have been computers.
You might want to go do some reading on the subject. I found this one by Googling "cache tutorial java" http://javalandscape.blogspot.com/2009/01/cachingcaching-algorithms-and-caching.html
In simplest terms (a one item cache) what you want is to store some data object that you recently took some time to come up with. But you also have to have some sort of identifier so you can tell if the next request is asking for the same data. If it isn't, you have to do all the work over. If it is the same data, you just return it again.
So the algorithm works something like this in this simple case:
if (storedData != null && storedRequestInfo == userRequest.requestInfo) {
return storedData;
}
storedData = youCalculateTheRequestedData();
storedRequestInfo = userRequest.requestInfo;
return storedData;
Its not any real programming language, just something to show you how it works.
The requestInfo is whatever comes in with the request that you use to look up your database stuff. You save it in storedRequestInfo after any calculation.
This shows it as returning some data to the user, that's what is in storedData.
It's a simple, one-element cache.
(To expand on this, you can store the storedRequestInfo and storedData in the session and you end up with one of these stored for each user. You can also use a java Map and store a bunch of storedData. The problem is to decide how to limit your memory use. If you store too many of these for each user, you use up too much memory. So you limit how many each user can have either by size or by count. Then you have to decide which one to delete when it gets too big. In the simple case, you always delete, in essence, the stored one and store a new one.
I noticed your comment. ECache is just a big fancy Map in the terms I used above. I don't know if it's naturally session dependent but it can be made that way by adding the session id to the cache key.)

Categories

Resources