I have a aftersave on Parse cloud code. I have made changes to the table once but the aftersave hook triggers twice
1st Update (Actual update)
Input: {"object":{"addedBy":"tt","albumTitle":"ggh","approved":true,
"createdAt":"2015-12-14T03:07:27.253Z","image":
{"__type":"File","name":"tfss-e26ec608-5a0b-46a2-91db-33590139c4b3-
newImage.jpg","url":"http://files.parsetfss.com/0accbdba-e3f2-493d-
ac70-1c6bccc367b9/tfss-e26ec608-5a0b-46a2-91db-33590139c4b3-
newImage.jpg"},"objectId":"p4pLO70gQY","updatedAt":"2015-12-
14T03:07:37.733Z"}}
2nd Update (Shouldn't happen)
Input: {"object":{"addedBy":"tt","albumTitle":"ggh","approved":true,
"createdAt":"2015-12-14T03:07:27.253Z","image":
{"__type":"File","name":"tfss-e26ec608-5a0b-46a2-91db-33590139c4b3-
newImage.jpg","url":"http://files.parsetfss.com/0accbdba-e3f2-493d-
ac70-1c6bccc367b9/tfss-e26ec608-5a0b-46a2-91db-33590139c4b3-
newImage.jpg"},"objectId":"p4pLO70gQY","updatedAt":"2015-12-
14T03:07:38.038Z"}}
The only difference between the two updates is the updatedAt time. Will aftersave be triggered even if the update time changes?
How can I avoid the second aftersave execution?
Here is my cloud code :
Parse.Cloud.afterSave("Photos", function (request) {
var albumNameA = "";
var publicUser = "";
var albumOwner = "";
var photoUniqueId = "";
var isApproved = "";
albumNameA = request.object.get("albumTitle");
publicUser = request.object.get("addedBy");
photoUniqueId = request.object.id;
isApproved = request.object.get("approved");
if (request.object.get("createdAt").getTime() == request.object.get("updatedAt").getTime()) {
var getAlbumOwner = new Parse.Object.extend("Albums");
var q3 = new Parse.Query(getAlbumOwner);
q3.equalTo("title", albumNameA);
q3.first({
success: function (results) {
console.log("Checking for Creator name " + results.get("creatorName"));
albumOwner = results.get("creatorName");
console.log("Uploading a Photo Final " + albumNameA + "-by-" + publicUser + "--ownedby--" + albumOwner);
console.log("Uploading a Photo" + albumNameA + "-by-" + publicUser + "--" + photoUniqueId + "--" + isApproved);
var install = new Parse.Object.extend("Installation");
var q2 = new Parse.Query(install);
q2.equalTo("privacy", privateUserNo);
q2.equalTo("username", albumOwner);
q2.find({
success: function (results) {
if (!isApproved) {
Parse.Push.send({
where: q2, // Set our Installation query
data: {
alert: "New Photo uploaded by " + publicUser + " ,waiting for approval"
}
}, {
success: function () {
// Push was successful
console.log("Push success");
},
error: function (error) {
// Handle error
console.log("Push error");
}
})
}
},
error: function (error) {
console.log("Error: " + error.code + " " + error.message);
}
});
},
error: function (error) {
console.log("Error: " + error.code + " " + error.message);
}
});
} else if (!(request.object.get("createdAt").getTime() == request.object.get("updatedAt").getTime())) {
console.log("all case scenarios");
var getAlbumOwner1 = new Parse.Object.extend("Albums");
var q6 = new Parse.Query(getAlbumOwner1);
q6.equalTo("title", albumNameA);
q6.first({
success: function (results) {
albumOwner = results.get("creatorName");
var sendApproval = new Parse.Object.extend("Photos");
var q4 = new Parse.Query(sendApproval);
q4.descending("updatedAt");
q4.first({
success: function (results) {
var objectIDNeeded = results.id;
var isChanged = results.get("approved");
var currentUpdateTime = results.get("updatedTime");
console.log("Your Photo, " + publicUser + " ,has been approved by " + albumOwner);
var install = new Parse.Object.extend("Installation");
var q5 = new Parse.Query(install);
q5.equalTo("privacy", privateUserNo);
q5.equalTo("username", publicUser);
q5.find({
success: function (results) {
Parse.Push.send({
where: q5, // Set our Installation query
data: {
alert: "Your Photo has been approved by " + albumOwner
}
}, {
success: function () {
// Push was successful
console.log("Push success");
},
error: function (error) {
// Handle error
console.log("Push error");
}
})
},
error: function (error) {
console.log("Error: " + error.code + " " + error.message);
}
});
},
error: function (error) {
console.log("Error: " + error.code + " " + error.message);
}
});
},
error: function (error) {
console.log("Error: " + error.code + " " + error.message);
}
});
}
});
Related
I defined a cloud codeļ¼
Parse.Cloud.define("updateUser", async (request) => {
const query = new Parse.Query("User");
query.get(request.params.id, {useMasterKey:true})
.then(function(user) {
user.set("username", request.params.username);
user.set("password", request.params.password);
user.set("gender", request.params.gender);
return user.save(null, {useMasterKey:true});
}).catch(function(error) {
console.error("Got an error " + error.code + " : " + error.message);
});
});
Return has been changed successfully.
But, using the new password to log in on the mobile app, the password is incorrect.
{"code":101, "stack": "Error": Invalide username/password}
I think you need to return the first promise. Also try to use setUsername and setPassword. It would be something like this:
Parse.Cloud.define("updateUser", async (request) => {
const query = new Parse.Query("User");
return query.get(request.params.id, {useMasterKey:true})
.then(function(user) {
user.setUsername(request.params.username);
user.setPassword(request.params.password);
user.set("gender", request.params.gender);
return user.save(null, {useMasterKey:true});
}).catch(function(error) {
console.error("Got an error " + error.code + " : " + error.message);
});
});
I have used the original helloworld app and just change the model from HelloWorldModel to MainModel.
Then i required "http" but when i run the app and klik the button for "updateAction" it only writes to the console and sets the message.
The HTTP request doesn't do anything.
Code: (main-view-model.js)
var __extends = this.__extends || function(d, b) {
for (var p in b)
if (b.hasOwnProperty(p)) d[p] = b[p];
function __() {
this.constructor = d;
}
__.prototype = b.prototype;
d.prototype = new __();
};
var observable = require("data/observable");
var http = require("http");
var MainModel = (function(_super) {
__extends(MainModel, _super);
function MainModel() {
_super.call(this);
console.log("MainModel called");
this.set("message", "Last updated" + " 2015-07-22 00:00:00");
this.set("message2", "Last updated" + " 2015-07-22 00:00:00");
}
MainModel.prototype.updateAction = function() {
console.log("updateAction");
this.set("message2", "Last updated" + " 2015-07-22 01:00:00");
http.getJSON("https://httpbin.org/get").then(function(r) {
this.set("message", "Last updated \n" + r);
console.log("SUCCESS");
console.log(r);
}, function(e) {
// Argument (e) is Error!
console.log("FAIL");
console.log(e);
this.set("message", "Last updated \n" + e);
});
};
return MainModel;
})(observable.Observable);
exports.MainModel = MainModel;
exports.mainViewModel = new MainModel();
What am I doing wrong?
Note: I'm testing on iPhone 6 emulator
It seems that using getString works and gives the same response.
Still wierd the getJSON doesn't work.
A working example is:
http.getString("https://httpbin.org/get").then(function (r) {
console.log("SUCCESS");
console.log(r);
}, function (e) {
console.log("FAIL");
console.log(e);
});
i'am using the Barcode Scanner for phonegap build, How would i retrieve the QR Codes URL data and display the webpage into a Iframe or div
$(document).ready(function(e) {
$("#scanner_mode").click(function() {
cordova.plugins.barcodeScanner.scan(
function (result) {
alert("We got a barcode\n" +
"Result: " + result.text + "\n" +
"Format: " + result.format + "\n" +
"Cancelled: " + result.cancelled);
},
function (error) {
alert("Scanning failed: " + error);
}
);
});
});
Right i have tried this but its not working, so how would i get the src of a iframe to load result.text url
$(document).ready(function(e) {
$("#scanner_mode").click(function() {
cordova.plugins.barcodeScanner.scan(
function (result) {
document.getElementById("frame").src = result.text;
},
function (error) {
alert("Scanning failed: " + error);
}
);
});
});
yep so its working :)
$(document).ready(function(e) {
$("#scanner_mode").click(function() {
cordova.plugins.barcodeScanner.scan(
function (result) {
document.getElementById("frame").src = result.text;
},
function (error) {
alert("Scanning failed: " + error);
}
);
});
});
that works :)
I've got the follwing parse.com cloud code
Parse.Cloud.afterSave("Action", function (request) {
var BookStatus = Parse.Object.extend("BookStatus");
var Book = Parse.Object.extend("Book");
var book = new Book();
var actionType = request.object.get("actionTypePointer").id;
var bookId = request.object.get("bookPointer").id;
var queryBook = new Parse.Query("Book");
var newBookStatus;
queryBook.get(bookId,{
success: function (gottenBook) {
newBookStatus = "idOfTheBookStatus";
book.id = bookId;
book.set("bookStatus", new BookStatus({id: newBookStatus}));
gottenBook.set("bookStatus", new BookStatus({id: newBookStatus}));
//OPTION 1
gottenBook.save(null,{
success: function(data) {
console.log("Bookstatus updated1");
},
error: function (data,error) {
// error is a Parse.Error with an error code and description.
console.log("Error: " + error.code + " " + error.message);
}
});
//OPTION 2
book.save(null,{
success: function(data) {
console.log("Bookstatus updated2");
},
error: function (data,error) {
// error is a Parse.Error with an error code and description.
console.log("Error: " + error.code + " " + error.message);
}
});
},
error: function (object, error) {
// The object was not retrieved successfully.
// error is a Parse.Error with an error code and description.
console.log("Error: " + error.code + " " + error.message);
}
});
OPTION1
I try to save the queried book after setting the bookStatus to the returned book.
OPTION2
I try to save the new book object after setting the book.Id
book.id = bookId;
book.set("bookStatus", new BookStatus({id: newBookStatus}));
However with any of the 2 options I end up getting in the parse.com logs:
Error: 101 object not found for update
Error: 101 object not found for update
Any idea of what I am doing wrong?
Thanks in advance!
--EDIT
New implementation with fetch:
Parse.Cloud.afterSave("Action", function (request) {
var BookStatus = Parse.Object.extend("BookStatus");
var Book = Parse.Object.extend("Book");
var book = new Book();
var actionType = request.object.get("actionTypePointer").id;
var bookId = request.object.get("bookPointer").id;
book.id = bookId;
console.log("before fetch book.id" + book.id);
var newBookStatus;
book.fetch({
success: function (book) {
newBookStatus = "XMFkXS9NVv";
book.set("bookStatus", new BookStatus({id: newBookStatus}));
console.log("book" + book);
console.log("book.id" + book.id);
console.log("book.isValid()" + book.isValid());
book.save(null,{
success: function(data) {
console.log("Book Status updated to:" +newBookStatus);
},
error: function (data,error) {
// error is a Parse.Error with an error code and description.
console.log("Error: " + error.code + " " + error.message);
}
});
},
error: function (object, error) {
// The object was not retrieved successfully.
// error is a Parse.Error with an error code and description.
console.log("Error: " + error.code + " " + error.message);
}
});
});
With result:
Input: {"place":{"__type":"GeoPoint","latitude":41.354643806134625,"longitude":2.121594674804572},"bookLocationDescription":"sad","bookPointer":{"__type":"Pointer","className":"Book","objectId":"kWcALge4az"},"actionTypePointer":{"__type":"Pointer","className":"ActionType","objectId":"kJC954w9iO"},"userPointer":{"__type":"Pointer","className":"_User","objectId":"6xpiAHX9Ju"},"createdAt":"2013-05-16T13:59:33.810Z","updatedAt":"2013-05-16T13:59:33.810Z","objectId":"PwlXhKL51l","ACL":{"6xpiAHX9Ju":{"read":true,"write":true},"*":{"read":true}}}
Result: Success
I2013-05-15T20:52:19.170Z] before fetch book.idc1iKxw3NLD
I2013-05-15T20:52:19.273Z] book[object Object]
I2013-05-15T20:52:19.273Z] book.idc1iKxw3NLD
I2013-05-15T20:52:19.273Z] book.isValid()true
I2013-05-15T20:52:19.325Z] Error: 101 object not found for update
Your afterSave hook is overwriting the fetched Book's object id. Even if you're setting the same object id on it, the object now thinks it's dirty and it's no longer a valid reference.
Avoid this by using the book returned by get() and not updating it's id:
Parse.Cloud.afterSave("Action", function (request) {
var BookStatus = Parse.Object.extend("BookStatus");
var Book = Parse.Object.extend("Book");
var book = new Book();
var actionType = request.object.get("actionTypePointer").id;
var bookId = request.object.get("bookPointer").id;
var queryBook = new Parse.Query("Book");
var newBookStatus;
queryBook.get(bookId,{
success: function (book) {
newBookStatus = "idOfTheBookStatus";
book.set("bookStatus", new BookStatus({id: newBookStatus}));
book.save(null,{
success: function(data) {
console.log("Bookstatus updated1");
},
error: function (data,error) {
// error is a Parse.Error with an error code and description.
console.log("Error: " + error.code + " " + error.message);
}
});
},
error: function (object, error) {
// The object was not retrieved successfully.
// error is a Parse.Error with an error code and description.
console.log("Error: " + error.code + " " + error.message);
}
});
});
Since you already know the id for this book, instead of using a query, you can create a pointer and fetch it directly.
Final afterSave hook:
Parse.Cloud.afterSave("Action", function (request) {
var BookStatus = Parse.Object.extend("BookStatus");
var Book = Parse.Object.extend("Book");
var book = new Book();
var actionType = request.object.get("actionTypePointer").id;
var bookId = request.object.get("bookPointer").id;
book.id = bookId;
var newBookStatus;
book.fetch({
success: function (book) {
newBookStatus = "idOfTheBookStatus";
book.set("bookStatus", new BookStatus({id: newBookStatus}));
book.save(null,{
success: function(data) {
console.log("Bookstatus updated1");
},
error: function (data,error) {
// error is a Parse.Error with an error code and description.
console.log("Error: " + error.code + " " + error.message);
}
});
},
error: function (object, error) {
// The object was not retrieved successfully.
// error is a Parse.Error with an error code and description.
console.log("Error: " + error.code + " " + error.message);
}
});
});
Here's how I did it after some running around
ParseCrashReporting.enable(this);
// Enable Local Datastore.
Parse.enableLocalDatastore(this);
// Add your initialization code here
Parse.initialize(this, "*******", "******");
ParseUser.enableAutomaticUser();
ParseACL defaultACL = new ParseACL();
ParseACL.setDefaultACL(defaultACL, true);
// save the installation
ParseInstallation.getCurrentInstallation().saveInBackground();
More info on the issue in my blog post here:
http://aprogrammersday.blogspot.com/2015/02/fix-parse-101-error-object-not-found.html
Whilst looking for this error I found this thread the most useful. I wanted to add that object not found for get can also essentially mean foreign key reference not found.
The not found for get error can be incredibly unhelpful; for me it wasn't even giving a line number where the error was occurring, the error message is very vague and I could not find reference to the phrase in any of the documentation.
If you are getting this error, you will find a lot of reference to permissions issues, but if you are already using the master key then you need to find the object that is being referenced by a foreign key on your selected object.
I'm trying to make an AJAX request to a public service
Here's the code:
$.ajax({
url : "http://api.geonames.org/citiesJSON",
type : 'POST',
cache : false,
dataType : 'json',
data : {
username: "demo",
north:10,
south: 10,
east:10,
west:10}
}).done(function(data) {
alert("Success: " + JSON.stringify(data));
}).fail(function(a, b, c, d) {
alert("Failure: "
+ JSON.stringify(a) + " "
+ JSON.stringify(b) + " "
+ JSON.stringify(c) + " "
+ JSON.stringify(d) );
});
You may try it in this link: http://jsfiddle.net/hDXq3/
The response is retrieved successfully on Chrome & Firefox, and the output is as follows:
But for IE, the fails alerting:
Failure: {"readyState":0,"status":0,"statusText":"No Transport"} "error" "No Transport" undefined
Why it's not working on IE ? and how to fix this ?
Here's the solution for those who are interested:
if (!jQuery.support.cors && window.XDomainRequest) {
var httpRegEx = /^https?:\/\//i;
var getOrPostRegEx = /^get|post$/i;
var sameSchemeRegEx = new RegExp('^'+location.protocol, 'i');
var xmlRegEx = /\/xml/i;
// ajaxTransport exists in jQuery 1.5+
jQuery.ajaxTransport('text html xml json', function(options, userOptions, jqXHR){
// XDomainRequests must be: asynchronous, GET or POST methods, HTTP or HTTPS protocol, and same scheme as calling page
if (options.crossDomain && options.async && getOrPostRegEx.test(options.type) && httpRegEx.test(userOptions.url) && sameSchemeRegEx.test(userOptions.url)) {
var xdr = null;
var userType = (userOptions.dataType||'').toLowerCase();
return {
send: function(headers, complete){
xdr = new XDomainRequest();
if (/^\d+$/.test(userOptions.timeout)) {
xdr.timeout = userOptions.timeout;
}
xdr.ontimeout = function(){
complete(500, 'timeout');
};
xdr.onload = function(){
var allResponseHeaders = 'Content-Length: ' + xdr.responseText.length + '\r\nContent-Type: ' + xdr.contentType;
var status = {
code: 200,
message: 'success'
};
var responses = {
text: xdr.responseText
};
try {
if (userType === 'json') {
try {
responses.json = JSON.parse(xdr.responseText);
} catch(e) {
status.code = 500;
status.message = 'parseerror';
//throw 'Invalid JSON: ' + xdr.responseText;
}
} else if ((userType === 'xml') || ((userType !== 'text') && xmlRegEx.test(xdr.contentType))) {
var doc = new ActiveXObject('Microsoft.XMLDOM');
doc.async = false;
try {
doc.loadXML(xdr.responseText);
} catch(e) {
doc = undefined;
}
if (!doc || !doc.documentElement || doc.getElementsByTagName('parsererror').length) {
status.code = 500;
status.message = 'parseerror';
throw 'Invalid XML: ' + xdr.responseText;
}
responses.xml = doc;
}
} catch(parseMessage) {
throw parseMessage;
} finally {
complete(status.code, status.message, responses, allResponseHeaders);
}
};
xdr.onerror = function(){
complete(500, 'error', {
text: xdr.responseText
});
};
xdr.open(options.type, options.url);
//xdr.send(userOptions.data);
xdr.send();
},
abort: function(){
if (xdr) {
xdr.abort();
}
}
};
}
});
};
jQuery.support.cors = true;
$.ajax({
url : "http://api.geonames.org/citiesJSON",
crossDomain: true,
type : 'POST',
cache : false,
dataType : 'json',
data : {
username: "demo",
north:10,
south: 10,
east:10,
west:10}
}).done(function(data) {
alert("Success: " + JSON.stringify(data));
}).fail(function(a, b, c, d) {
alert("Failure: "
+ JSON.stringify(a) + " "
+ JSON.stringify(b) + " "
+ JSON.stringify(c) + " "
+ JSON.stringify(d) );
});
You may try it in this link: http://jsfiddle.net/bjW8t/4/
Just include the jQuery ajaxTransport extension that uses XDomainRequest for IE8+.