Parse Cloud Code: Can you pass objects in a push notification? - javascript

I'm creating a push notification similar to this sample code provided by Parse:
Parse.Cloud.afterSave('Activity', function(request) {
if (request.object.get("type") === ("comment") {
var message = request.user.get('displayName') + ': ';
message += request.object.get('content').trim();
var query = new Parse.Query(Parse.Installation);
query.equalTo('user', request.object.get("toUser"));
Parse.Push.send({
where:query,
data: {
alert: message,
badge: 'Increment'
}
});
}
});
My question is: in the data area of the Parse.Push.send, can I send an entire message object, where Message is a custom class I created? If so, what would that look like?

If you already have the class created and saved an object why not just send the object ID and query it asynchronously once the user goes to retrieve the push notification?
The message object does not need to waste up space and be sent via push just a pointer is required.
I'm in the process of implementing something similar and this is the route I plan to use.

You can serialize the object in JSON/XML format and then deserialize it when you receive the push notification.

You can't send objects directly. You'll get an exception (I had this issue a few days ago but didn't write the name of the exception down). The best answer is so far is by BrentonGray88.
I'm assuming you're not using Android because you included the badge: "Increment" value, but this is how I would do it:
Android code to send the notification:
Make sure the Comment object has a pointer (_User) column to the User who sent the comment. When you create the comment, include user.put("commentAuthor", ParseUser.getCurrentUser()); in your Android code so that you can always access the user who created the comment.
Now you need to query the Comment to send its objectId through to the push notification.
ParseQuery<ParseObject> query = new ParseQuery<>("Comment");
query.whereEqualTo("objectId", I AM NOT SURE WHAT CONDITION YOU WANT HERE);
query.findInBackground((comment, e) -> {
if (e == null) for (ParseObject commentObject: comment) {
String recipientObjectId = commentObject.getParseObject("commentAuthor").getObjectId();
final Map<String, Object> params = new HashMap<>();
// This is to send the notification to the author of the Comment
params.put("recipientObjectId", recipientObjectId);
// This is so we can use values from the Comment in the notification
params.put("commentObjectId", commentObject.getObjectId());
// This is a required lined
params.put("useMasterKey", true);
ParseCloud.callFunctionInBackground("pushMessage", params, new FunctionCallback<String>() {
public void done(String result, ParseException e) {
if (e == null) {
Log.d(getClass().toString(), "ANNOUNCEMENT SUCCESS");
} else {
System.out.println(e);
Log.d(getClass().toString(), "ANNOUNCEMENT FAILURE");
}
}
});
}
});
Now for the query in your Cloude Code:
Parse.Cloud.define("pushMessage", function (request, response) {
// Again, we are sending the notification to the author of the Comment
var pushQuery = new Parse.Query(Parse.Installation);
pushQuery.equalTo('user', request.params.get("recipientObjectId"));
// We retrieve information from the Comment created by that author
var commentQuery = new Parse.Query(Parse.Comment);
commentQuery.equalTo('objectId', request.params.commentObjectId);
commentQuery.get("commentObjectId", {
success: function(userObject) {
var displayName = userObject.get("displayName");
var content = userObject.get("content");
var message = displayName + ': ';
message += content.trim();
Parse.Push.send({
where: pushQuery,
data: {
alert: message
},
}, {
useMasterKey: true,
success: function () {
response.success("Success!");
},
error: function (error) {
response.error("Error! " + error.message);
}
});
console.log();
},
error: function(error) {
console.log("An error occured :(");
}
});
});
Sorry I'm not the best at JavaScript but that's kind of how I'd do it. Best of luck! :)

Related

Creating Parse.Object new parse server

I am using the new open source parse server and this is what I have in the main.js for creating a object.
Parse.Cloud.define("purchaseItem", function(request, response) {
Parse.Cloud.useMasterKey();
var order, custom;
Parse.Promise.as().then(function() {
var fullreceipt;
var receiptData = new Array();
receiptData = request.params.receipt.titles;
if(receiptData){
console.log('value of recept data is good');
}
if (!receiptData){
console.log('Value of receiptData is empty');
}
for (var i = 0; i < receiptData.length; i++) {
console.log(receiptData[i]);
fullreceipt = receiptData[i];
console.log(fullreceipt);
//Do something
}
var currentUser = Parse.User.current();
order = new Parse.Object('Order');
order.set('name', request.params.name);
order.set('email', request.params.email);
order.set('address', request.params.address);
order.set('zip', request.params.zip);
order.set('city_state', request.params.city_state);
order.set('fulfilled', false);
order.set('charged', false); // set to false until we actually charge the card
order.set('user', currentUser);
order.set('receipt', request.params.receipt);
order.set('tipAmount', request.params.tipAmount);
order.set('taxAmount', request.params.taxAmount);
order.set('orderInstructions', request.params.instructions);
order.set('pickupOrDelivery', request.params.pickupOrDelivery);
order.set('totalBillAmount', request.params.totalBill);
return order.save().then(null, function(error) {
console.log('Creating order object failed. Error: ' + error);
return Parse.Promise.error('An error has occurred. Your credit card was not charged.' + order);
});
}
}
In the logs I get value of recept data is good but creating the object fails and I get the error message, Creating order object failed. Error: [object Object]
. If any one cloud help that would be great!
I looks like found my own answer in a error message. What was going wrong was I need to point it to the new parse server on AWS api and not the old parse api.

Basic Parse query to access a field inside a pointer object in JavaScript

I have a table called "Current1", which I am saving user's object as pointer like this:
When I click on this pointer I direct to _User table. Now I am trying to do very simple query. I need to access to username inside user pointer and later update something in _User table.
My problem is now to access 'username' in '_User' table by using a pointer:
var aveGame2 = Parse.Object.extend("Current1");
var query2 = new Parse.Query(aveGame2);
query2.include("user");
query2.find({
success: function(results) {
for (var i = 0; i < results.length; i++)
{
var object = results[i];
//....
var user = object.get('user');
var username = user.get('username'); //<--Error is pointing to this line
//More operation
if(True)//Some conditions
{
Parse.Cloud.useMasterKey();
var query = new Parse.Query(Parse.User);
query.equalTo("username", username);
// Get the first user which matches the above constraints.
query.first({
success: function(anotherUser) {
anotherUser.set("prize", 10);
// Save the user.
anotherUser.save(null, {
success: function(anotherUser) {
// The user was saved successfully.
response.success("Successfully updated user.");
},
error: function(gameScore, error) {
// The save failed.
// error is a Parse.Error with an error code and description.
response.error("Could not save changes to user.");
}
});
},
error: function(error) {
response.error("Could not find user.");
}
});
Error:
[Error]: TypeError: Cannot call method 'get' of undefined
at e.query2.find.success
After hours of checking each fields I realised I have not set ACL for _User table as Public read. This might help someone else.

Parse Cloud Code - Only Retrieve Certain Columns Before Sending Response.

I currently have this cloud code to retrieve all the users that have a relation with the current user. I have to first find the current user then query the "Friends" column hence the relational query step.
The line response.success(results) returns all the attributes of all of the current user's friends. I only want a few of the columns that belong to these friends, not every single thing they saved when signing up.
Parse.Cloud.define("getFriends", function(request, response) {
var userId = request.params.UserKey;
var query = new Parse.Query(Parse.User);
query.ascending("updatedAt");
query.get(userId, {
success: function(foundCurrentUser) {
var currentUser = foundCurrentUser;
var relation = currentUser.relation("Friends");
var getRelationQuery = relation.query();
getRelationQuery.find().then(function(results) {
response.success(results);
});
},
error: function(error) {
response.error(error);
}
});
});
I am using swift to to use the response, I am not sure that if I need to tweak the swift code but will provide it anyway.
func LoadCarpoolersFromParse(Success:(object:AnyObject)->(),Failure:(error:NSError)->())
{
let params = NSMutableDictionary()
params.setObject(PFUser.currentUser()!.objectId!, forKey: "UserKey")
PFCloud.callFunctionInBackground("getCarpoolers", withParameters: params as [NSObject : AnyObject], block: {
(response:AnyObject?, error: NSError?) -> Void in
if error == nil {
Success(object: response!)
}
else{
Failure(error:error!)
}
})
}
}
You can do it by using select method of Parse.Query, make the following changes in your cloud code
Parse.Cloud.define("getFriends", function(request, response) {
var userId = request.params.UserKey;
var query = new Parse.Query(Parse.User);
query.ascending("updatedAt");
query.select("name","phone"); // replace with your required fields

Cannot create a pointer to an unsaved ParseObject

I am having troubles referring to a "User" object from inside a query. I have the following code:
Parse.Cloud.define("getTabsBadges", function(request, response) {
var UserObject = Parse.Object.extend('User');
var user = new UserObject();
user.id = request.params.userId;
// Count all the locked messages sent to the user
var receivedMessagesQuery = new Parse.Query('Message');
receivedMessagesQuery.equalTo('status', 'L');
receivedMessagesQuery.equalTo('toUser', user); // THIS LINE GENERATES THE ERROR
receivedMessagesQuery.count({
// more code here
});
});
I call the function using CURL but I always get the following error:
{"code":141,"error":"Error: Cannot create a pointer to an unsaved
ParseObject\n at n.value (Parse.js:14:4389)\n at n
(Parse.js:16:1219)\n at r.default (Parse.js:16:2422)\n at e.a.value
(Parse.js:15:1931)\n at main.js:9:25"}
I am using the exactly same code in another project, the only difference is that instead of counting objects I find them and its works correctly. I have also verified that the tables have a column type of Pointer<_User> in both projects. What's causing the problem?
The error message Cannot create a pointer to an unsaved means that you are trying to use an object which does not exist in the Parse DB.
With var user = new UserObject();, you're creating a new user object. You cannot use it in a query until you save it to Parse.
Instead of creating a new User object and setting it's objectId, do a query for the User object. See code below:
Parse.Cloud.define("getTabsBadges", function(request, response) {
var UserObject = Parse.Object.extend('User');
var query = new Parse.Query(UserObject);
query.get(request.params.userId, {
success: function(user) {
// Count all the locked messages sent to the user
var receivedMessagesQuery = new Parse.Query('Message');
receivedMessagesQuery.equalTo('status', 'L');
receivedMessagesQuery.equalTo('toUser', user); // THIS LINE GENERATES THE ERROR
receivedMessagesQuery.count({
// more code here
});
},
error: function(error) {
// error fetching your user object
}
});
});
Your request.params.userId may be undefined or null, which causes this error.
Your query constraints cannot compare the Parse Object that is created without data (createWithoutData()) using undefined or null as its objectId.

Create Installation object from Cloud code with Parse

As documentation says - "The JavaScript SDK does not currently support modifying Installation objects.", but what about creating these objects? is it possible to create Installation objects from cloud code?
For ex:
Parse.Cloud.define("registerForNotifications", function(request,response) {
var token = request.params.deviceToken;
var deviceType = request.params.deviceType;
var user = request.user;
var installation = new Parse.Object("Installation");
if (installation) {
installation.set("deviceToken",token);
... so on..
installation.save();
}
});
Will this work? Thank you.
Some example:
//The following Cloud Function expects two parameters: the channel to be added to this user's installations, and the object id for the user.
//It assumes that each installation has a `Pointer <_User>` back to the original user.
//...
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 parameter: userId")
return;
}
// Create a Pointer to this user based on their object id
var user = new Parse.User();
user.id = userId;
// Need the Master Key to update Installations
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 all the installations for this user
installations[i].addUnique("channels", channel);
}
// Save all the installations
Parse.Object.saveAll(installations, {
success: function(installations) {
// All the installations were saved.
response.success("All the installations were updated with this channel.");
},
error: function(error) {
// An error occurred while saving one of the objects.
console.error(error);
response.error("An error occurred while updating this user's installations.")
},
});
},
error: function(error) {
console.error(error);
response.error("An error occurred while looking up this user's installations.")
}
});
});

Categories

Resources