Modifying Parse.User object before FIRST save - parse-platform

I'm working on an app and I need some changes to be made on new users registering during certain periods.
I've added a variable which I will change manually, and a check if that value is true or false.
This is my current code:
Parse.Cloud.beforeSave(Parse.User, function(request, status)
{
console.log("********************************************");
Parse.Cloud.useMasterKey();
var special = true;
if(special)
{
request.object.set("points", 1000);
request.object.set("role/objectid", "PZHTquGti0");
}else{
request.object.set("points", 0);
request.object.set("role/objectid", "TQyjIY59oL");
}
console.log("********************************************");
status.success("Job finished successfully!");
}); // end of Parse.define
This code errors out with "Uncaught Error: change must be passed a Parse.Object" and I've been looking through the documentation to find out how to change a value of a subclass of the User object, but have found none.
Also, this code will also run when updating a user, which I don't want it to do.
Any help is highly appreciated!

First of all for running the code on first save (insert), you can use request.object.isNew()
As the role column is a pointer, you should set an object & not the id string directly.
So create a new dummy object and assign the id to it.
Parse.Cloud.beforeSave(Parse.User, function(request, status)
{
console.log("********************************************");
Parse.Cloud.useMasterKey();
if(request.object.isNew()){ // Object Insert
var Role = Parse.Object.extend("_Role");
var role = new Role();
var special = true;
if(special)
{
request.object.set("points", 1000);
role.id = "PZHTquGti0";
request.object.set("role", role);
}else{
request.object.set("points", 0);
role.id = "TQyjIY59oL";
request.object.set("role", role);
}
}
else{ // Object Update
//Do nothing
}
console.log("********************************************");
status.success("Job finished successfully!");
}); // end of Parse.define

Related

Parse Cloud Code Setting Relation On User Class

I have an issue with not getting some cloud code to run in Parse. Currently, I pass an objectId of another user who I want to set a review for. In client side, I am saving the review, and capturing that object. I pass that as well up to cloud code. Both show up there, but I cannot figure out the right way to set the relation on this user and apply that review that was created. Code snip is below. Any help would be appreciated before I bang my head against a wall.
Parse.Cloud.define("addReview", async (request, response) => {
let { userObjId, reviewObj } = request.params;
const query = new Parse.Query(Parse.User);
//get the user object to post review of
try{
let object = await query.get(userObjId, {useMasterKey: true});
console.log(object);
console.log("running");
object.set('Reviews', new Parse.Object(reviewObj));
object.save(null, { useMasterKey: true })
return ("saved relation and updated reviews");
} catch (err){
throw new Error(err.message)
}
});
I assume
reviewObj is the review object, the user recently created.
and in your User class, you got a to-many-relation to Review class, named 'Reviews'.
First I'd suggest to name your user object user instead of object, to make it clearer what you're dealing with and make your code easier to understand.
Since you said, the review object is already successfully saved on server side, I'd recommend to transmit only the reviewId in your request.
To add an object to a relation, you first need to get the relation property of your user object:
const reviewsRelation = user.relation('Reviews');
Then to add the object to the relation just call:
reviewsRelation.add(user);
In total, your snippet should look like this:
Parse.Cloud.define("addReview", async (request, response) => {
let { userObjId, reviewObjId } = request.params;
const userQuery = new Parse.Query(Parse.User);
const reviewQuery = new Parse.Query(Parse.Review);
//get the user object to post review of
try{
let user = await userQuery.get(userObjId, {useMasterKey: true});
let review = await reviewQuery.get(reviewObjId, {useMasterKey: true});
console.log(user);
console.log("running");
const reviewsRelation = user.relation('Reviews');
reviewsRelation.add(review);
user.save(null, { useMasterKey: true })
return ("saved relation and updated reviews");
} catch (err){
throw new Error(err.message)
}
});

parse.com destroyAll not working

In the code following this description, I am trying to find and remove all these bad ListConfig objects that didn't have a group object set. It is correctly finding them, however it does not remove them. Is there something I am missing in the following code?
var Groups = [];
function queryForGroups(callback) {
var Group = Parse.Object.extend("Group");
var query = new Parse.Query(Group);
query.limit(1000);
query.find().then(function(result) {
Groups = result;
callback();
});
};
function removeConfigs(){
var Config = Parse.Object.extend("ListConfig");
var query = new Parse.Query(Config);
query.limit(10000);
query.notContainedIn("group", Groups);
query.find().then(function(configs){
return Parse.Object.destroyAll(configs, {useMasterKey:true});
});
}
function removeBadConfigs() {
queryForGroups(function() {
removeConfigs();
});
};
removeBadConfigs();
The code could be a little cleaner with respect to mixing promises, callbacks and an unnecessary global. Beyond that, it looks like it should work as long as your data model supports it. Specifically, your ListConfig object must have a "group" property, and it must have a Parse.Object value set for that property. The most common error I've seen is something like this:
var myGroup = // a parse object of type Group
myListConfig.set("group", myGroup.id); // WRONG
myListConfig.set("group", myGroup); // RIGHT
Assuming you've got that right, then it's mysterious why you're not seeing some deletes, but here's the code cleaned up with promises...
function queryForGroups() {
let query = new Parse.Query("Group")
query.limit(1000);
return query.find();
};
function removeConfigsWithGroups(groups){
let query = new Parse.Query("Config");
query.notContainedIn("group", groups);
return query.find().then(function(configs){
return Parse.Object.destroyAll(configs, {useMasterKey:true});
});
}
function removeBadConfigs() {
return queryForGroups(function(groups) {
return removeConfigsWithGroups(groups);
});
};
removeBadConfigs();
I figured it out. I removed "useMasterKey: true" because 1) it isn't needed for objects not with elevated privileges and 2) I was not running it in Cloud Code.

