Tried loads of different variations with my cloud code and I can't get it to work. Basically I've got a push notification function, and in this function I want to add an object to a PFUser's array, but you can't use a master key in Xcode so here's what I have:
Parse.Cloud.define("iOSPush", function (request, response) {
console.log("Inside iOSPush");
var data = request.params.data;
var not_class = request.params.not_class;
var not_objectid = request.params.not_objectid;
var not_date = request.params.not_date;
var userid = request.params.userid;
var recipientUser = new Parse.Query(Parse.User);
recipientUser.equalTo("objectId", userid);
// set installation query:
var pushQuery = new Parse.Query(Parse.Installation);
pushQuery.equalTo('deviceType', 'ios');
pushQuery.matchesQuery('user', recipientUser);
pushQuery.find({ useMasterKey: true }).then(function(object) {
response.success(object);
console.log("pushQuery got " + object.length);
}, function(error) {
response.error(error);
console.error("pushQuery find failed. error = " + error.message);
});
// send push notification query:
Parse.Push.send({
where: pushQuery,
data: data
}, { useMasterKey: true }).then(function() {
console.log("### push sent!");
// create notification:
var notification = {
"title": not_class,
"body": request.params.data.alert,
"class": not_class,
"objectId": not_objectid,
"date": not_date
};
// get notifications:
var tmp_notifications = recipientUser.get("notifications");
// add notification:
tmp_notifications.push(notification);
// update with notifications:
recipientUser.set("notifications", tmp_notifications);
recipientUser.save();
}, function(error) {
console.error("### push error" + error.message);
});
response.success('success. end of iospush');
});
The Xcode cloud function I have provides the correct information, the function gets to the end.. just the function is not setting the notifications for some reason
I ended up figuring out the answer to this post myself. The reason this didn't work is because I needed to first fetch the user object in a separate query, then save it using the master key. I also found out that there's a function for appending data onto an existing array without having to create another one (parseObject.add()):
var userQ = new Parse.Query(Parse.User);
userQ.get(userid, {
success: function(theuser) {
console.log("### got userrrrrrrrrr!");
theuser.add("notifications", n_object);
theuser.save(null, {useMasterKey:true});
},
error: function(object, error) {
// The object was not retrieved successfully.
// error is a Parse.Error with an error code and message.
}
});
This set of code was executed just before:
response.success('success. end of iospush');
Related
Im trying to sign a Bitcoin testnet transaction using blockcypher and the bitcoinjs lib described here, but I have run into this error and I am not usre what I am doing wrong.
{"error": "Couldn't deserialize request: invalid character 'x' in literal true (expecting 'r')"}
When searching around I cannot find a solution to the problem, I have contacted blockcypher but they never respond. Here is the code im using to sign the transaction, does anyone know why its giving me this error?
var bitcoin = require("bitcoinjs-lib");
var buffer = require('buffer');
var keys = new bitcoin.ECPair.fromWIF('cMvPQZiG5mLARSjxbBwMxKwzhTHaxgpTsXB6ymx7SGAeYUqF8HAT', bitcoin.networks.testnet);
var newtx = {
inputs: [{addresses: ['ms9ySK54aEC2ykDviet9jo4GZE6GxEZMzf']}],
outputs: [{addresses: ['msWccFYm5PPCn6TNPbNEnprA4hydPGadBN'], value: 1000}]
};
// calling the new endpoint, same as above
$.post('https://api.blockcypher.com/v1/btc/test3/txs/new', JSON.stringify(newtx))
.then(function(tmptx) {
// signing each of the hex-encoded string required to finalize the transaction
tmptx.pubkeys = [];
tmptx.signatures = tmptx.tosign.map(function(tosign, n) {
tmptx.pubkeys.push(keys.publicKey.toString("hex"));
const SIGHASH_ALL = 0x01;
return bitcoin.script.signature.encode(keys.sign(new buffer.Buffer(tosign, "hex")), SIGHASH_ALL,).toString("hex");
});
// sending back the transaction with all the signatures to broadcast
$.post('https://api.blockcypher.com/v1/btc/test3/txs/send', tmptx).then(function(finaltx) {
console.log(finaltx);
}).catch(function (response) {
console.log(response.responseText);
});
}).catch(function (response) {
console.log(response.responseText);
});
I’m having an issue with my project. In my angularjs controller a function is being executed and then my function to make a call to my database to update a record is executing without waiting for the first function to complete and therefore sending over an undefined result variable.
Below you can find my code snippets with my attempts so far.
Submit button function:
$scope.submitNewStarters = function () {
// result is returning as undefined <<<<< Issue
var result = $scope.sendNewStarterDetailsToApi();
$scope.updateArchivedImportFlag(result);
};
Controller function handling the logic:
$scope.sendNewStarterDetailsToApi = function () {
swal({
title: "Confirmation",
text: "Are you sure you want to import the new starter details?",
icon: "info",
dangerMode: true,
buttons: ["No", "Yes"]
}).then(function (approve) {
if (approve) {
// Get each of the new starter details that have been set to true for import.
var newStartsToImport = $scope.tableParams.data.filter(x => x.imported == true);
for (let i = 0; i < newStartsToImport.length; i++) {
// Parses the current new starter object into a stringified object to be sent to the api.
$scope.newStartsToImport = $scope.createApiObject(newStartsToImport[i]);
// A check to ensure that nothing has went wrong and that the stringify object has worked.
if ($scope.newStartsToImport !== "") {
apiFactory.postNewStarterDetailsToApi($scope.newStartsToImport).then(function (response) {
var isSuccessful = response.data.d.WasSuccessful;
if (isSuccessful)
toastr.success("New starter details successfully sent to API.", "Success!");
else {
var errorMessage = response.data.d.ErrorMessage;
toastr.error("New starter details were unsuccessfully sent to API. Please try again. \n" + errorMessage, "Error!");
}
});
}
else {
toastr("An error has occurred when attempting to create the data object to be sent to API. The process has stopped!", "Error!");
break;
}
}
return newStartsToImport;
}
else
toastr.info("No new starter details were sent to API", "Information!");
});
};
Factory function for API call:
postNewStarterDetailsToApi: function (data) {
return $http({
url: "https://www.example.com/services/service.svc/Import",
method: "POST",
data: data,
headers: {
'Content-Type': 'application/json; charset=utf-8',
}
}).then(function successCallbwack(response) {
// this callback will be called asynchronously
// when the response is available
return response;
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
console.log('An error has occured during the function call postNewStarterDetailsToApi(): ', response);
});
}
So with the concept of promises how am I able to execute the sendNewStarterDetailsToApi function, wait for it to complete and then return the populated array? Once the populated array (result) is returned then execute the updateArchivedImportFlag function.
Below I've added an illustration of what I'd like to achieve:
The approach I am using is , save all the promises in an array .
Use any promise library or es6 Promise, and use .all function to wait for all promises to execute
The syntax i wrote is not totally correct. Since you are using angular js , you can use $q.all
$scope.sendNewStarterDetailsToApi = function () {
swal({
title: "Confirmation",
text: "Are you sure you want to import the new starter details?",
icon: "info",
dangerMode: true,
buttons: ["No", "Yes"]
}).then(function (approve) {
var res = [];
if (approve) {
// Get each of the new starter details that have been set to true for import.
var newStartsToImport = $scope.tableParams.data.filter(x => x.imported == true);
for (let i = 0; i < newStartsToImport.length; i++) {
// Parses the current new starter object into a stringified object to be sent to the api.
$scope.newStartsToImport = $scope.createApiObject(newStartsToImport[i]);
// A check to ensure that nothing has went wrong and that the stringify object has worked.
if ($scope.newStartsToImport !== "") {
res.push(apiFactory.postNewStarterDetailsToApi($scope.newStartsToImport))
}
else {
toastr("An error has occurred when attempting to create the data object to be sent to API. The process has stopped!", "Error!");
break;
}
}
return Promise.all(res);
}
else
toastr.info("No new starter details were sent to API", "Information!");
}).then(function (data) {
data.forEach((response) => {
var isSuccessful = response.data.d.WasSuccessful;
if (isSuccessful)
toastr.success("New starter details successfully sent to API.", "Success!");
else {
var errorMessage = response.data.d.ErrorMessage;
toastr.error("New starter details were unsuccessfully sent to API. Please try again. \n" + errorMessage, "Error!");
}
})
}).then((res) => {
//call Submit new starters
})
};
I am attempting to update a parse user field and the function stops in the middle of it:
Parse.Cloud.define("modifyAdminStatus", function(request, response) {
var userQuery = new Parse.Query(Parse.User);
var isAdmin = request.params.adminStatus;
console.log("isAdmin:" + isAdmin);
userQuery.equalTo("username", request.params.username);
userQuery.find({ useMasterKey: true,
success: function(user) {
console.log(user.length);
console.log("Got User")
console.log(user);
user.set("isAdmin", isAdmin);
console.log("Set Status");
user.save(null, {useMasterKey: true,
success: function(user) {
response.success();
},
error: function(error) {
response.error(error.message);
}
});
},
error: function(error) {
response.error(error.message);
}
});
});
I dont get any syntax errors, when i run the code i get:
1
Got User
[ ParseUser { _objCount: 2, className: '_User', id: '2vigcitsl6' } ]
in my console. However, it seems to stop the code after i attempt to set the admin status. I have tried running it using useMasterKey but that didnt do anything so maybe I'm missing something and where the useMasterKey should go?
The answer is:
query.find({
... code here
});
Returns an array, using query.first (or selecting one object from the array) instead will get one object and allow you to set things on it.
When you're trying to save the user, parse expects two parameters. The first should be an object containing any changes, and the second should be the save options.
So in your case, simply change your save to user.save (null, {useMasterKey:true, success...})
The way you have it now would create a column on Parse.User entitled useMasterKey, if permissions allow.
i am using this
var USER = Parse.Object.extend("_User");
var query = new Parse.Query(USER);
query.get(request.user.id, {
success: function(results) {
console.log(results);
// results has the list of users with a hometown team with a winning record
},
error : function(error){
console.error(error);
}
to fetch the user making the request. (In this case it's a after save hook)
For any reason "results" just containing:
ParseObjectSubclass { className: '_User', _objCount: 2, id: 'zW3o9c2wbY' }
But i need access to other fields of this user - how can i do so?
Best, Nico
see query documentation the include method is what you are looking for.
Fyi, here's how I would write it:
new Parse.Query(Parse.User)
.include('ptrFieldIWantReturned')
// master key shouldn't be needed, but I can't be sure of your config.
.get(request.user.id, { useMasterKey: true })
.then(
user => console.log('got: ' + user.id),
error => console.error('uh-oh: ' + error.message)
);
I am trying to implement the advanced push targeting from cloud code (background job) using parse.com service. I have added the day as a field in the Installation object.
I made it work if I have only one condition, i.e. day equals 1, using following snippet
var pushQuery = new Parse.Query(Parse.Installation);
pushQuery.equalTo("day",1);
Parse.Push.send({
where: pushQuery,
data: {
"content-available" : "1",
alert : "Message day 1!",
sound : "default"
}}, {
success: function() {
// Push was successful
},
error: function(error) {
// Handle error
}}).then(function() {
// Set the job's success status
status.success("Job finished successfully.");
}, function(error) {
// Set the job's error status
status.error("Uh oh, something went wrong.");
});
Reference: Push Notification Java Script guide
My next step is sending notifications to 20 queries (0 <= day < 20) and for each query send message according to day number. Calling function 20 times seems to me ugly, may I anyhow iterate, calling each time in loop Parse.Push.send function?
I solved my problem using Parse.Promise.when(promises)
Promises are a little bit magical, in that they let you chain them without nesting. If a callback for a promise returns a new promise, then the first one will not be resolved until the second one is. This lets you perform multiple actions without incurring the pyramid code you would get with callbacks.
function scheduleWordsForDay(day)
{
var pushQuery = new Parse.Query(Parse.Installation);
pushQuery.equalTo("day",day);
pushQuery.exists("deviceToken");
var promise = new Parse.Promise();
Parse.Push.send({
where: pushQuery,
data: {
alert : "word" + day
}}, { success: function() {
// Push was successful
},
error: function(error) {
}}).then (function(result){
//Marks this promise as fulfilled,
//firing any callbacks waiting on it.
promise.resolve(result);
}, function(error) {
//Marks this promise as fulfilled,
//firing any callbacks waiting on it.
promise.reject(error);
});
return promise;
}
Parse.Cloud.job("scheduleWordNotification", function(request, status)
{
var promiseArray = [];
for (var i = 0; i < 100; i++) {
var promise = scheduleWordsForDay(i);
promiseArray.push(promise);
}
//Returns a new promise that is
//fulfilled when all of the input promises are resolved.
Parse.Promise.when(promiseArray).then(function(result) {
console.log("success promise!!")
status.success("success promise!!");
}, function(error) {
console.error("Promise Error: " + error.message);
status.error(error);
});
});