Parse cloud function send JSON to specific user - android

I create an App that a user can send messages(notifications) in other users. Fot these perpose i use parse SDK. So i send the message from device into the parse cloud with below code.
final ParseQuery<ParseUser> query = ParseUser.getQuery();
query.whereEqualTo("email", "user#email.com");
query.getFirstInBackground(new GetCallback<ParseUser>() {
public void done(ParseUser object, ParseException e) {
if (e == null) {
Toast.makeText(getActivity(), "User found", Toast.LENGTH_SHORT).show();
String search_username = object.getString("username");
String id = object.getObjectId();
Log.d("ObjectID:",id);
HashMap<String, Object> params = new HashMap<String, Object>();
params.put("recipientId", id);
params.put("message", username);
ParseCloud.callFunctionInBackground("sendPushToUser", params, new FunctionCallback<String>() {
public void done(String success, ParseException e) {
if (e == null) {
// Push sent successfully
Toast.makeText(getActivity(), "Request send", Toast.LENGTH_SHORT).show();
}
}
});
Then i have the next cloud function for recieve and push the message to the specific user.
Parse.Cloud.define("sendPushToUser", function(request,response){
var senderUser = request.user;
var recipientUserId = request.params.recipientId;
var message = request.params.message;
var title ="Friend Request";
if(message.length > 140){
message = message.substring(0, 137) + "...";
}
var recipientUser = new Parse.User();
recipientUser.id = recipientUserId;
var pushQuery = new Parse.Query(Parse.Installation);
pushQuery.equalTo("user", recipientUser);
Parse.Push.send({
where: pushQuery,
data: {
"alert":{"data":{"message":"message",
"title":"title"}}
}
}).then(function(){
response.success("true")
}, function(error) {
response.error("Push failed to send with error: "+error.message);
});
});
But the message never been received. If i sent a push notification from parse dashboard everything works fine. Anyone knows how to solve it? The device expect a JSON to received so may my cloud function didnt send data in json format? Thanks in advance

I had problems while sending notifications because of 2 things
enabling client push "not in your case"
didn't save the user in the installation "try the following"
After the user logs into your app add his id to the installation by
ParseInstallation installation = ParseInstallation.getCurrentInstallation();
installation.addUnique("userId", currentUser.getObjectId());
installation.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
// check the returned exception
if (e == null) {
// everything worked fine
} else {
// error occurred
}
}
});
hope it helps :)
Update
In your code you're sending the recipient userId although you saved the username also in your cloud function you have the same problem, the username is saved but you query the installation based on the id. I've updated the installation above also change the "user" in your cloud function to the "userId"
pushQuery.equalTo("userId", recipientUser);

Related

Parse Android: understanding cloud code and deploy

My app is simple as it requires four steps
Step 1:
UserA can create a questionnaire and send it to userB.
Step 2:
UserB receives the questionnaire with three options represented in radio button
Step 3:
UserB chooses the preferable answer that presented in radio button and click submit button
Step 4:
Upon clicking submit button userA receives an email with given answer from userB
However, I used parse for this app and I just started recently learning about cloud code and how to use it since I am trying to fetch sender's (UserA) email from User table but still I am not getting the desired results as I feel I am missing something
My main.js
Parse.Cloud.define("getEmail", function(request, response) {
Parse.Cloud.useMasterKey();
var userQuery = new Parse.Query(Parse.User);
var senderName = userEmail.get("senderId");
userQuery.equalTo("email", request.params.email);
userQuery.get("email", {
success: function(userEmail) {
// the object was retrieved
if ( email == senderName) {
status.message(email + "found");
return getEmail.save;
}
else {
status.message("Invalid email address");
}
},
error: function(object, error) {
status.error("something went wrong")
}
});
});
My android, cloud code function
private void callCodeCloud() {
HashMap<String, String> params = new HashMap<String, String>();
params.put("objectId", objectId);
params.put("email", email);
ParseCloud.callFunctionInBackground("getEmail", params, new FunctionCallback<String>() {
public void done(String email, ParseException e) {
if (e == null) {
Toast.makeText(getApplication(), "Vote Sent", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplication(), "Error", Toast.LENGTH_SHORT).show();
}
}
});
}
private String returnVoteAnswer() {
int nIdRadio = radioVoteGroup.getCheckedRadioButtonId();
if (nIdRadio == R.id.optionone) {
optionONE.setText(mO);
callCodeCloud();
}
else if (nIdRadio == R.id.optiontwo) {
optionTWO.setText(mT);
callCodeCloud();
}
else if (nIdRadio == R.id.optionthree) {
optionTHREE.setText(mH);
callCodeCloud();
}
else{
}
return null;
}
I have been really struggling with this for a while now and I need guidance please. It will be really great achievement for me and fresher by finishing this app as this problem has become an obstacle for me in finishing this app.
Thanks in advance

