Skip to content

Instantly share code, notes, and snippets.

@OneCricketeer
Last active January 25, 2022 06:36
Show Gist options
  • Save OneCricketeer/10001273 to your computer and use it in GitHub Desktop.
Save OneCricketeer/10001273 to your computer and use it in GitHub Desktop.
Targeted Push Notifications: Parse.com Cloud Code
// Use Parse.Cloud.define to define as many cloud functions as you want.
// For example:
Parse.Cloud.define("hello", function(request, response) {
response.success("Hello world!");
});
Parse.Cloud.define("userWithEmailExists", function(request, response) {
var email = request.params.email;
if (email != null && email !== "") {
email = email.trim();
} else {
response.error("Must provide \"email\" in JSON data");
return;
}
var logMessage = "Checking for email \"{0}\"".format(email);
console.log(logMessage);
// Find users with a given email
var userQuery = new Parse.Query(Parse.User);
userQuery.equalTo("email", email);
userQuery.find({
success: function(results) {
if (results.length > 0) {
response.success('true');
} else {
response.success('false');
}
},
error: function(error) {
response.error(error);
}
});
});
Parse.Cloud.define("getUserWithEmail", function(request, response) {
var emailParam = request.params.email;
// Check if email exists and return associated user
Parse.Cloud.run("userWithEmailExists", {
email: emailParam
}, {
success: function(booleanObj) {
if (JSON.parse(booleanObj)) {
// Find users with a given email
var userQuery = new Parse.Query(Parse.User);
userQuery.equalTo("email", emailParam);
userQuery.first({
success: function(object) {
response.success(object);
}
});
} else {
response.error("User with email does not exist");
}
},
error: function(error) {
response.error(error);
}
});
});
Parse.Cloud.define("pushToEmail", function(request, response) {
var emailParam = request.params.email;
var message = request.params.message;
if (message != null && message !== "") {
message = message.trim();
} else {
response.error("Must provide \"message\" in JSON data");
return;
}
// Can see this at https://www.parse.com/apps/{APP_NAME}/cloud_code/log
var logMessage = "Sending \"{0}\" to {1}".format(message, emailParam);
console.log(logMessage);
// Check if email exists and send notification
Parse.Cloud.run("userWithEmailExists", {
email: emailParam
}, {
success: function(booleanObj) {
if (JSON.parse(booleanObj)) {
// Find users with a given email
var userQuery = new Parse.Query(Parse.User);
userQuery.equalTo("email", emailParam);
var pushQuery = new Parse.Query(Parse.Installation);
// pushQuery.containedIn("deviceType", ["ios", "android"]); // errors if no iOS certificate
pushQuery.exists("user"); // filter out installations without users
pushQuery.include('user'); // expand the user pointer
pushQuery.matchesQuery("user", userQuery);
// Send push notification to query
Parse.Push.send({
where: pushQuery, // Set our installation query
data: {
alert: message
}
}, {
success: function() {
// Push was successful
console.log("Message was sent successfully");
response.success('true');
},
error: function(error) {
response.error(error);
}
});
} else {
response.error("User with email does not exist");
}
},
error: function(error) {
response.error(error);
}
});
});
Parse.Cloud.define("pushToAll", function(request, response) {
var message = request.params.message;
if (message != null && message !== "") {
message = message.trim();
} else {
response.error("Must provide \"message\" in JSON data");
return;
}
// Can see this at https://www.parse.com/apps/{APP_NAME}/cloud_code/log
var logMessage = "Sending \"{0}\" to all installations".format(message);
console.log(logMessage);
var pushQuery = new Parse.Query(Parse.Installation);
// pushQuery.containedIn("deviceType", ["ios", "android"]); // errors if no iOS certificate
// Send push notification to query
Parse.Push.send({
where: pushQuery, // Set our installation query
data: {
alert: message
}
}, {
success: function() {
// Push was successful
console.log("Message was sent successfully");
response.success('true');
},
error: function(error) {
response.error(error);
}
});
});
if (!String.prototype.format) {
String.prototype.format = function() {
var args = arguments;
return this.replace(/{(\d+)}/g, function(match, number) {
return typeof args[number] != 'undefined' ?
args[number] :
match;
});
};
}
@TonyTangAndroid
Copy link

In Google Cloud Message, the maximum length of the message in a push notification is 4K. If it is over that, Client won't be able to receive the push notification. How to get the size of a Parse Object in Cloud code?

@OneCricketeer
Copy link
Author

OneCricketeer commented Aug 20, 2015

I'm by no means a pro at JavaScript, but perhaps this may work.

Source: http://jsperf.com/utf-8-byte-length

function byteLength(str) {
  // returns the byte length of an utf8 string
  var s = str.length;
  for (var i=str.length-1; i>=0; i--) {
    var code = str.charCodeAt(i);
    if (code > 0x7f && code <= 0x7ff) s++;
    else if (code > 0x7ff && code <= 0xffff) s+=2;
  }
  return s;
}

function getObjectSize(obj) {
  return byteLength(JSON.stringify(obj.toJSON());
}

@mikeandike
Copy link

What do the method calls look like? What values/types do you pass in for request and response?

@OneCricketeer
Copy link
Author

Sorry @mikeandike, I would respond faster if there were notification on these comments.

  1. It depends on the language... typically, though, any SDK I have seen follows the pattern of Parse.Cloud.callFunction("functionName", paramMap, functionCallback).
    In Javascript, see line 38 where I call the previously defined function userWithEmailExists. I pass in { email: emailParam } for the request.params and have a function map for success & error, which are triggered according to response.success() or response.error() in the called function's definition.

Sidenote: I think getting parameters for a Web request using request.params is just a common practice for Web frameworks; you are acting ON the request, not passing anything into it directly. Similarly, for the response, it simply provides a way to pass data back to the calling function via success() and error().

  1. In client code, the request is an associative array/dictionary/hashmap/etc. The response function is either a function map of {success(), error()}, some reactive component of onSuccess and onError, or simply boolean checking via if (error) { ... } else { ... }. For each, the logic is up to you to define. For example, in line 40, I needed to parse the boolean values from lines 23 & 25. I don't know if/how multiple parameters can be passed to the callback functions. In the event I needed to, though, I typically would just return a JSON string and parse it out client-side.

The Parse.com documentation has changed quite a bit since I implemented this, but the official Cloud Code documentation does a good job explaining the essentials.

For the Java/Android API, see Parse Android API - ParseCloud.
And for iOS, see Parse iOS API - PFCloud

@OneCricketeer
Copy link
Author

OneCricketeer commented Mar 6, 2016

Notice

For those finding this post-shutdown of Parse.com, there is no guarantee it'll work on the new Parse Server (or any service that hosts it)

Contact me with questions

Instead of commenting below, if you would like assistance or have questions, preferably ask on StackOverflow. My username is cricket_007, and you can tag @cricket_007 in the comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment