Parse Cloud job - parse-platform

I have a job in the parse cloud, inside the job I've a Parse.Cloud.run, when I run this function works fine and parse data base is update, but in the in the cloud job statuses appears failed. Here's my code:
Thanks in advance.
Parse.Cloud.job("updateTopsThreeJob", function(request, status) {
Parse.Cloud.useMasterKey();
var query = new Parse.Query("_User");
query.descending("followersOfMe");
query.limit(3);
query.find({
success: function(results) {
var TestJS = Parse.Object.extend("testJS");
var test = new TestJS();
var listTops = [];
for (var i = 0; i < results.length; i++) {
var object = results[i].get("username");
listTops.push(object);
}
Parse.Cloud.run("updateTopsThree", {objects: listTops}, {
success: function(result) {
status.success("Migration completed successfully.");
response.success(result)
},
error: function(error) {
status.error("Uh oh, something went wrong.");
}
});
response.success(listTops);
},
error: function(error) {
response.error("failed");
}
});
});
Parse.Cloud.define("updateTopsThree", function(request, response) {
var tops = Parse.Object.extend("testJS");
var query = new Parse.Query(tops);
query.get(ObjIDs.topsThreeID(), {
success: function(topsThree) {
topsThree.set("topsThree", request.params.objects);
topsThree.save();
response.success(topsThree);
},
error: function(object, error) {
response.error(error);
}
});
});

The Parse Cloud Code runs much like any other javascript file. In order to declare another function to be called within the parse .js file, such as in this case, you do not need to define the function using Parse syntax. Define and call it just as you would a normal Javascript function.
Use this to call the function within your Parse.job:
updateTopsThree(topThreeObjects);
Define function:
function updateTopsThree(topObjects) {
var tops = Parse.Object.extend("testJS");
var query = new Parse.Query(tops);
query.get(ObjIDs.topsThreeID(), {
success: function(topsThree) {
topsThree.set("topsThree", topObjects);
topsThree.save();
response.success(topsThree);
},
error: function(object, error) {
response.error(error);
}
});
}

Thanks, but finally I´ve solved my problem as follows: I´ve created a cloud function like this:
Parse.Cloud.define("setLikesInDB", function(request, response) {
var query = new Parse.Query("testJS");
query.get(ObjIDs.topsLikesID(), {
success: function(topsThree) {
topsThree.set("topsLikes", "likes");
topsThree.save();
response.success(topsThree)
},
error: function(object, error) {
response.error(error);
}
});
});
And then into my Parse.Cloud.Job I´ve called a cloud function like this:
Parse.Cloud.run('setLikesInDB', {obj : listTops}, {
success: function(result) {
response.success(result);
},
error: function(error) {
response.error('some error')
}
});
This way works fine.
I hope this helps someone else.

Related

uploading profile pic in hapijs 17.0