Parse Cloud Right Query to retrieve Friendslist and not (like Instagram)

I have the class "Users" the default of Parse Dashboad. I have also the class "Friends", where I store the friendships between users like this:
There are two columns, "toUser" and "fromUser", which are showing who of the two users sent the friend request. These two columns are Pointers(Pointer<_User>) to the Users Class.
My concept is to retrieve two lists:
1. Friendlist for the logged in user
2. Userlist of users (who are not friends with the logged in user)
What would be the appropriate queries for that?
The first one logically should not scan all the class Users because it may slow down the perfomance of the app which is using Ionic 3 and Angular 4
Thank you
you don't need another class to do so all you need is a relation column in the default user class
to add new friend you just need the following code
var friendtoadd
//this is the friend object from parse user class you want to add you can get it by anyway you want
var currentUser = Parse.User.current();
var relation = currentUser.relation("friends");
relation.add(friendtoadd)
currentUser.save();
to retrieve array of friends of logged in user you can use the following code
var currentUser = Parse.User.current();
var friendRelation = currentUser.relation('friends');
var env = this
friendRelation.query().find({
success: function(users) {
for (var i = 0; i< users.length; i++) {
var object = users[i];
env.friends.push(object)
console.log(env.friends)
}
}
});
// you should define friends = []; in the class
if I understood your question right you want to find the friend requests you sent, or the ones you received. because I don't see where you made a relation between the user and his friends.
this is the code if you want to do this using cloud code:
First I validated the parameters of the friendRequest being saved :
Parse.Cloud.beforeSave("Friends", function(request, response){
var friendRequest = request.object;
if (!friendRequest.has("toUser") || !friendRequest.has("fromUser")) {
response.error("Invalid parameters");
return;
}
response.success();
});
then I created two cloud functions, one for retrieving the sentRequests:
Parse.Cloud.define("getSentRequests", function(request, response){
var query = new Parse.Query("Friends");
query.equalTo("fromUser", request.user);
if (!request.master) {
query.find({ sessionToken: request.user.getSessionToken() }).then(function(friends){
response.success(friends);
});
}else{
query.find({useMasterKey:true}).then(function(friends){
response.success(friends);
});
}
});
and you can call this either from a logged in user or using the masterKey if you want, and the other query is for the recievedRequests:
Parse.Cloud.define("getRecievedRequests", function(request, response){
var query = new Parse.Query("Friends");
query.equalTo("toUser", request.user);
if (!request.master) {
query.find({ sessionToken: request.user.getSessionToken() }).then(function(users){
response.success(users);
});
}else{
query.find({useMasterKey:true}).then(function(users){
response.success(users);
});
}
});

Why Parse server is creating new object instead of updating?

