iOS + Parse Cloud Code - updating a specific user (not logged in user) - ios

I am trying to update a user (Which is not the current user). I figured that you have to use cloud code to make the update.
I have created the cloud function below to update the selected user. I am trying to add meetingId's to an array property which belongs to User class.
Cloud Code:
Parse.Cloud.define('updateUser', function(request, response) {
var userId = request.params.userId,
meetingId = request.params.meetingId;
var User = Parse.Object.extend('_User'),
user = new User({ objectId: userId });
user.addUnique("meetingsArray", meetingId)
user.save(null, {userMasterKey:true}).then(function(user) {
response.success(user);
}, function(error) {
response.error(error)
});
});
Objective-C
//meetingId - is obtained from Meeting Object.
[PFCloud callFunctionInBackground:#"updateUser" withParameters:#{#"objectId":user.objectId, #"meetingsArray":meetingId} block:^(NSString *result, NSError *error)
{
if (!error) {
NSLog(#"%#",result);
}else if(error){
NSLog(#"%#", error);
}
}];
When I run the app - I get the following error code:
Error Domain=Parse Code=141 "The operation couldn’t be completed. (Parse error 141.)" UserInfo=0x1704f2780 {code=141, temporary=0, error={"code":201,"message":"missing user password"}, originalError=Error Domain=NSURLErrorDomain Code=-1011 "The operation couldn’t be completed. (NSURLErrorDomain error -1011.)"}
I'm new to Cloud code - i just basically want to update the array that belongs to the selected user and add a meetingId to it. Any help would be greatly appreciate it.

There are a few problems with the code that will prevent it from working:
the cloud code expects the meeting id parameter to be named #"meetingId", so change the parameters passed to #{#"objectId":user.objectId, #"meetingId":meetingId}
use Parse.User, not '_User' to extend user.
get - don't build - the user being updated
Summing up...
Parse.Cloud.define('updateUser', function(request, response) {
var userId = request.params.userId;
var meetingId = request.params.meetingId;
var query = new Parse.Query(Parse.User);
query.get(userId).then(function(user) {
user.addUnique("meetingsArray", meetingId);
return user.save(null, {useMasterKey:true});
}).then(function(user) {
response.success(user);
}, function(error) {
response.error(error);
});
});

I was still getting the error after implementing #danh's answer. I needed to add
Parse.Cloud.useMasterKey()
in the .js file then everything worked perfect!

Related

How to change PFUser password in Swift?

I've tried updating the same way you would update a PFUser's email and even tried converting obj-c code (from other questions); neither worked. I also have no idea how to use Cloud Code (well...I installed it but I don't know how to pass information into Cloud Code or how to use JavaScript). Is there a way to update a users password without having to send the reset email?
You can not change a user's password that way for security reasons. You have two choices
Password Reset Email
Cloud Code Function to Reset the Password
As I understand that you do not know JavaScript, here is a cloud code function that you can use to reset the user's password, as well as a way to call the function using Swift.
Function (in JavaScript):
Parse.Cloud.define("changeUserPassword", function(request, response) {
// Set up to modify user data
Parse.Cloud.useMasterKey();
var query = new Parse.Query(Parse.User);
query.equalTo("username", request.params.username); // find all the women
query.first({
success: function(myUser) {
// Successfully retrieved the object.
myUser.set("password", request.params.newPassword);
myUser.save(null, {
success: function(myUser) {
// The user was saved successfully.
response.success("Successfully updated user.");
},
error: function(myUser, error) {
// The save failed.
// error is a Parse.Error with an error code and description.
response.error("Could not save changes to user.");
}
});
},
error: function(error) {
alert("Error: " + error.code + " " + error.message);
}
});
});
Swift code to call the above function:
PFCloud.callFunctionInBackground("changeUserPassword", withParameters: ["username" : "MyCoolUsername", "newPassword" : passwordField.text]) {
(result: AnyObject?, error: NSError?) -> Void in
if (error == nil) {
// result is "Successfully updated user."
}
}
Good luck!
Yes, password can be changed without Cloud Code and e-mail. After changing "password" field for current user session is reset, but you can restore it by calling PFUser.logInWithUsername again.
let currentUser = PFUser.current()
currentUser!.password = "<new_password>"
currentUser!.saveInBackground() { (successed, error) in
if successed {
PFUser.logInWithUsername(inBackground: currentUser!.email!, password: currentUser!.password!) { (user, error) in
// Your code here...
}
}
}

Parse.com saving non logged in users

I am building an iOS app with a following/follower relation using Parse.com. I am trying to do something where every time a user follows another user it puts the follower into to an array of Followers in Parse.com but i can not save a user who is not logged in. Is there anyway to get around this using the iOS SDK?
If you want to save a user that is not the current user, you will have to use cloud code and the master key. You can send up the id of the user you want to change, query for that user, and change any fields you want. Here is my cloud code function for editing users, where "myUser" is the id I sent up:
Parse.Cloud.define("editUser", function(request, response) {
//var GameScore = Parse.Object.extend("SchoolHappening");
// Create a new instance of that class.
//var gameScore = new GameScore();
Parse.Cloud.useMasterKey();
var query = new Parse.Query(Parse.User);
query.get(request.params.myUser, {
success: function(myUser) {
// The object was retrieved successfully.
myUser.set("cabinetPosition", request.params.myPosition);
// Save the user.
myUser.save(null, {
success: function(myUser) {
// The user was saved successfully.
response.success("Successfully updated user.");
},
error: function(gameScore, error) {
// The save failed.
// error is a Parse.Error with an error code and description.
response.error("Could not save changes to user.");
}
});
},
error: function(object, error) {
// The object was not retrieved successfully.
// error is a Parse.Error with an error code and description.
}
});
});
You can learn more about cloud code in the parse docs.
You can try to set an array property in your follower user (logged in) which represents the id of users he actually follows. Each time you follows another user, add his objectId in the array.
To get all your followers, use whereKey:containsAllObjectsInArray: method of PFQuery
PFQuery *followersQuery = [PFUser query];
[followersQuery whereKey:#"followsId" containsAllObjectsInArray:#[[PFUser currentUser].objectId]];
[followersQuery findObjectsInBackgroundWithBlock:^(NSArray *followersArray, NSError *error){
// Do stg
}];

iOS Parse validating user

I want to write code in AppDelegate.m that checks if PFUser.currentUser credentials are still valid. The reason I am doing this is for this scenario. Assume user logged in successfully and now currentUser has the basic information of that user. If the user changes the password at some time, when application launch, it should check if those credentials are up to date or not. If email & password doesn't match the one in table, it should log the user out.
I tried to do this but apparently PFUser.currentUser.password is always set to null while PFUser.currentUser.email has the actual value of email used to log in. How can I achieve this validation without the password being accessible?
Here is the code I have for guidance:
PFQuery *query = [PFQuery queryWithClassName:#"User"];
[query whereKey:#"objectId" equalTo: PFUser.currentUser.objectId];
[query whereKey:#"password" equalTo: PFUser.currentUser.password];
[query getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error) {
if (!object) {
/*Credentials changed! Logout user and request login again*/
NSLog(#"Credentials Changed!");
[PFUser logOut];
[[[navigationController viewControllers] objectAtIndex:0] performSegueWithIdentifier:#"loginSegue" sender:self];
}
else {
/*Credentials are still valid..proceed!*/
NSLog(#"Credentials Correct!");
[[[navigationController viewControllers] objectAtIndex:0] performSegueWithIdentifier:#"skipLoginSegue" sender:self];
}
}];
When this failed I tried to NSLog the password and got null so I understood that this was the problem.
I would write a cloud code function using the master key: Parse.Cloud.useMasterKey();
When you include this in your function you will be able to access/check the user's password and send back a "verified" variable or something of that sort.
Here is my cloud code function to modify a user, but you can easily modify it to verify a user's info. There are also many answers on the parse forums on this as well as lots of info in the docs.
Parse.Cloud.define("editUser", function(request, response) {
//var GameScore = Parse.Object.extend("SchoolHappening");
// Create a new instance of that class.
//var gameScore = new GameScore();
Parse.Cloud.useMasterKey();
var query = new Parse.Query(Parse.User);
query.get(request.params.myUser, {
success: function(myUser) {
// The object was retrieved successfully.
myUser.set("cabinetPosition", request.params.myPosition);
// Save the user.
myUser.save(null, {
success: function(myUser) {
// The user was saved successfully.
response.success("Successfully updated user.");
},
error: function(gameScore, error) {
// The save failed.
// error is a Parse.Error with an error code and description.
response.error("Could not save changes to user.");
}
});
},
error: function(object, error) {
// The object was not retrieved successfully.
// error is a Parse.Error with an error code and description.
}
});
});
If you want to verify your current password, you can store your password locally, then use loginWithUsernameInBackground: to verify. Something like,
[PFUser logInWithUsernameInBackground:[PFUser currentUser].username
password:password
block:^(PFUser *user, NSError *error) {
}];

Error when trying to retrieve basic user information

I have successfully included the Facebook Login in my IOS app however i seem to be having some difficulty getting some of the users basic information such as name, email etc....
My current code looks like this:
// Ask for the required permissions
self.loginView.readPermissions = #[#"basic_info",
#"user_location",
#"user_birthday",
#"user_likes"];
// Fetch user data
[FBRequestConnection
startForMeWithCompletionHandler:^(FBRequestConnection *connection,
id<FBGraphUser> user,
NSError *error) {
if (!error) {
// Display the user info
tempLabel.text = user.name;
}
}];
However there is always an error (where the if statement checks for !error, its always equal to false).
Can someone help me in trying to get this please?
Thanks,
Jake
EDIT:
2013-08-04 15:52:03.457 Ludis[37821:c07] {
"com.facebook.sdk:HTTPStatusCode" = 400;
"com.facebook.sdk:ParsedJSONResponseKey" = {
body = {
error = {
code = 2500;
message = "An active access token must be used to query information about the current user.";
type = OAuthException;
};
};
code = 400;
};
}
2013-08-04 15:52:03.458 Ludis[37821:c07] The operation couldn’t be completed. (com.facebook.sdk error 5.)
You haven't obtained the user's permission to perform the action you're attempting to perform. First call
openActiveSessionWithReadPermissions:allowLoginUI:completionHandler:
on FBSession. Here's some more information about how to log in to Facebook from iOS

Fetching Current User Profile using Objective C Google Plus Client Library

I am using the Google CLient Libraries for Objective C available here..
I have successfully been able to Authorize the user and get refresh token. (Using the GTMOAuthenticaion api embedded within).
In the Selector called after successful authorization I make the Get User Profile request as follows.. (I need the id of currently loggedin/authenticated user)
-(void)viewController:(GTMOAuth2ViewControllerTouch *)viewController
finishedWithAuth:(GTMOAuth2Authentication *)auth
error:(NSError *)error {
if (error != nil) {
NSLog(#"Stop");
} else {
if ([auth canAuthorize]){
[Mediator plusService].authorizer = auth;
// Problematic Line
GTLQueryPlus *profileQuery = [GTLQueryPlus queryForPeopleGetWithUserId:#"me"]; // Notice the UserId Param
profileQuery.completionBlock = ^(GTLServiceTicket *ticket, id object, NSError *error) {
if (error == nil) {
self.mediator.gProfile = object;
} else {
NSLog(#"GPlus Service Error %#", error);
}
};
[[Mediator plusService] executeQuery:profileQuery completionHandler:
^(GTLServiceTicket *ticket, id result, NSError *error) {
if (error)
NSLog(#"Some Service Error %#", error);
}];
}
}
}
If I put "me" as parameter, I get invalid user ID error string in jSON response.
However, If I provide some userId like my own 113632923069489732066 it works perfectly fine and returns the appropriate jSON response..!!
The Example for Google Plus inside Examples folder also fails to get current user profile ending with following error.
Error Domain=com.google.GTLJSONRPCErrorDomain Code=400 "The operation couldn’t be completed. (Invalid user ID: {0})" UserInfo=0x7a670fa0 {NSLocalizedFailureReason=(Invalid user ID: {0}), GTLStructuredError=GTLErrorObject 0x7a67b130: {message:"Invalid user ID: {0}" code:400 data:[2]}, error=Invalid user ID: {0}}
P.S. My API Console application doesn't work with iOS option under installed app but needs be configured with "Other" option. When configured with iOS option, the oAuth fails with invalid_client error response.
My Mistake .. !! And a very silly one .. !!
I was signing in using a Gmail Account that was yet not associated with GPlus .. !! =/

Resources