A bit confused why there's no display name being displayed in my Firebase database, I've followed the steps in the example on their website and didn't get the expected result which they showed. Here's the example code.
final Firebase ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
ref.authWithPassword("jenny#example.com", "correcthorsebatterystaple",
new Firebase.AuthResultHandler() {
#Override
public void onAuthenticated(AuthData authData) {
// Authentication just completed successfully :)
Map<String, String> map = new HashMap<String, String>();
map.put("provider", authData.getProvider());
if(authData.getProviderData().containsKey("displayName")) {
map.put("displayName", authData.getProviderData().get("displayName").toString());
}
ref.child("users").child(authData.getUid()).setValue(map);
}
#Override
public void onAuthenticationError(FirebaseError error) {
// Something went wrong :(
}
});
Whenever I tried this example code the expected result was to be something similar to what is shown below.
{
"users": {
"6d914336-d254-4fdb-8520-68b740e047e4": {
"displayName": "alanisawesome",
"provider": "password"
},
"002a448c-30c0-4b87-a16b-f70dfebe3386": {
"displayName": "gracehop",
"provider": "password"
}
}
}
Instead of showing something similar to the above, in my database only the provider is shown and not the displayName. Is there any necessary steps required to get the displayName to show or should it be there automatically?
I tried to look into this to see what was included within authData.getProviderData() and this was what was produced in the console when I printed it out.
01-25 17:58:51.921 15651-15651/<package-name> I/System.out: {email=j.joe#hotmail.co.uk, isTemporaryPassword=false, profileImageURL=https://secure.gravatar.com/avatar/de53da9874178adb1a44b392ba5bed2f?d=retro}
So from the result produced it's left me wondering if the key "displayName" was formerly automatically created from the email and stored by default in authData.getProviderData() and that's why it is no longer shown.
Would appreciate it if someone could explain where the displayName in the database comes from because judging by the expected result it seems I've missed something.
Thanks!
An email+password account does not have an associated display name. It only requires an email address and a password.
You can definitely require the user to enter additional information. Just don't pass it to createUser() and don't overwrite it after calling authWithPassword().
Update: since the update to Firebase Authentication released at Google I/O 2016, there is now a display name property for each user. So you can also keep the display name in Firebase Authentication itself (although you won't be able to query/search for it).
Related
I am doing a simple Registration page and I have a problem. I can't put users' data in the firestore database. I did it with Realtime Database but with firestore there is a problem and I don't know what it is. Here is the code :
CollectionReference UsersRef = FirebaseFirestore.getInstance().collection("Users");
if (UsersRef != null) {
HashMap<String, Object> userDataMap = new HashMap<>();
userDataMap.put("phone",phoneNumber);
userDataMap.put("password",password);
userDataMap.put("name",name);
UsersRef.document(phoneNumber).update(userDataMap).addOnSuccessListener(aVoid -> {
// First TOAST
Toast.makeText(RegisterActivity.this,"Congratulations, your account has been created.",Toast.LENGTH_SHORT).show();
loadingBar.dismiss();
startLoginActivity();
}).addOnFailureListener(e -> {
loadingBar.dismiss();
//SECOND TOAST
Toast.makeText(RegisterActivity.this,"Network error, please try again later",Toast.LENGTH_LONG).show();
});
} else {
Toast.makeText(RegisterActivity.this,"Votre reference USERS n'a pas été créée",Toast.LENGTH_SHORT).show();
}
I'm getting the user's inputs with variables name, phone number, and password.
If everything is fine, the first toast appears.
if the operation didn't work, the second toast appears.
Just for the sake of giving this post an answer:
As Tom Bailey has correctly commented, the code above is using the update() operation. On this official documentation you can find very useful information about the set() and update() operations.
TL:DR
Set(): creates or overwrites a single document. If the document does not exist, it will be created. If the document does exist, its contents will be overwritten with the newly provided data.
Update(): updates some fields of a document without overwriting the entire document.
I am storing user FCM device tokens in Firebase. When the user logs in, the token is added to the user's profile like this:
if (FirebaseAuth.getInstance().getCurrentUser()!=null) {
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
#Override
public void onSuccess(InstanceIdResult instanceIdResult) {
DeviceToken token = new DeviceToken(instanceIdResult.getToken());
CollectionReference deviceTokens = mUserCollection.document(mSignedInUserID).collection("device_tokens");
deviceTokens.document(token.getTokenID()).set(token);
}
});
}
This works. However, I also want to delete that document when the user signs out. I am attempting to do so like this:
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
#Override
public void onSuccess(InstanceIdResult instanceIdResult) {
Log.d(TAG,instanceIdResult.getToken());
DocumentReference deactivatedToken = mUserCollection.document(mSignedInUserID).collection("device_tokens").document(instanceIdResult.getToken());
deactivatedToken.delete();
mAuth.signOut();
recreate();
}
});
Everything works in that method except for the actual deletion of that document, and the log statement confirms that the user's current ID matches the title of the document to be deleted. A simulation for a signed in user writing to that location returns allowed. What am I doing wrong?
Note that, with your code, the user is going to get signed out before the document is deleted. That's because the delete() is asynchronous (as well as all database operations), and returns immediately, before the work is complete. If I had to guess, I'd say that your authentication token is getting wiped out before the delete operation actually gets sent, and the delete is effectively acting as an unauthenticated user. So, what you should do is wait for the delete to complete for actually signing out the user. Use the Task returned by delete() to know when that finishes. It'll work the same way as the Task returned by getInstanceId().
I'm working on a small app to practice my JAVA/Firebase skills, and I have come into a roadblock. I do admit that I'm not very familiar with Firebase, and rules associated with the database portion. But I have tried looking at other SO posts and searching through documentation.
Problem:
Users create an account (through Firebase Authentication - E-mail/Password). Then they are able to create a "character" and provide this "character" with a name. So I need the "charName" to be unique. And obviously the authenticated ID is also unique already. So I need the app to tell users if the name is already taken or if it isn't, then to go ahead with adding it to the database.
Here are simplified snippits of my code:
btnCreate.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final String charName = "MyCharactersName";
final int charID = 123;
mFirebaseDatabase.child("characters").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
if (!(snapshot.child(charName).exists())) {
Character newCharacter = new Character(charID, charName);
mFirebaseDatabase.child("characters").child(getNewCharID()).setValue(newCharacter); // add to database
Snackbar.make(findViewById(R.id.view_root), "Success", BaseTransientBottomBar.LENGTH_INDEFINITE).show();
} else {
Snackbar.make(findViewById(R.id.view_root), "Error creating a character.", BaseTransientBottomBar.LENGTH_INDEFINITE).show();
}
} else {
Snackbar.make(findViewById(R.id.view_root), "That character name is already taken.", BaseTransientBottomBar.LENGTH_INDEFINITE).show();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Snackbar.make(findViewById(R.id.view_root), "Error - Did not connect with Database", BaseTransientBottomBar.LENGTH_INDEFINITE).show();
}
});
}
});
Currently: The app creates a new character on the database, but you can add duplicate characters. (the charID is unique by the way, I hardcoded it in the snippit above... but it is timeStamp + 4 random digits).
So that obviously happens with the default database Rules. And in the examples that I did read, it looks like I might have to modify those?
My Database structure is as such:
App / characters / charID / charName
I tried to adapt some code from this SO post: How do you prevent duplicate user properties in Firebase?
and this is what I wrote, but it doesn't work and as I admitted before, I'm not familiar with rules, so I'm not sure what I did/did wrong. haha.
{
"rules" : {
"characters" : {
"$charID" : {
".validate": "root.child('charName_lookup/'+newData.val()).val() === auth.uid"
}
},
"charName_lookup" : {
"$charName" : {
".write" : "!data.exists()",
".validate": "newData.val() === auth.uid"
}
}
}
}
If you have any questions/clarifications please let me know. I will be stepping away from the computer periodically but I will check back promptly (I hope!)
Basically, the userName or the email address should be the name of your node. Regarding rules, you can use wildcards. If you create a userName George, to verify if exists you only need to put a reference on users node and use exists() method.
Please take a look at Frank van Puffelen's explanation from this video. Even if you'll need to remodel a bit your database, remember that this is the best practice when we are talking about duplicates.
Basically I am retrieving QBUser list from quickblox server and I don't want Admin(application registered - account owner) name to be listed as QBUser.
Example :
I signup quickblox with name "A" to register "xyz" application.
Afterwards I add certain users ("B","C","D") to application "xyz".
Now when I request user list API for "xyz" application I want only ("B","C","D") in response, but the issue is user list contains all users ("A","B","C","D").
I doubt there's a query to exempt a particular user from the query but you can handle that in your code when the user list is returned.
QBPagedRequestBuilder pagedRequestBuilder = new QBPagedRequestBuilder();
pagedRequestBuilder.setPage(1);
pagedRequestBuilder.setPerPage(50);
QBUsers.getUsers(pagedRequestBuilder, new QBEntityCallback<ArrayList<QBUser>>() {
#Override
public void onSuccess(ArrayList<QBUser> users, Bundle params) {
for(QBUser user: users){
if(user.getFullName().equals("A"))
users.remove(user);
}
//go ahead to use users list without A
}
#Override
public void onError(QBResponseException errors) {
}
});
Hope it helps.
I have an app which works with users, and offers the possibility to follow certain users, at the current user choice.
Unfortunately, I don't know how to modify data of a user which is not the current user. I have not seen anything like that stated in the Parse.com docs(or i missed).
I have a column in my database in "Users" class called "usersFollowed" and when the current user clicks "Follow" i want to add the current user to the "usersFollowed" list, but adding them like you will see in the following code does not work.
Follow user code:
dialog = ProgressDialog.show(context, "",
"Following...", true);
viewHolder.userFollow.setSelected(true);
viewHolder.userFollow.setText("FOLLOWING");
ParseQuery<ParseUser> userListQuery = ParseUser.getQuery();
userListQuery.whereEqualTo("screenName", parseUserList.get(position).get("screenName").toString());
userListQuery.findInBackground(new FindCallback<ParseUser>() {
#Override
public void done(List<ParseUser> parseObjects, ParseException e) {
parseUserFollowedList = new ArrayList<>();
if (parseObjects.get(0).getList("usersFollowed") == null) {
parseUserFollowedList.add(ParseUser.getCurrentUser());
parseObjects.get(0).addAll("usersFollowed", parseUserFollowedList);
} else {
parseUserFollowedList = parseObjects.get(0).getList("usersFollowed");
parseUserFollowedList.add(ParseUser.getCurrentUser());
parseObjects.get(0).addAll("usersFollowed", parseUserFollowedList);
}
parseObjects.get(0).saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
dialog.dismiss();
}
});
}
});
.saveInBackground does not work because it throws exception: Cannot save info for user that is not logged in".
Can anyone help me in how to do this?
Cheers!
Users may modify only their own data. But the idea of following can be implemented such that only the currentUser's record requires write access: If Jack chooses to follow Jill, then Jack writes to his "following" relation. This works as long as we don't try to represent "followedBy" in Jill's data (which can be achieved instead with a query).
Or consider that the User table represents the private relationship between a real person and your app. It might make better sense to model the idea of a user's public face with your own custom object, and model following relationships between those. I mention this idea elsewhere here and here.