I am running parse server in NodeJS environment with express.
Generally, Parse automatically figures out which data has changed so only “dirty” fields will be sent to the Parse Cloud. So, I don’t need to worry about squashing data that I didn’t intend to update.
But why this following code is saving new data every time instead of updating the existing document data with name "Some Name".
// Parse code
Parse.initialize(keys.parseAppID);
Parse.serverURL = keys.parseServerURL;
var GameScore = Parse.Object.extend("GameScore");
var gameScore = new GameScore();
let data = {
playerName: "Some Name",
score: 2918,
cheatMode: true
};
gameScore.save(data, {
success: (gameScore) => {
// let q = new Parse.Query("GameScore");
// q.get(gameScore.id)
console.log("ID: " + gameScore.id)
},
error: function (gameScore, error) {
// Execute any logic that should take place if the save fails.
// error is a Parse.Error with an error code and message.
alert('Failed to create new object, with error code: ' + error.message);
}
});
// End of Parse code
The problem is that you're executing the query to find which object you want to update, but then you're not using the results when you go to save data.
query.first({ // This will result in just one object returned
success: (result) => {
// Check to make sure a result exists
if (result) {
result.save(data, {
// Rest of code
Note: You're treating playerName as a unique key. If multiple users can have the same playerName attribute, then there will be bugs. You can use id instead which is guaranteed to be unique. If you use id instead, you can utilize Parse.Query.get
Edit:
Since you want to update an existing object, you must specify its id.
var GameScore = Parse.Object.extend("GameScore");
var gameScore = new GameScore();
gameScore.id = "ID"; // This id should be the id of the object you want to update

parse.com inherited ACL + roles - afterSave or beforeSave, tricky scenario

Here's what I am trying to achieve but somehow I am stuck and I am not sure what's the proper approach, I cannot find any good examples of such case so I am seeking your help.
Each registered user can add new object to class "List". Once the new item is created I call afterSave function and assign proper ACL creating new role ("membersOf_" + List.id). Next, user can add new object to class "Items", which will store List.id as a reference and ACL for item should be inherited from list. Lists and Items can be shared between multiple users of their choice. There are few problems in such case:
when creating new List, I need to create new role and assign creator to it and add such role to created List
when creating new Item, I need to pass List.id as a payload and validate with cloud code if current user can create such item (assigned to specified List) by checking first if he has proper permissions to List
if permission check is ok, I need give this item the same ACL as List has and proceed with saving
Here's my afterSave for List, creating role properly and assigning ACL to List object. (1) I am missing adding this role to user (creator)
Parse.Cloud.afterSave("List", function(request, response) {
var list = request.object;
var user = Parse.User.current();
if (list.existed()) {
// quit on update, proceed on create
return;
}
var roleName = "membersOf_" + list.id;
var listRole = new Parse.Role(roleName, new Parse.ACL(user));
return listRole.save().then(function(listRole) {
var acl = new Parse.ACL();
acl.setPublicReadAccess(false);
acl.setPublicWriteAccess(false);
acl.setReadAccess(listRole, true);
acl.setWriteAccess(listRole, true);
var itemData = new Parse.Object("List", {
ACL: acl
});
return itemData.save('objectId', list.id);
});
// to do - add user to this role too
});
Here's my Item beforeSave to validate if user can actually create such object, I am checking if he can query the List table, if he get >0 results for such List that means he will be ok to adding an Item assigned to this List. (2) Missing ACL inheritance
Parse.Cloud.beforeSave("Item", function(request, response) {
var item = request.object;
var listId = request.object.get("list");
var user = Parse.User.current();
var List = Parse.Object.extend("List");
var query = new Parse.Query(List);
query.equalTo("objectId", listId);
query.first({
success: function(list) {
if (list.id) {
response.success();
}
else {
response.error('No such list or you don\'t have permission to perform this operation.');
}
},
error: function(error) {
response.error(error);
}
});
});
Can someone point me to the proper solution or help solve that puzzle? I am missing two things:
- (1) I need to add user (creator) to new role created in afterSave
- (2) I need to add the same ACL to Item, inherit it from List object
I have tried many things, passing ACL in afterSave for Item, modifying payload in beforeSave. Many different functions following documentation and different examples, but still no luck.
Any advice would be awesome!
Ok, I think I finally figured it out. Hopefully this will help someone in future.
Here are final beforeSave and afterSave functions adding user to specified role and assigning the same ACL to Item object
Parse.Cloud.afterSave("List", function(request, response) {
var list = request.object;
var user = Parse.User.current();
if (list.existed()) {
// quit on update, proceed on create
return;
}
var roleName = "membersOf_" + list.id;
var listRole = new Parse.Role(roleName, new Parse.ACL(user));
//+ adding user to role in this line:
listRole.relation("users").add(user);
return listRole.save().then(function(listRole) {
var acl = new Parse.ACL();
acl.setPublicReadAccess(false);
acl.setPublicWriteAccess(false);
acl.setReadAccess(listRole, true);
acl.setWriteAccess(listRole, true);
var itemData = new Parse.Object("List", {
ACL: acl
});
return itemData.save('objectId', list.id);
});
// to do - add user to this role too
});
Parse.Cloud.beforeSave("Item", function(request, response) {
var item = request.object;
var listId = request.object.get("list");
var user = Parse.User.current();
// + modifying payload with the same ACL here
var acl = new Parse.ACL();
acl.setPublicReadAccess(false);
acl.setPublicWriteAccess(false);
acl.setRoleWriteAccess("membersOf_" + listId, true);
acl.setRoleReadAccess("membersOf_" + listId, true);
item.set('ACL', acl);
var List = Parse.Object.extend("List");
var query = new Parse.Query(List);
query.equalTo("objectId", listId);
query.first({
success: function(list) {
if (list.id) {
response.success();
}
else {
response.error('No such list or you don\'t have permission to perform this operation.');
}
},
error: function(error) {
response.error(error);
}
});
});

Resources