Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

iOS

Aaron Watkins
PLUS
Aaron Watkins
Courses Plus Student 10,677 Points

Parse.com + Swift: How do you add PFUser.currentUser() to another user's relations using Cloud Code & the Master Key?

Hi all,

I am creating a social networking app with the customary method of adding friends: User A: sends friend request to user B User B: accepts friend request from user A User A & User B: are now friends and appear on one another's friend list

I'm able to get user A to send the friend request and it appears on user B's screen. user B can accept the friend request and see user A in the friend list. However, user B cannot see user A on their friend list. This is because Parse.com doesn't allow you to update any user information other than for the PFUser.currentUser(). In doing some research, I've found that people have achieved this by using Cloud Code and the Master Key. I'm not as familiar with JavaScript, so this is a bit daunting. However, this is the JavaScript that will apparently do the trick.

Cloud Code:

Parse.Cloud.define('editUser', function(request, response) {
    var userId = request.params.userId,
        newColText = request.params.newColText;

    var User = Parse.Object.extend('_User'),
        user = new User({ objectId: userId });

    user.set('new_col', newColText);

    Parse.Cloud.useMasterKey();
    user.save().then(function(user) {
        response.success(user);
    }, function(error) {
        response.error(error)
    });
});

Calling the cloud function from Objective-C:
```Objective-C
[PFCloud callFunction:@"editUser" withParameters:@{
    @"userId": @"someuseridhere",
    @"newColText": @"new text!"
}];

The swift equivalent is where I'm struggling I think.  Here's what I have:
```Swift:
PFCloud.callFunctionInBackground("editUser", withParameters:nil) {
            (result: AnyObject!, error: NSError!) -> Void in
            if error == nil {
                // result is "Hello world!"
            }
        }

My parameter is nil, but not sure of the syntax to add parameters or even what parameters I should be adding exactly to make this work. Hoping someone may have some thoughts?

Thanks a lot!

Aaron Watkins
Aaron Watkins
Courses Plus Student 10,677 Points

sorry for the horrible code block format. not sure what i'm doing wrong there.

3 Answers

Stone Preston
Stone Preston
42,016 Points

I got this working a few weeks ago. It's probably one of the most challenging things ive had to get working. working with cloud code was not as easy as I thought it was going to be.

this is the way I did it.

I have a friend request class in parse that has a fromUser that stores the user the request is from and a toUser attribute that stores who its to as well as a status attribute ("accepted, denied, etc)

I have a button that the user can press to accept a friend request.

when the button is pressed I call a cloud code function that adds the current user as a friend of the person who sent the request. I pass in the friendRequest object id as a parameter (you cant pass in an actual object, you just pass the id in and then query for it in cloud code)

then once that is done I add the person who sent the request as a friend of the current user.

this is the handler for the button press:

func handleAcceptButtonPressed(sender: UIButton) {

        //the buttons tag stores the indexPath.row of the array
        let friendRequest: PFObject = self.friendRequestsToCurrentUser[sender.tag] as PFObject

        let fromUser: PFUser = friendRequest[FriendRequestKeyFrom] as PFUser

        //call the cloud code function that adds the current user to the user who sent the request and pass in the friendRequest id as a parameter
        PFCloud.callFunctionInBackground("addFriendToFriendsRelation", withParameters: ["friendRequest": friendRequest.objectId]) { (object:AnyObject!, error: NSError!) -> Void in

            //add the person who sent the request as a friend of the current user
            let friendsRelation: PFRelation = self.currentUser.relationForKey(UserKeyFriends)
            friendsRelation.addObject(fromUser)
            self.currentUser.saveInBackgroundWithBlock({ (succeeded: Bool, error: NSError!) -> Void in

                if succeeded {



                } else {

                    Utilities.handleError(error)
                }
            })
        }


    }

the cloud code function I wrote looks like this:

Parse.Cloud.define("addFriendToFriendsRelation", function(request, response) {

    Parse.Cloud.useMasterKey();

        //get the friend requestId from params
    var friendRequestId = request.params.friendRequest;
    var query = new Parse.Query("FriendRequest");

    //get the friend request object
    query.get(friendRequestId, {

        success: function(friendRequest) {

            //get the user the request was from
            var fromUser = friendRequest.get("from");
            //get the user the request is to
            var toUser = friendRequest.get("to");

            var relation = fromUser.relation("friends");
            //add the user the request was to (the accepting user) to the fromUsers friends
            relation.add(toUser);

            //save the fromUser
            fromUser.save(null, {

                success: function() {

                    //saved the user, now edit the request status and save it
                    friendRequest.set("status", "accepted");
                    friendRequest.save(null, {

                        success: function() {

                            response.success("saved relation and updated friendRequest");
                        }, 

                        error: function(error) {

                            response.error(error);
                        }

                    });

                },

                error: function(error) {

                 response.error(error);

                }

            });

        },

        error: function(error) {

            response.error(error);

        }

    });

});

this took me forever to get working by the way. I was not very familiar with javascript and all the nested functions were pretty confusing. But after a while and after a few questions on the parse google group I managed to make it work

Aaron Watkins
Aaron Watkins
Courses Plus Student 10,677 Points

OH. MY. GOD. :-o

That absolutely worked. I played with it for like 15 minutes and almost fell out of my chair. Thank you SOOO much Stone Preston . You're a genius!

Stone Preston
Stone Preston
42,016 Points

no problem : ) Glad it worked for you!