I am using hapijs version 17.0.1. I am trying to upload an image using ajax request on a hapijs route. Here is my AJAX code to upload profile pic:
var image_file_input = document.getElementById("user_profile_upload");
image_file_input.onchange = function () {
if(this.files != undefined)
{
if(this.files[0] != undefined)
{
var formData = tests.formdata ? new FormData() : null;
if (tests.formdata)
{
//alert(file)
formData.append('image_file', this.files[0]);
formData.append('userId', user_id);
formData.append('memberId', member_id);
}
$.ajax({
url: "/v1/User/uploadUserPic",
data: formData,
type: "POST",
dataType: "json",
contentType: false,
processData: false,
contentType: "multipart/form-data",
success: function(data){
console.log(data);
var errMsg = null;
var resData = null;
if(data.statusCode == 200)
{
resData = data.result;
}
else
{
alert(data.message)
}
},
error: function(error){
alert(error);
}
});
}
}
}
And here is my Hapijs route Code:
var uploadUserPic = {
method: 'POST',
path: '/v1/Module/uploadUserPic',
config: {
description: 'Update Image For User',
tags: ['api', 'User'],
auth: 'session',
payload: {
output: 'stream',
parse: true,
allow: 'multipart/form-data'
},
validate: {
payload: {
userId : Joi.string().regex(/^[a-f\d]{24}$/i).required(),
memberId: Joi.string().required(),
image_file: Joi.object().required(),
},
failAction: FailCallBack
}
},
handler: function (request, reply) {
var resultData = null;
var error = null;
return new Promise(function (resolve) {
var multiparty = require('multiparty');
var fs = require('fs');
var form = new multiparty.Form();
form.parse(request.payload, function (err, fields, files) {
if(err)
{
error = err;
resolve();
}
else
{
var mkdirp = require('mkdirp');
var img_dir = "./files/users/";
mkdirp(img_dir, function (err) {
if (err)
{
error = err;
console.error(err);
resolve();
}
else
{
var oldpath = files.image_file.path;
var newpath = "./files/users/"+requestPayload.userId+".png";
fs.rename(oldpath, newpath, function (err) {
if(err)
{
error = err;
}
resolve();
});
}
});
}
});
}).then(function (err, result) {
if(err) return sendError(err);
if(error) return sendError(error)
return {
"statusCode": 200,
"success": true
};
});
}
}
The above code gives me following error cannot read property 'content-length' of undefined on line form.parse(request.payload, function (err, fields, files) {});
Please let me know If I am doing something wrong. If I replace the url in ajax request with anohter url that I have written in php then it works perfectly. which means that something is wrong with my hapijs/nodejs code.
There's a good post on how to handle file uploads in Hapi.js (written in version 16) https://scotch.io/bar-talk/handling-file-uploads-with-hapi-js
Since you are using payload.parse = true, I am not seeing a particular reason why you have to use multiparty. I have the following working code that would save files (of any type) uploaded from client into uploads directory on the server (Please do not use directly on production as no sanitation is done)
{
path: '/upload',
method: 'POST',
config: {
payload: {
output: 'stream',
parse: true,
allow: 'multipart/form-data'
},
validate: {
payload: {
files: Joi.array().single()
}
}
},
handler: function(request) {
const p = request.payload, files = p.files
if(files) {
console.log(`${files.length} files`)
files.forEach(async file => {
const filename= file.hapi.filename
console.log(`Saving ${filename} to ./uploads`)
const out = fs.createWriteStream(`./uploads/${filename}`)
await file.pipe(out)
})
}
return {result: 'ok'}
}
}
You can use the following curl command to test
curl http://localhost:8080/upload -F 'files=#/path/to/a/note.txt' -F 'files=#/path/to/test.png' -vvv
There are a few issues with your code. First in your $.ajax call, you have specified contentType twice, although it's not a syntax error but it's careless to code like that. Second the function's signature inside your .then() block is incorrect. You are mixing the idea of Promise and callback. I don't think the following line will be triggered
if(err) return sendError(err);
One last trivial thing, you said you are using Hapi 17 but based on the handler function's signature
handler: function (request, reply) {
...
Seems you are not totally onboard with Hapi17 as the new signature is
handler: function (request, h) {
And it's not just the rename of reply to h.

How to insert a Parse Query first() call ahead of a series of Parse.Cloud.httpRequest() calls?

How would I add this code:
var query = new Parse.Query("Obj1");
query.equalTo("user", Parse.User.current());
query.first().then(function(obj) {
to the front of the chain in 'perform()'. Currently 'perform()' makes the two Parse.Cloud.httpRequest calls. I'd like it to do the Parse query first.
module.exports = {
version: '1.0.0',
initialize: function() {
return this;
},
perform: function(options) {
return Parse.Cloud.httpRequest({
method:'POST',
url:'http://...',
}).then(function(httpResponse) {
return Parse.Cloud.httpRequest({
method:'POST',
url:'http://...',
}).then(function(httpResponse) {
return httpResponse;
});
}, function(httpResponse) {
if (options && options.error) {
options.error(httpResponse);
}
});
}
}
Your code already demonstrates you understand thenable chaining, you can just apply it here:
// inside your function
var query = new Parse.Query("Obj1");
query.equalTo("user", Parse.User.current());
query.first().then(function(obj) {
// use obj here
return Parse.Cloud.httpRequest({
method:'POST',
url:'http://...',
});
}).then(... // rest of your code

Parse.com Cloud Code Failing

I am trying to use the following cloud code
Parse.Cloud.job("sendAlert", function(sendAlert, status) {
Parse.Push.send({
data: {
"content-available": 1,
}
}, {
success: function() {
status.success("Push Worked!!!");
},
error: function(error) {
status.error("Uh oh, something went wrong.");
}
});
});
to send a silent push alert.
It fails and calls the error function. What is the issue?
Allow me to answer my own question, I got the following code to work.
var query = new Parse.Query(Parse.Installation);
Parse.Cloud.job("sendAlert", function(sendAlert, status) {
Parse.Push.send({
where: query, // Set our Installation query
data: {
alert: "Broadcast to everyone"
}
}, {
success: function() {
status.success("Push Worked!!!");
},
error: function(error) {
status.error("Uh oh, something went wrong.")
}
});
});

Adding contraints to a column on Parse Data

I'm saving some objects into tables on my Parse Data. But I need to add a constraint or make sure that the data i'm trying to insert is unique. I'm using something like the following code. But i want to guarantee that the eventId (that I'm getting from facebook API) is unique in my tables, so i don't have any redundant information. What is the best way to make it work?
var Event = Parse.Object.extend("Event");
var event = new Event();
event.set("eventId", id);
event.set("eventName", name);
event.save(null, {
success: function(event) {
console.log('New object created with objectId: ' + event.eventId);
},
error: function(event, error) {
console.log('Failed to create new object, with error code: ' + error.message);
}
});
Update:
I'm calling it inside a httpRequest. The following is pretty much what I have and I cant figure out just how to call a beforeSave inside it.
Parse.Cloud.define("hello", function(request, response) {
var query = new Parse.Query("Location");
query.find({
success: function(results) {
console.log(results);
var totalResults = results.length;
var completedResults = 0;
var completion = function() {
response.success("Finished");
};
for (var i = 0; i < totalResults; ++i){
locationId = results[i].get("locationFbId");
Parse.Cloud.httpRequest({
url: 'https://graph.facebook.com/v2.2/'+locationId+'/events?access_token='+accessToken,
success: function(httpResponse) {
console.log(httpResponse.data);
console.log("dsa"+locationId);
for (var key in httpResponse.data) {
var obj = httpResponse.data[key];
for (var prop in obj) {
var eventObj = obj[prop];
if (typeof(eventObj) === 'object' && eventObj.hasOwnProperty("id")) {
var FbEvent = Parse.Object.extend("FbEvent");
var fbEvent = new FbEvent();
fbEvent.set("startDate",eventObj["start_time"]);
fbEvent.set("locationFbId", locationId);
fbEvent.set("fbEventId", eventObj["id"]);
fbEvent.set("fbEventName", eventObj["name"]);
Parse.Cloud.beforeSave("FbEvent", function(request, response) {
var query = new Parse.Query("FbEvent");
query.equalTo("fbEventId", request.params.fbEventId);
query.count({
success: function(number) {
if(number>0){
response.error("Event not unique");
} else {
response.success();
}
},
error: function(error) {
response.error(error);
}
});
});
}
}
}
completedResults++;
if (completedResults == totalResults) {
completion();
}
},
error:function(httpResponse){
completedResults++;
if (completedResults == totalResults)
response.error("Failed to login");
}
});
}
},
error: function() {
response.error("Failed on getting locationId");
}
});
});
So this is occurring in Cloud Code correct? (Im assuming since this is Javascript)
What you could do is create a function that occurs before each "Event" object is saved and run a query to make sure that the event is unique (query based off of "eventId" key, not objectId since the id comes from Facebook). If the event is unique, return response.success(), otherwise return response.error("Event not unique")
EX:
Parse.Cloud.beforeSave("Event", function(request, response) {
if(request.object.dirty("eventId")){
var query = var new Parse.Query("Event");
query.equalTo("eventId", request.object.eventId);
query.count({
success: function(number) {
if(number>0){
response.error("Event not unique");
} else {
response.success();
}
},
error: function(error) {
response.error(error);
}
});
} else {
response.success();
}
});
Parse.Cloud.define("hello", function(request, response) {
var query = new Parse.Query("Location");
query.find({
success: function(results) {
console.log(results);
var totalResults = results.length;
var completedResults = 0;
var completion = function() {
response.success("Finished");
};
for (var i = 0; i < totalResults; ++i){
locationId = results[i].get("locationFbId");
Parse.Cloud.httpRequest({
url: 'https://graph.facebook.com/v2.2/'+locationId+'/events?access_token='+accessToken,
success: function(httpResponse) {
console.log(httpResponse.data);
console.log("dsa"+locationId);
for (var key in httpResponse.data) {
var obj = httpResponse.data[key];
for (var prop in obj) {
var eventObj = obj[prop];
if (typeof(eventObj) === 'object' && eventObj.hasOwnProperty("id")) {
var FbEvent = Parse.Object.extend("FbEvent");
var fbEvent = new FbEvent();
fbEvent.set("startDate",eventObj["start_time"]);
fbEvent.set("locationFbId", locationId);
fbEvent.set("fbEventId", eventObj["id"]);
fbEvent.set("fbEventName", eventObj["name"]);
// Our beforeSave function is automatically called here when we save it (this will happen every time we save, so we could even upgrade our method as shown in its definition above)
fbEvent.save(null, {
success: function(event) {
console.log('New object created with objectId: ' + event.eventId);
},
error: function(event, error) {
console.log('Failed to create new object, with error code: ' + error.message);
}
});
}
}
}
completedResults++;
if (completedResults == totalResults) {
completion();
}
},
error:function(httpResponse){
completedResults++;
if (completedResults == totalResults)
response.error("Failed to login");
}
});
}
},
error: function() {
response.error("Failed on getting locationId");
}
});
});
This can also be accomplished before ever calling the save by querying and only saving if the query returns with a number == 0.
Summary: For those joining later, what we are doing here is checking to see if an object is unique (this time based on key eventId, but we could use any key) by overriding Parse's beforeSave function. This does mean that when we save our objects (for the first time) we need to be extra sure we have logic to handle the error that the object is not unique. Otherwise this could break the user experience (you should have error handling that doesn't break the user experience anyway though).

Getting multiple queries from parse.com

I am using the following code to get a single entry from parse.com in my corona sdk app. Is there a way to get two entries at the same time, say x1=55.317269 and x1=55.21354. I need the corresponding values for both entries rather than one.
local params = {x1=55.317269}
params.headers = headers
params.body = json.encode ( params )
network.request( "https://api.parse.com/1/functions/getFeatured","POST",getData,params)
The following is my cloud function.
Parse.Cloud.define("getFeatured", function(request, response) {
var query = new Parse.Query("testClass");
query.equalTo("x1", request.params.x1);
query.find({
success: function(results) {
var sum = 0;
sum = results[1].get("y1");
response.success(sum);
},
error: function() {
response.error("movie lookup failed");
}
});
});
Try this -
Parse.Cloud.define("getFeatured", function(request, response) {
var query = new Parse.Query("testClass");
query.containedIn("x1", ARRAY_OF_VALUES_TO_BE_MATCHED);
query.find({
success: function(results) {
// Modify/Create Proper Response Here
respones.success(results);
},
error: function() {
response.error("movie lookup failed");
}
});
});

Resources