How to logout/change Twitter account with Parse

I know how to login:
ParseTwitterUtils.logIn(loginView.getCurrentContext(), new LogInCallback() {
#Override
public void done(ParseUser parseUser, ParseException e) {
if (e == null) {
String welcomeMessage = "";
if (parseUser.isNew()) {
welcomeMessage = "Hello new guy!";
} else {
welcomeMessage = "Welcome back!";
}
loginView.showLoginSuccess(parseUser, welcomeMessage);
} else {
String errorMessage = "Seems we have a problem : " + e.getLocalizedMessage();
loginView.showLoginFail(errorMessage);
}
}
});
And to logout :
ParseUser.logOutInBackground(new LogOutCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
homeView.goLogin(true, "See you soon");
} else {
homeView.goLogin(false, "Error detected : " + e.getLocalizedMessage());
}
}
});
But when I want to log in again, I don't have the alert dialog asking me to choose accounts (i use the webview since Twitter app is not installed on the emulator).
How to truly logout from Parse using Twitter login?
In iOS, you can revise the source code of Parse in PFOauth1FlowDialog.m
- (void)loadURL:(NSURL *)url queryParameters:(NSDictionary *)parameters {
NSMutableDictionary *_parameter = [[NSMutableDictionary alloc] init];
[_parameter setObject:#"true" forKey:#"force_login"];
[_parameter addEntriesFromDictionary:parameters];
_loadingURL = [[self class] _urlFromBaseURL:url queryParameters:_parameter];
NSURLRequest *request = [NSURLRequest requestWithURL:_loadingURL];
[_webView loadRequest:request];
}
Then everything should work fine, And this should also work in Android.
Use the unlink functions from ParseTwitterUtils:
https://parse.com/docs/android/api/com/parse/ParseTwitterUtils.html#unlink(com.parse.ParseUser)
This will remove the link between the twitter account and the parse user.
The confusion seems to stem from the fact that the api is so straightforward.
What you're doing in the login is associating a twitter account with a parse user and logging in as that parse user. Then when you are logging out, you are only logging out of the parse user, and the twitter account is still linked to the parse user. Therefore when you go to log in again it automatically uses the twitter account to log in as the parse user.

Android parse push notification and new GCM generate wrong device token and parse push notification not working

Brief : In parse installation table device token is not added properly when I use new GCM API.
right now following type of device token added into Parse installation table.
DeviceToken : |ID|1|:crGctxOB068:APA91bFgPRehabJcm9CYdS948iqX2_ppLj02CtbzmEHR0cfbuPooq5F--hqqvR9AH-Ez6MWMQON1Toc2DiNJTNdpRc3nmm3ukIpWJ1jHaXq0Iug6MoHbmKb9U0ak2CrKznkpKnPY5_Jp
Detailed description :
I have used new GCM api to get registration id.
I need that regId for internal use.
I have used code from following link of google: Google cloud messaging android.
I have noted one point. when ever I start app parse get deviceToken properly. After login I am updating "user" field using following code in onCreate of mainActivity
ParseACL acl = new ParseACL();
acl.setPublicReadAccess(true);
acl.setPublicWriteAccess(true);
ParseInstallation installation = ParseInstallation.getCurrentInstallation();
installation.setACL(acl);
if (ParseUser.getCurrentUser() != null) {
installation.put("user", ParseUser.getCurrentUser());
}
installation.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
Log.e("installation", "success");
Log.i("parse", "token after save : " + ParseInstallation.getCurrentInstallation().getString("deviceToken"));
ParsePush.subscribeInBackground("", new SaveCallback() {
#Override
public void done(ParseException e) {
if (e != null) {
Log.e("error: ", e.getLocalizedMessage());
e.printStackTrace();
} else {
Log.e("subscribed: ", "to broadcast channel");
Log.i("parse", "token after subscribe : " + ParseInstallation.getCurrentInstallation().getString("deviceToken"));
}
}
});
} else {
Log.e("installation", "failed");
e.printStackTrace();
}
}
});
Generally when above code run deviceToken got changed to Above mentioned token which seems wrong. So My push notification is not working.
I have solved issue.
I need to pass GCM device token to other webservice so I have used following code to get token from GCM.
InstanceID instanceID = InstanceID.getInstance(getApplicationContext());
String token = instanceID.getToken(CommonUtils.SENDER_ID,
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
After getting token from this code parse's deviceToken changed.
So instead of using above code I have used following code to get deviceToken and it solved the issue.
ParseInstallation.getCurrentInstallation().getString("deviceToken");

Android: How to input values to Parse cloud code, eg beforesave

Inside a app, users will upload slot results with period name to the Parse Database. However, before upload, it would be much preferred if beforesave, checked whether the period ref is already there, if the same period ref is existing in the DB, the slot result would not be uploaded.
Cloud.beforesave
Parse.Cloud.beforeSave("check_duplicate", function(request, response)
{
var DB = Parse.Object.extend("Record_db");
var query = new Parse.Query(DB);
query.equalTo("period_ref", request.object.get("period_ref"));
query.first
({
success: function(object)
{
if (object)
{
response.error("A Period with this ref already exists.");
}
else
{
response.success();
}
},
error: function(error)
{
response.error("Could not validate uniqueness for this period ref object.");
}
});
});
Android code:
ParseCloud.callFunctionInBackground("check_duplicate", new HashMap<String, Object>(), new FunctionCallback<String>() {
public void done(String result, ParseException e)
{
if (e == null)
{
Utilities.custom_toast(CurrentResult.this, "cloud success" + result, "gone!", "short");
}
else
{
Utilities.custom_toast(CurrentResult.this, "cloud error" + e, "gone!", "short");
}
}
});
Question:
There is no clear example for such common situation. I would like to ask
for example, now the user would like to upload slot ref 001/2015 results. All info are already available at device, how could I pass this period reference 001/2015 to the cloud code for checking whether it is already existing in the Cloud DB uploading and saving to the Cloud DB?
Thanks a lot!
your first line of Android...
ParseCloud.callFunctionInBackground("check_duplicate", new HashMap(), new FunctionCallback() {
becomes
ParseCloud.callFunctionInBackground("check_duplicate",
new HashMap<String, String>{"period_ref":"001/2015"};,
new FunctionCallback<String>() {

Parse.com ParseQuery inconstancy

I have a very weird situation. I have an application where I am implementing a "Notification History".
I have a separate application that sends push notifications to targeted channels and then creates an entry into a table called Notifications, saving the channel that was targeted and the message that was sent.
channels = channelEditText.getText().toString();
message = messageEditText.getText().toString();
ParsePush push = new ParsePush();
push.setChannel(channels);
push.setMessage(message);
push.sendInBackground();
channelEditText.setText("");
messageEditText.setText("");
ParseObject notifications = new ParseObject("Notifications");
notifications.add("channels", channels);
notifications.put("msg", message);
notifications.saveInBackground();
My Android app's "Notification History" fragment then performs
ParseQueryAdapter<ParseObject> notificationAdapter =
new ParseQueryAdapter<ParseObject>(getActivity(), new ParseQueryAdapter.QueryFactory<ParseObject>() {
public ParseQuery<ParseObject> create() {
ParseQuery query = new ParseQuery("Notifications");
query.whereContainedIn("channels", ParseInstallation.getCurrentInstallation().getList("channels"));
query.orderByDescending("createdAt");
return query;
}
});
notificationAdapter.setTextKey("msg");
ListView notificationListView = (ListView) rootView.findViewById(R.id.notificationListView);
notificationListView.setAdapter(notificationAdapter);
My ParseApplication.java subscribes a user to channel: "Welcome" on installation so I don't receive a null pointer. The Notifications Table entry with channel "Welcome" populates the listview.
I have two ways to subscribe to a channel. One way is on the device itself like this
final EditText syncInput = (EditText) rootView.findViewById(R.id.syncInput);
Button syncButton = (Button) rootView.findViewById(R.id.syncButton);
syncButton.setOnClickListener(new OnClickListener() {
public void onClick(View v){
String sync = null;
sync = syncInput.getText().toString();
PushService.subscribe(getActivity(), sync, DashboardActivity.class);
syncInput.setText("");
}
});
The other way is through CloudCode
Parse.Cloud.define("subscribeToChannel", function(request, response){
var channelName = request.params.channel;
var userId = request.params.userId;
if(!channelName) {
response.error("Missing parameter: channel");
return;
}
if (!userId) {
response.error("Missing paremeter: userId");
return;
}
//Create a Pointer to the user based on their object id
var user = new Parse.User();
user.id = userId;
Parse.Cloud.useMasterKey();
// A user might have more than one installation
var query = new Parse.Query(Parse.Installation);
query.equalTo("user", user); //Match Installations with a pointer to this User
query.find({
success: function(installations) {
for (var i = 0; i < installations.length; i++) {
//Add the channel to al the installations for this user
installations[i].addUnique("channels", channelName);
}
//Save all the installations
Parse.Object.saveAll(installations, {
success: function(installations) {
//All the installations where saved.
response.success("All the installations were updated with this channel.");
},
error: function(error) {
//An error occured while saving one of the objects.
console.error(error);
response.error("An error occured while updating this user's installations.");
}
});
},
error: function(error) {
console.error(error);
response.error("An error occurred while looking up this user's installations");
}
});
});
Both ways of subscribing are successful in that a Push notification sent to the target channel reaches the device. Here is the issue... If I use the device to subscribe my query will show the messages sent to that channel that is saved in the Notifications table. If I use the CloudCode my query does NOT show the message sent to the channel that is saved in the Notification table.
I'm stumped. Any help is deeply appreciated.
--------------------------------SOLUTION-------------------------------------------------
protected void onResume() {
super.onResume();
ParseInstallation.getCurrentInstallation().refreshInBackground(new RefreshCallback(){
#Override
public void done(ParseObject parseObject, ParseException e) {
List<String> channels = ParseInstallation.getCurrentInstallation().getList("channels");
for (int i = 0; i < channels.size(); i++) {
Log.w("TEST", channels.get(i));
}
}
});
}
You're editing the Installation record on the server-side in Cloud Code, but the device isn't getting the updated data. If this is a common behavior in your app, refresh the installation object when you load the app:
ParseInstallation.getCurrentInstallation().refreshInBackground();
or fetchInBackground, as shown here: https://parse.com/docs/android_guide#objects-retrieving
This could also be solved by, instead of querying from the device, calling a cloud function which does the query (with the updated channels list already on the server-side.)

Categories

Resources