Can't Write Non Current User Objects by Pfuser Currentuser

Can't write non current user objects by PFUser currentuser

For security reasons, Parse won't allow you to save any changes to a user that is not currently logged in.

If you want to be able to make and save changes to user, you need to use Cloud Code and the Master Key to get around this roadblock.

I have had multiple problems like this before, and every time I've been forced to use a workaround via Cloud Code.

Here's an example of a workaround I did for creating a friends relationship between two users:

[PFCloud callFunction:@"editUser" withParameters:@{@"userId": user.objectId}];

The above code statement is in xcode, and executes the function I have added to my Cloud Code file.

Then, here's what my Cloud Code file looks like:

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

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

var currentUser = request.user;

var relation = user.relation("friendsRelation");
relation.add(currentUser);

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

The above code uses the Master Key to save changes to both the currently logged in user, and to the user who's objectId was passed into this function.

Code details:

var relation

This is just a variable I'm creating to hold what the following fucntion returns:

user.relation("friendsRelation");

In the above function, "friendsRelation" is the name of my PFRelation key in Parse.

Now that we have a valid relation object contain in our variable called relation, we execute this function with an argument of our currentUser object.

After that, all that's left is saving everything. I don't program with javascript, but I was still able to come up with the above solution by looking at the Parse Cloud Code docs, and searching around on their support forums.

If you take my template from above, and make some small changes, then you should be able to easily accomplish what you need. You just have to jump through these extra hoops because the Parse SDK doesn't want a situation where someone can login and somehow make changes to another user's account, whether by their own fault or a developer's mistake.

EDIT:

Here is the code to add the relationship for the current user:

PFRelation *friendsRelation = [[PFUser currentUser]relationforKey:@"friendsRelation"];

PFUser *user = [self.parseUsers objectAtIndex:indexPath.row];

[friendsRelation addObject:user];
[currentUser saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (error) {
NSLog(@"%@ %@", error, [error userInfo]);
}
}];

And then you can call the Cloud Code method right after:

    [PFCloud callFunction:@"editUser" withParameters:@{
@"userId": user.objectId
}];

Parse PFUser.currentUser returns nil - Swift

I discovered that this problem appeared because the segue signInToNavigation was wired from the Login-button, instead from the login view controller itself. This resulted in the segue being executed before the login function was executed, and therefore the PFUser.currentUser()object was not yet assigned when the table view loaded. I solved this by rewiring the segues. Stupid slip-up on my side.

Thanks to Ryan Kreager and Wain for taking time to help me figure out this issue!

Query on local datastore with [PFUser currentUser] returns no objects

As per our discussion above;

Provided you have an active PFUser session, then that user will autonomously be designated as the owner. Even if you don't have a current session and there is no [PFUser currentUser] local datastore is owned by the device. For now, local datastore is prejudice. Since apps are sandboxed and you have no writing privileges outside of your own resource bundle, another user can not change alter/update your local datastore. Even with the backend, you can not update any users information in the User class, unless your the current user or have writing privileges. With local datastore, it's always assumed you are the "current user", regardless of the session. However, if you do want to ignore Roles for protected information in local datastore you can see their notes here :

https://parse.com/docs/ios_guide#users-lds/iOS

The same security model that applies to objects in Parse applies to objects in the Local Datastore. Read-write permissions are defined by PFACLs and a user cannot access or modify anything they don't have permission to.

The only difference is that you won't be able to access any data protected by Role based ACLs due to the fact that the Roles are stored on the server. To access this data protected by Role based ACLs, you will need to ignore ACLs when executing a Local Datastore query

However, I don't feel you need this considering your circumstance.

Define mutual relation between two user with Parse JavaScript

You aren't changing the currentUser so calling currentUser.save() will not do anything.

Also when getting an existing user you should do the following:

Parse.Cloud.define('editUser', function(request, response) {
Parse.Cloud.useMasterKey();

var userQuery = new Parse.Query(Parse.User);

userQuery.get(request.params.userId)
.then(function (user) {
var relation = user.relation("sampleRelation");
relation.add(request.user);
// chain the promise
return user.save();
}).then(function (user) {
var currentUser = request.user;
var relation = currentUser.relation("sampleRelation");
relation.add(user);
// chain the new promise
return currentUser.save();
}).then(function () {
response.success();
}, function (error) {
response.error(error);
});
});

Parse doesn't return PFObject

Parse doesn't fetch for you automatically, except a few pieces of data in specific scenarios. Like, when a user logs in the current user will be fetched and will include the standard user data - but it won't include any custom data.

If you fetch an object then that objects details will be downloaded, but the details of related objects won't - unless you specifically request it to be included in the query that you make (using includeKey:).

It's generally best to always use fetchIfNeededInBackgroundWithBlock: if you aren't sure whether the data you need has been obtained yet. Not doing this shouldn't cause a crash but it will generally cause you issues with missing information. It's possible that the crash is related to parse using exceptions for navigation in the framework, but that's a guess and you might want to try contacting parse to see if you can get more details.

Subclassing PFUser. Accessing current user

If you check PFUser.h in Parse library, you will see currentUser returns instancetype.

+ (instancetype)currentUser;

This means that if you subclass PFUser, then currentUser returns an object of the type of the subclass, which is MyUserSubclass in your case.

Here is a short example of subclassing PFUser:

User.h

#import <Parse/Parse.h>

@interface User : PFUser <PFSubclassing>

@property (nonatomic, strong) NSString *firstName;

+ (User *)user;
+ (BOOL)isLoggedIn;

@end

User.m

#import "User.h"
#import <Parse/PFObject+Subclass.h>

@implementation User

@dynamic firstName;

+ (User *)user {
return (User *)[PFUser user];
}

+ (BOOL)isLoggedIn
{
return [User currentUser] ? YES: NO;
}

@end

Notice that I need to implement a +(User *)user; method, because in PFUser.h it is +(PFUser *)user; rather than instancetype.

PFUser Subclassing: Local-Only (non-db) User Properties?

I would override the saveInBackground: method in your PFUser subclass in order to accomplish your goal. Something like this:

Header file:

@interface PFUserSubclass : PFUser

@property (nonatomic, strong) NSString *customPropertyToSave;
@property (nonatomic, strong) NSString *customPropertyToIgnore;

- (void)saveInBackgroundWithBlock:(PFBooleanResultBlock)block;

@end

Implementation file:

@implementation PFUserSubclass

@synthesize customPropertyToSave;
@synthesize customPropertyToIgnore;

- (void)saveInBackgroundWithBlock:(PFBooleanResultBlock)block {
PFUser *userToSave = [PFUser currentUser];
[userToSave setObject:self.customPropertyToSave forKey:@"customProperty"];
[userToSave saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
block(succeeded, error);
}];
}

@end


Related Topics



Leave a reply



Submit