I am writing a Parse Android application which uses anonymous users by enabling automatic user creation. I can successfully signup this user (to convert the anonymous user into a regular user) and after that, logging in. Both calls return successfully. When I then set data on the user object and trying to save the user, I get a stackoverflow in the ParseObject class.
My code looks like this (simplified example code):
user.setUsername("MyUserName");
final String password = new PasswordGenerator().nextSessionId();
user.setPassword(password);
try {
user.signUp();
ParseUser.logInInBackground(verification.getPhoneNumber(), password, new LogInCallback() {
#Override
public void done(final ParseUser parseUser, final ParseException e) {
if (parseUser == null) {
requestListener.onError(e);
} else {
parseUser.put("phone_no", "123");
parseUser.saveInBackground(new SaveCallback() { // This generates a stackoverflow
#Override
public void done(final ParseException e) {
int i = 0;
System.out.println("i = " + i);
}
});
// requestListener.onSuccess(null);
}
}
});
} catch (ParseException e) {
e.printStackTrace();
}
The stack overflow is generated when calling saveInBackground on the ParseUser. The stackoverflow looks like this:
java.lang.StackOverflowError
at com.parse.ParseObject.isDataAvailable(ParseObject.java:3212)
at com.parse.ParseObject.checkGetAccess(ParseObject.java:3284)
at com.parse.ParseObject.getString(ParseObject.java:2867)
at com.parse.ParseUser.getUsername(ParseUser.java:401)
at com.parse.ParseUser.signUpAsync(ParseUser.java:665)
at com.parse.ParseUser.resolveLazinessAsync(ParseUser.java:1397)
at com.parse.ParseUser.saveAsync(ParseUser.java:502)
at com.parse.ParseUser.signUpAsync(ParseUser.java:681)
at com.parse.ParseUser.resolveLazinessAsync(ParseUser.java:1397)
at com.parse.ParseUser.saveAsync(ParseUser.java:502)
at com.parse.ParseUser.signUpAsync(ParseUser.java:681)
The Parse version I use is 1.8.0.
Any ideas?
I found the solution! Turns out you have to save the anonymous user first before converting the user into a registered one. If you save the user first, convert the user into a registered one and then do a saveInBackground, you won't get a stackoverflow. So the full code to convert an anonymous user is:
final String accountUsername = username.getText().toString();
final String accountPassword = password.getText().toString();
final ParseUser user = ParseUser.getCurrentUser();
user.setUsername(accountUsername);
user.setPassword(accountPassword);
user.signUpInBackground(new SignUpCallback() {
#Override
public void done(final ParseException e) {
if (e != null) {
Toast.makeText(MainActivity.this, "Signup Fail", Toast.LENGTH_SHORT).show();
e.printStackTrace();
} else {
Toast.makeText(MainActivity.this, "Signup success", Toast.LENGTH_SHORT).show();
final ParseUser user = ParseUser.getCurrentUser();
user.put("phone_no", "31743379507");
user.saveInBackground(new SaveCallback() {
#Override
public void done(final ParseException e) {
if (e != null) {
Toast.makeText(MainActivity.this, "Save data Fail", Toast.LENGTH_SHORT).show();
e.printStackTrace();
} else {
Toast.makeText(MainActivity.this, "Save data success", Toast.LENGTH_SHORT).show();
}
}
});
}
}
});
Please note that the saveInBackground in the SignupCallback is optional. You could also set this data on the user before the signUpInBackground is called and save an extra roundtrip. This is pure for demonstration purposes.
Also, it is assumed the following code is placed in the Application class to allow anonymous users:
ParseUser.enableAutomaticUser();
ParseUser.getCurrentUser().saveInBackground();
Here you see the user is saved as soon it is created.
findViewById(R.id.createUser).setOnClickListener(newView.OnClickListener() {
#Override
public void onClick(final View v) {
final String accountUsername = username.getText().toString();
final String accountPassword = password.getText().toString();
final ParseUser user = ParseUser.getCurrentUser();
user.setUsername(accountUsername);
user.setPassword(accountPassword);
user.signUpInBackground(new SignUpCallback() {
#Override
public void done(final ParseException e) {
if (e != null) {
Toast.makeText(MainActivity.this, "Signup Fail",
Toast.LENGTH_SHORT).show();
Log.e(TAG, "Signup fail", e);
} else
{ Toast.makeText(MainActivity.this,"Signupsuccess",Toast.LENGTH_SHORT).show();
final ParseUser user = ParseUser.getCurrentUser();
user.put("phone_no", "31612345678");
user.saveInBackground(new SaveCallback() {
#Override
public void done(final ParseException e) {
if (e != null) {
Toast.makeText(MainActivity.this, "Save data Fail", Toast.LENGTH_SHORT).show();
Log.e(TAG, "Signup fail", e);
} else {
Toast.makeText(MainActivity.this, "Save
data success", Toast.LENGTH_SHORT).show();
}
}
});
}
}
});
}
})
Related
Welcome all!
I am currently working to pass a token generated by Stripes API from an Android app to a ParseServer. Below is my code, please be advised that I commented out previous failed attempts to let you know what I have tried and to also spark your imagination. Please note that with trial and error the issue presents to be with saving the data to the server. I have double checked that the class User has write permissions and it has an Object attribute titled token.
// Test the data.
if (userCard.validateCard()) {
Stripe stripe = new Stripe(CardActivity.this, "correct data is here I removed it, for StackOverflow");
stripe.createToken(
userCard,
new TokenCallback() {
public void onSuccess(final Token token) {
// Send token to your server
// Query the users, and get the username.
ParseQuery<ParseObject> query = ParseQuery.getQuery("User");
ParseUser user = ParseUser.getCurrentUser();
String objectId = user.getObjectId();
// Query the current user.
//query.whereEqualTo("objectId", username);
ParseObject object;
try {
object = query.get(objectId);
object.put("token", token);
object.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
Toast.makeText(CardActivity.this, "Success", Toast.LENGTH_SHORT).show();
}
}
});
} catch (ParseException e) {
Toast.makeText(CardActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
// Attempt to update... Currently not working.
/*query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> objects, ParseException e) {
if (e == null && objects != null) {
for (ParseObject object : objects) {
object.put("token", token);
object.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
Toast.makeText(CardActivity.this, "Success", Toast.LENGTH_SHORT).show();
}
}
});
}
} else {
Toast.makeText(CardActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
});*/
}
public void onError(Exception error) {
// Show error message
Toast.makeText(CardActivity.this,
error.getMessage(),
Toast.LENGTH_LONG
).show();
}
}
);
} else {
Toast.makeText(CardActivity.this, "Something went wrong", Toast.LENGTH_SHORT).show();
}
A few things here:
1) Parse allows you to add/overwrite information to objects from their "shell". This is a ParseObject instance, set to a specified class, assigned an objectId, and then whatever values you want to add/change, and then saved. Any field you did not assign a value to will be ignored, so say you only set field3, field2 and field1 will not be overwritten to nothing.
2) ParseUser user = ParseUser.getCurrentUser() already returns a user object. You don't even need to create a shell from the id, this is a fully functioning parse object. You can then set the value you want and save it!
3) Queries and fetches (and cloud function calls) are asynchronous. This means that the code executes over time on a background thread, and your main thread will go on. So, things that require the results of these methods need to be called within the completion handler. You're doing object = query.get(objectId), but query.get() takes a bit to run so you're probably running through the rest of the code block before object has a proper value.
4) To my knowledge (not an Android developer, but I've used the JS and iOS SDKs) the Parse SDKs have a specific query for the User class that is a bit easier and safer to use than creating a ParseQuery set to the "User" class. Should be something like ParseUser.query()
So, not being an Android developer, I think what you want is more like this:
// Test the data.
if (userCard.validateCard()) {
Stripe stripe = new Stripe(CardActivity.this, "correct data is here I removed it, for StackOverflow");
stripe.createToken(
userCard,
new TokenCallback() {
public void onSuccess(final Token token) {
// Send token to your server
// Query the users, and get the username.
ParseQuery<ParseObject> query = ParseQuery.getQuery("User");
ParseUser user = ParseUser.getCurrentUser();
try {
user.put("token", token);
user.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
Toast.makeText(CardActivity.this, "Success", Toast.LENGTH_SHORT).show();
}
}
});
} catch (ParseException e) {
Toast.makeText(CardActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
public void onError(Exception error) {
// Show error message
Toast.makeText(CardActivity.this,
error.getMessage(),
Toast.LENGTH_LONG
).show();
}
}
);
} else {
Toast.makeText(CardActivity.this, "Something went wrong", Toast.LENGTH_SHORT).show();
}
I'm beginner on Android and I'm looking for a way on how can I check if a username exists already in Parse data class(User) in Android.
btnreg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ParseUser user = new ParseUser();
user.setUsername(etmail.getText().toString());
user.setPassword(etpwd.getEditableText().toString());
user.put("nom_prenom", etname.getText().toString());
user.put("tel", ettel.getText().toString());
user.put("adresse", adresse.getText().toString());
user.put("sexe", spsexs.getSelectedItem().toString());
user.put("annee_naissance",spnaissance.getSelectedItem().toString());
user.put("ville", spville.getSelectedItem().toString());
user.signUpInBackground(new SignUpCallback() {
public void done(ParseException e) {
if (e == null) {
// Show a simple Toast message upon successful registration
} else {
alerte("Oupss!!", "Error..." + e.getMessage(), 0);
}
}
public void done(com.parse.ParseException e) {
alerte("Succes", "Inscription terminée..", 1);
}
});
I want to check if a username exist in parse : if it exist i want to show an error or a message ("username already taken").
Why do you want do to this ? parse will do that itself for you.
You can track this using ParseException object that you get in SignUpCallback's done method.
Try to get message of that ParseException.
It might be helpful for you to check the ParseUI module, they have all those scenarios covered. Here is a snippet from ParseSignupFragment.java that does the validation:
user.signUpInBackground(new SignUpCallback() {
#Override
public void done(ParseException e) {
if (isActivityDestroyed()) {
return;
}
if (e == null) {
loadingFinish();
signupSuccess();
} else {
loadingFinish();
if (e != null) {
debugLog(getString(com.parse.ui.R.string.com_parse_ui_login_warning_parse_signup_failed) +
e.toString());
switch (e.getCode()) {
case ParseException.INVALID_EMAIL_ADDRESS:
showToast(com.parse.ui.R.string.com_parse_ui_invalid_email_toast);
break;
case ParseException.USERNAME_TAKEN:
showToast(com.parse.ui.R.string.com_parse_ui_username_taken_toast);
break;
case ParseException.EMAIL_TAKEN:
showToast(com.parse.ui.R.string.com_parse_ui_email_taken_toast);
break;
default:
showToast(com.parse.ui.R.string.com_parse_ui_signup_failed_unknown_toast);
}
}
}
}
});
I'm trying to make an android app using parse that allows one to login using either their username or email. I have tried querying to get an object with a provided email address, then get that object's username to login with. However, I am getting this error:
'getFirstInBackground(com.parse.GetCallback)' in 'com.parse.ParseQuery' cannot be applied to '(anonymous com.parse.GetCallback "com.parse.ParseObject>)'
I'm new to app dev and parse, so I'm not entirely sure what this means. From what I understand it wont let me use getFirstInBackground because that works with parseUser's and I'm working with ParseObjects, but the code I'm using I pulled from a prior stackoverflow question where this was a working answer: Login username AND email in Parse Android
Here is my code:
// Do this to allow for username or email log in
if (mEmail.indexOf("#") != -1) {
ParseQuery<ParseUser> query = ParseUser.getQuery();
query.whereEqualTo("email", mEmail);
query.getFirstInBackground(new GetCallback<ParseObject>() {
public void done(ParseObject object, ParseException e) {
if (object == null) {
Log.d("score", "The getFirst request failed.");
} else {
String actualUsername = object.getString("username");
ParseUser.logInInBackground(actualUsername, mPassword, new LogInCallback() {
#Override
public void done(ParseUser parseUser, ParseException e) {
if (e != null) {
// TODO: Show error message
Toast.makeText(LoginActivity.this, "Credentials incorrect", Toast.LENGTH_LONG).show();
} else {
// Start Intent for activity
// TODO: Choose activity
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
}
}
});
}
}
});
According to docs, the method's signature is as follows:
class com.parse.ParseQuery<T> {
public void getFirstInBackground(GetCallback<T> callback)
}
That means that the generic type of GetCallback must be the same as in your ParseQuery. So it probably should be
query.getFirstInBackground(new GetCallback<ParseUser>()) { /* ... */ }
You are attempting to query a ParseUser with a GetCallBack of type ParseObject.
Replace all instances of ParseObject with ParseUser in your code.
query.getFirstInBackground(new GetCallback<ParseUser>() {
public void done(ParseUser user, ParseException e) {
if (object == null) {
Log.d("score", "The getFirst request failed.");
} else {
String actualUsername = user.getUsername();
ParseUser.logInInBackground(actualUsername, mPassword, new LogInCallback() {
#Override
public void done(ParseUser parseUser, ParseException e) {
if (e != null) {
// TODO: Show error message
Toast.makeText(LoginActivity.this, "Credentials incorrect", Toast.LENGTH_LONG).show();
} else {
// Start Intent for activity
// TODO: Choose activity
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
}
}
});
}
}
});
Hope this helps
final String userOrEmal = editTextEmailOrUserName.getText().toString().trim();
final String mpassword = editTextPassword.getText().toString().trim();
if (userOrEmal.contains("#")) {
ParseQuery<ParseUser> query = ParseUser.getQuery();
query.whereEqualTo("email", userOrEmal);
query.getFirstInBackground(new GetCallback<ParseUser>() {
#Override
public void done(ParseUser object, ParseException e) {
if (object != null) {
ParseUser.logInInBackground(object.getString("username"), mpassword, new LogInCallback() {
public void done(ParseUser user, ParseException e) {
if (user != null) {
Log.v("login", "secessful");
} else {
Log.v("login", "fail");
}
}
});
} else {
}
}
});
} else {
ParseUser.logInInBackground(userOrEmal,mpassword, new LogInCallback() {
public void done(ParseUser user, ParseException e) {
if (user != null) {
Log.v("login", "secessful");
} else {
Log.v("login", "fail");
}
}
});
}
I have an android app in which user can change his/her password my problem is how i can verify old password of user using parse i have 3 edit text "old password, new password and confirm new password".
I search on parse.com but can't find any solution parse do not fetch data using get password.
i am doing this
String get_confrimpass=currentuser.getpassword();
if(get_confrimpass.replaceAll("\\s", "").equals(current_pass_check))
{ }
You can try logging them in using there current username and the password that they have given to you. If the loggin is successful the old password is correct. I.e
ParseUser.logInInBackground(ParseUser.getCurrentUser().getUsername(), currentPassword, new LogInCallback() {
public void done(ParseUser user, ParseException e) {
if (user != null) {
// Hooray! The password is correct
} else {
// The password was incorrect
}
}
});
In the example above the 'currentPassword' variable is the text that you would retreive from the 'Old Password' EditText
final ParseUser currentUser = ParseUser.getCurrentUser();
final String userName = ParseUser.getCurrentUser().getUsername();
ParseUser.logInInBackground(userName, oldPass, new LogInCallback() {
#Override
public void done(ParseUser user, ParseException e) {
if (user != null) {
if (et.length() < 6)
Toast(getActivity(), "Password is short, Min char 6", Toast.LENGTH_LONG).show();
else {
currentUser.setPassword(newPass);
currentUser.saveInBackground();
ParseUser.logOut();
ParseUser.logInInBackground(userName, newPass, new LogInCallback() {
#Override
public void done(ParseUser parseUser, ParseException e) {
if (e == null) {
Toast(getActivity(), "Password change", Toast.LENGTH_LONG).show();
} else
Toast(getActivity(), "Network Error", Toast.LENGTH_LONG).show();
}
});
}
} else {
new CustomToast(getActivity(), "Old Password is incorrect", Toast.LENGTH_LONG);
}
}
});
I want a unique user but I don't need it to be a formal thing for my app. So, on launch I inspect shared preferences for a previously stored username. I handle the user creation or login like so:
String parseUsername = _appPrefs.getParseUsername();
_progress.setVisibility(View.VISIBLE);
if (parseUsername == null) {
Log.v(TAG, "Creating a user.");
ParseUser.enableAutomaticUser();
_user = ParseUser.getCurrentUser();
_user.setPassword("abc123");
_user.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
Log.w(TAG, String.format("User '%s' created.", _user.getUsername()));
_progress.setVisibility(View.GONE);
_appPrefs.saveParseUsername(_user.getUsername());
createStory();
return;
}
Log.e(TAG, "Error creating user: ", e);
}
});
} else {
Log.v(TAG, String.format("Logging the user '%s' in with password '%s'.", parseUsername, "abc123"));
ParseUser.logInInBackground(parseUsername, "abc123", new LogInCallback() {
#Override
public void done(ParseUser user, ParseException e) {
Log.v(TAG, "User logged in.");
_progress.setVisibility(View.GONE);
if (e == null) {
createStory();
return;
}
Log.e(TAG, "Error logging in: ", e);
}
});
}
I can see the user being successfully created in the logs. I can kill the app and re-launch but it always fails with "invalid login credentials" response from Parse.
If I manually enter abc123 in the Parse data browser then everything works. Ideas?