How do you remove currentUser from friends PFRelation?

Aaron Watkins
PLUS
Aaron Watkins
Courses Plus Student 10,677 Points

Hi Priya!

I called this function from within my code. Here's the cloud code i was using:

Parse.Cloud.define("removeFriend", function(request, response) 
{
    //Example where an objectId is passed to a cloud function.
    var id = request.params.friend;

    //When getUser(id) is called a promise is returned. Notice the .then this means that once the promise is fulfilled it will continue. See getUser() function below.
    getUser(id).then
    (   
        //When the promise is fulfilled function(user) fires, and now we have our USER!
        function(user)
        {
            //"user" is the person to who the current user wants to remove
            response.success(user);
            var currentUser = Parse.User.current().id;
            var currentUserObject = Parse.User.current();
            var relation = user.relation("friendsRelation");
            relation.remove(currentUserObject);
            user.save();
        },
        function(error)
        {
            response.error(error);
        }
    );

});

Thanks for the script. I am going to give it a try. But where should I run it? I have "Parse.Cloud.define("addFriendToFriendsRelation", function(request, response)" in my main.js Should I just put this at the end of this function?

Should it look like this?

// Use Parse.Cloud.define to define as many cloud functions as you want. // For example: //Parse.Cloud.define("hello", function(request, response) { // response.success("Hello world!"); //});

Parse.Cloud.define("addFriendToFriendsRelation", function(request, response) {

Parse.Cloud.useMasterKey();

var friendRequestId = request.params.friendRequest;
var query = new Parse.Query("FriendRequest");

//get the friend request object
query.get(friendRequestId, {

    success: function(friendRequest) {

        //get the user the request was from
        var fromUser = friendRequest.get("requestFrom");
        //get the user the request is to
        var toUser = friendRequest.get("requestTo");

        var relation = fromUser.relation("friends");
        //add the user the request was to (the accepting user) to the fromUsers friends
        relation.add(toUser);

        //save the fromUser
        fromUser.save(null, {

            success: function() {

                //saved the user, now edit the request status and save it
                friendRequest.set("requestStatus", "Accepted");
                friendRequest.save(null, {
                success: function() {

                        response.success("saved relation and updated friendRequest");
                    }, 

                    error: function(error) {

                        response.error(error);
                    }

                });

            },

            error: function(error) {

             response.error(error);

            }

        });

    },

    error: function(error) {

        response.error(error);

    }

});

});

Parse.Cloud.define("removeFriend", function(request, response) { //Example where an objectId is passed to a cloud function. var id = request.params.friend;

//When getUser(id) is called a promise is returned. Notice the 
//.then this means that once the promise is fulfilled it will continue. 
//See getUser() function below.
getUser(id).then
(   
    //When the promise is fulfilled function(user) fires, and now we have our USER!
    function(user)
    {
        //"user" is the person to who the current user wants to remove
        response.success(user);
        var currentUser = Parse.User.current().id;
        var currentUserObject = Parse.User.current();
        var relation = user.relation("friendsRelation");
        relation.remove(currentUserObject);
        user.save();
    },
    function(error)
    {
        response.error(error);
    }
);

});

Aaron Watkins
Aaron Watkins
Courses Plus Student 10,677 Points

Yes - I believe that is how i have it set up. i have it put in my main.js. I call it from an @IBAction button (called removeFriend) and it works. Did that work for you?

I am trying to do that now. Thank you very much.

hi, this is the error I get "Error: ReferenceError: getUser is not defined at main.js:81:5 (Code: 141, Version: 1.5.0)" Below is my code:

void removeFriendship(PFUser *removeFriendUser)

{ [ProgressHUD show:@"Please wait..." Interaction:NO]; NSLog(@"removeFriendship %@", removeFriendUser); NSString *message = [NSString stringWithFormat:@"You are no longer friends with %@", removeFriendUser[PF_USER_FULLNAME]];

[PFCloud callFunctionInBackground:@"removeFriend" withParameters:@{@"friendRequest" : removeFriendUser.objectId} block:^(id object, NSError *error) {
    if (!error) {
        //remove the friend from currentUser PFRelation

        PFRelation *friendsRelation = [[PFUser currentUser] relationForKey:@"friends"];
        [friendsRelation removeObject:removeFriendUser];
        //save the current user
        [[PFUser currentUser] saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error)
         {
             if (!error) {


                 [ProgressHUD showSuccess:message];

             }else [ProgressHUD showError:@"Unable to fulfill the request."];
         }];
    }
}];

}

Vincent Jardel
Vincent Jardel
6,436 Points

Hey Priya Tuckley , I've the same error like you : getUser is not defined at main.js. How do you solve this ? Please have a look on this url : http://stackoverflow.com/questions/30174768/delete-pfuser-with-cloud-code-parse-com-ios

Jeremy Conley
Jeremy Conley
16,657 Points

I am currently trying to do this same thing, I'm not very familiar with working with cloud code. Before i was just trying to save the follower's objectID to an array key in the user class. Any help with how exactly pfrelations and adding users to them would be appreciated!