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>() {
Related
Is there a way to count the number of Parse installations records?
I could not query in my App so I did it using cloud code. But still I can't query.
I'd like to count the number of installations per versionNumber and show this in my Admin Activity in the App.
Any Suggestions?
Error when trying to do a count via cloudecode:
- Clients aren't allowed to perform the find operation on the installation collection.
- Error generating response. ParseError {
code: 141,
message: 'Clients aren\'t allowed to perform the find operation on the installation collection.' }
Key to the solutions was adding: useMasterKey: true
Parse.Cloud.define("countInstallations", function(request, response) {
var qInstallation = new Parse.Query(Parse.Installation);
var sVersion = request.params.version;
var sResult = "";
qInstallation.equalTo("versionNumber",parseInt(sVersion));
qInstallation.count({
useMasterKey: true,
success: function(number) {
sResult = number;
response.success(sResult);
},
error: function(error) {
response.error(0);
}
});
});
From my App I call this cloud function like this which will return the count for version 39.
Map<String, String> parameters = new HashMap<String, String>();
parameters.put("version","39");
try {
Log.d("MyApp","result:" +ParseCloud.callFunction("countInstallations",parameters));
} catch (ParseException e) {
e.printStackTrace();
}
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);
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
I have created a parse cloud beforeSave trigger for the predefined class ParseInstallation in order to delete duplicate parse installations for the same user, kinda like what is on this gist. My deployed cloud code is the following:
Parse.Cloud.beforeSave(Parse.Installation, function(request, response) {
Parse.Cloud.useMasterKey();
var query = new Parse.Query(Parse.Installation);
//PROBLEM: request.object.get("username") is undefined...
query.equalTo("username", request.object.get("username"));
query.first().then(function(duplicate) {
if (typeof duplicate === "undefined") {
console.log("Duplicate does not exist, New installation");
response.success();
} else {
console.log("Duplicate exist..Trying to delete " + duplicate.id);
duplicate.destroy().then(function(duplicate) {
console.log("Successfully deleted duplicate");
response.success();
}, function() {
console.log(error.code + " " + error.message);
response.success();
});
}
}, function(error) {
console.warn(error.code + error.message);
response.success();
});
})
The problem, as it is commented inline on the code, is that the request.object.get("username") returns undefined. In fact, all the properties of request.object are undefined!
On my android client app I associate the ParseUser and also the username to the ParseInstallation object, as follows:
user.signUpInBackground(new SignUpCallback() {
public void done(ParseException e) {
if (e == null) {
ParseInstallation installation = ParseInstallation.getCurrentInstallation();
installation.put("username", username);
installation.put("user", user);
installation.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if(e == null) {
Log.e(TAG, "Parse installation was created successfully!");
} else {
Log.e(TAG, "An error occurred while saving Parse installation: " + e.toString());
}
}
});
//more code...
} else {
Log.e(TAG, "Signup error: " + e.getMessage());
//more code...
}
}
});
So, given the above, one would expect that, on the parse cloud, request.object.get("username") would return the actual user username and not undefined, correct??? (Btw, yes I have checked that the username variable on the android client code is not null nor empty!)
Why the hell request.object properties are all undefined???
How to get username from ParseInstallation on the cloud trigger then???
Also, did anyone experienced this problem from an IOS client app?
Retrieve the username through the request.user object:
var User = request.user;
console.log(User.get("username"));
//or skip the first step:
console.log(request.user.get("username"));
Note you can also retrieve these values by calling the attributes property of the Parse.Object (typically bad practice):
console.log(request.user.attributes.username);
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.)