Changing field in PFUser from other PFUser, Parse iOS - ios

I am attempting to change the value of another PFUser field, from another unauthenticated PFUser in Parse, however I cant seem to do so. I am attempting to increase the number of 'hours' of one user from another user. Here is how I am attempting to do so:
PFUser *currentUser = [PFUser currentUser];
PFACL *ACL = [PFACL ACLWithUser:[PFUser currentUser]];
[ACL setPublicReadAccess:YES];
PFUser *selectedUser = [self.formValues objectForKey:#"user"];
NSLog(#"User ID: %#", selectedUser.objectId);
PFObject *volunteerSheet = [PFObject objectWithClassName:#"VolunteerSheet"];
volunteerSheet[#"userID"] = selectedUser.objectId;
volunteerSheet[#"fromID"] = currentUser.objectId;
volunteerSheet[#"volunteerTitle"] = [self.formValues objectForKey:#"title"];
volunteerSheet[#"location"] = [self.formValues objectForKey:#"location"];
volunteerSheet[#"volunteerHours"] = [self.formValues objectForKey:#"hours"];
volunteerSheet[#"volunteerDescription"] = [self.formValues objectForKey:#"description"];
volunteerSheet.ACL = ACL;
[volunteerSheet saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (succeeded) {
// The object has been saved.
PFQuery *query = [PFQuery queryWithClassName:#"_User"];
// Retrieve the object by id
[query getObjectInBackgroundWithId:selectedUser.objectId
block:^(PFObject *user, NSError *error) {
[user incrementKey:#"volunteerHours" byAmount:(NSNumber*)[self.formValues objectForKey:#"hours"]];
[user saveInBackgroundWithBlock:^(BOOL succeeded, NSError * _Nullable error) {
if (succeeded) {
NSLog(#"Succeeded");
}else{
NSLog(error.description);
}
}];
}];
NSLog(#"Saved");
[self dismissViewControllerAnimated:YES completion:^{
UIAlertView * alert =[[UIAlertView alloc ] initWithTitle:#"Success!"
message:#"Hours Sent succesfully."
delegate:self
cancelButtonTitle:nil
otherButtonTitles: nil];
[alert addButtonWithTitle:#"Okay"];
[alert show];
}];
} else {
// There was a problem, check error.description
NSLog(#"Error: %#",error.description);
}
}];

Users automatically have security put in place that disallow modifying another user (clps or alcs). Maybe consider moving to cloud code and calling use master key?

Users have ACLs set up to only allow themselves to change their values. To get around this, you either have to change the ACL every time you create a user to allow any user to have write permissions for them (VERY RISKY AND NOT SECURE AT ALL), or you need to call a cloud function that calls Parse.Cloud.useMasterKey() , which overrides all permissions, and will enable you to make the changes. Obviously, you should still be doing some sort of security check to make sure that these changes are allowed / proper changes before putting them through.

Related

Twitter login issue Parse.com iOS

I recently deleted all the multiple duplicate files from my mac and that messed up my xcode project. I had to import all the twitter frameworks again and had to delete the twitter run script for my app to work. Before my mess up everything worked fine.
Now everytime i login into with twitter this error comes up TWTRLogInButton was created with no completionBlock set
my code that worked perfectly:
- (IBAction)twlogin:(TWTRLogInButton *)sender {
[PFTwitterUtils logInWithBlock:^(PFUser *user, NSError *error) {
if (error) {
}
else {
PF_Twitter *twitter = [PFTwitterUtils twitter];
PFUser *user = [PFUser currentUser];
NSString *twitterScreenName = twitter.screenName;
[[PFUser currentUser] setObject:twitterScreenName forKey:#"username"];
[user saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error)
{
if (error)
{
UIAlertView *alertVeiw = [[UIAlertView alloc] initWithTitle:#"Sorry" message:[error.userInfo objectForKey:#"error"] delegate:nil cancelButtonTitle:nil otherButtonTitles:#"OK", nil];
[alertVeiw show];
}
else {
[[PFInstallation currentInstallation] setObject:[PFUser currentUser].objectId forKey:#"userId"];
[[PFInstallation currentInstallation] saveInBackground];
[self.navigationController popToRootViewControllerAnimated:NO];
}
}];
[self.navigationController popToRootViewControllerAnimated:NO];
}
}];
}
Please help me fix my issue.
It looks like there may be a bug in the Parse Twitter SDK. Many people are having this problem today. check this link https://developers.facebook.com/bugs/914545211986956/
You may be defining the button in the storyboard or xib file, and the completionBlock needs to be set programmatically. If you define it in the storyboard and your viewDidLoad, the app is probably presenting the button from the storyboard. So, in viewDidLoad, define it:
self.myTwitterLoginButton.logInCompletion = ^(TWTRSession *session, NSError *error) {
/* your code */
};
Edit:
In addition, don't hook up the twlogin action event in the storyboard. Your current action will end up in the completion block. Do hook the button up to an IBOutlet property and do not recreate it. In my code above, the IBOutlet is to myTwitterLoginButton.

How do I get notified when a PFObject is saved to my Parse backend?

I have followed the Quick Start Guide for parse:
https://parse.com/apps/quickstart#parse_data/mobile/ios/native/existing
I'm using this code to save a PFObject:
PFObject *testObject = [PFObject objectWithClassName:#"TestObject"];
testObject[#"Bookmarks"] = #"Restore Successful";
[testObject saveInBackground];
Below is what it looks like when my PFObject is saved to my Parse backend:
I would like to receive some sorta notification when this happens. Like an email, a text or a push notification. Anything that works.
Parse's recommended way of doing it is using Cloud Code. Once, you configure it, in the main.js file add the following function:
Parse.Cloud.afterSave("Posts", function(request) {
// Gets called when a new object is added to the 'Posts' class.
// From here you can proceed to send push notifications
});
The afterSave method it's triggered after a new object is added to the specified class. If you want to manage, whether or not an object should be saved, look into beforeSave.
Quick example I just put together: example:
-(void)saveLesson {
lesson = [PFObject objectWithClassName:#"lessons"];
PFObject *photo = [PFObject objectWithClassName:#"photoslessons"];
[photo setObject:[PFUser currentUser] forKey:#"userId"];
[photo setObject:self.photoFile forKey:#"lessonimage"];
[photo setObject:self.smallPhotoFile forKey:#"smalllessonimage"];
[photo setObject:self.thumbnailFile forKey:#"thumblessonimage"];
[photo setObject:self.originalFile forKey:#"originallessonimage"];
PFACL *publicACL = [PFACL ACL];
[publicACL setPublicWriteAccess:YES];
[publicACL setPublicReadAccess:YES];
photo.ACL = publicACL;
self.photoPostBackgroundTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:self.photoPostBackgroundTaskId];
}];
[photo saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (succeeded) {
NSLog(#"Photo uploaded");
NSNumber *userCount = [[NSNumber alloc] initWithInt:0];
lesson[#"textBody"] = [[[self contentView] descriptionText] text];
lesson[#"title"] = [[[self contentView] title] text];
lesson[#"likes"] = userCount;
lesson[#"times_viewed"] = userCount;
lesson[#"featured"] = #"false";
lesson[#"userId"] = [PFObject objectWithoutDataWithClassName:#"_User" objectId:[PFUser currentUser].objectId];
lesson[#"lessonimage"]= photo;
[lesson saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (succeeded) {
PFQuery *query = [PFQuery queryWithClassName:#"activesessions"];
[query whereKey:#"teacherid" equalTo:[PFUser currentUser]];
[query getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error) {
if (object!=nil) {
[object setObject:lesson forKey:#"lessonid"];
[object saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (succeeded) {
[(NSHLiveStudentProfileViewController*)self.navigationController.viewControllers[0] thisIsAHack];
[[self navigationController] popToRootViewControllerAnimated:true];
}
}];
}}];
} else if (error) {
NSString * alertTitle = #"Error Saving Lesson";
UIAlertController * alert = [UIAlertController alertControllerWithTitle:alertTitle message:#"Please make sure to include both a title and description." preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* ok = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { }];
[alert addAction:ok];
[self presentViewController:alert animated:YES completion:^{}];
}
}];
} else {
NSLog(#"Photo failed to save: %#", error);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Couldn't post your photo" message:nil delegate:nil cancelButtonTitle:nil otherButtonTitles:#"Dismiss", nil];
[alert show];
}
[[UIApplication sharedApplication] endBackgroundTask:self.photoPostBackgroundTaskId];
}];
}
So, that's a lot of code, but here's what we are going to do to help you out, lets add a method to send yourself an email:
First off, download load the pod mailgun:
then do this:
Mailgun *mailgun = [Mailgun clientWithDomain:kMailGunAPIClientDomain apiKey:kMailGunAPIKey];
Also, sign up for a mail gun account, and send an email to yourself
Then in the code above, whenever and object is saved with "success" in the block like this:
first off, obviously change this:
#"Peter Pan <peterpan.notarealemailaddress#gmail.com>"
to your mail address and then fill in the portions that require your API key and such that you get from MailGun, mailgun is cheap and this works for you immediately as soon as you set up the mail gun account (I dont work for mailgun, I'm jut a happy user)
[lesson saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (succeeded) {
[mailgun sendMessageTo:#"Peter Pan <peterpan.notarealemailaddress#gmail.com>"
from:#"Excited User <apeterpan.notarealemailaddress#gmail.com>>"
subject:#"Mailgun is awesome!"
body:#"and life is great!"];
boom!,
Here's the MailGun pod: https://github.com/rackerlabs/objc-mailgun
Sign up for a free account at: http://www.mailgun.com/
Test it out, the neat thing about this, is it's auto trigger and you can put whatever you want inside the email call that I've placed here, you also need to get AFNetworking:
get it here: https://github.com/AFNetworking/AFNetworking
This method doesn't require any sort of javascript cloudcoding and you can even substitute the body of your email for the informaiton you want to send to yourself. If you want to send yourself the USER ID of the person who just triggered your method, then there you have it, the email will be sent.
So you have this:
PFObject *testObject = [PFObject objectWithClassName:#"TestObject"];
testObject[#"Bookmarks"] = #"Restore Successful";
[testObject saveInBackground];
Change it to this:
PFObject *testObject = [PFObject objectWithClassName:#"TestObject"];
testObject[#"Bookmarks"] = #"Restore Successful";
[testObject saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (succeeded) {
NSLog(#"successfully SAVED!");
}
}];
this is your custom save function:
-(void)customSaveFunction {
PFObject *testObject = [PFObject objectWithClassName:#"TestObject"];
testObject[#"Bookmarks"] = #"Restore Successful";
[testObject saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (succeeded) {
NSLog(#"successfully SAVED!");
Mailgun *mailgun = [Mailgun clientWithDomain:kMailGunAPIClientDomain apiKey:kMailGunAPIKey];
[mailgun sendMessageTo:#"Peter Pan <peterpan.notarealemailaddress#gmail.com>"
from:#"Excited User <apeterpan.notarealemailaddress#gmail.com>>"
subject:#"Mailgun is awesome!"
body:#"and life is great!"];
}
}];
}
I showed the save lesson example as something where you can send multiple emails with multiple information in the email for differnet save triggers, but this code is useless to me now, this was used for major testing purposes only, so the custom save function that I posted above these few sentences is how you would do it yourself, or just put that same code in your viewcontroller or whereever you save your objects.

iOS-Parse How to retrieve an object given a username?

I have two ViewControllers, in the first one, there are 3 key-value pairs in each PFObject, save them to parse after clicking a button. In the second ViewController, I want to create another property and save it to the same PFObject. Here is my code:
in the first ViewController:
- (void)next
{
PFObject *thisuser = [PFObject objectWithClassName:#"User"];
thisuser[#"name"] = [PFUser currentUser].username;
thisuser[#"institution"] = institution.text;
thisuser[#"major"] = major.text;
[thisuser saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error)
{
if (succeeded)
{
GuideViewController2 *GVC2 = [[GuideViewController2 alloc]initWithNibName:#"GuideViewController2" bundle:nil];
UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:GVC2];
nav.modalPresentationStyle = UIModalPresentationFullScreen;
nav.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentViewController:nav animated:YES completion:nil];
NSLog(#"success");
}
else
{
NSLog(#"nope");
}
}];
}
and in my second view controller, the user can upload a profile photo, i want this photo to be saved in the same PFObject. So is there a way to retrieve an object using [PFUser currentUser].username property? How do i get this user object under the User class in order to add a photo key-value pair?
thx.
You can just query for the user:
PFQuery *query = [PFUser query];
[query whereKey:USERNAME_KEY equalTo:username];
[query getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error)
{
if (!error) {
//You found the user!
PFUser *queriedUser = (PFUser *)object;
}
}];
Supposing the username is actually unique! USERNAME_KEY would be your username field and username the actual username.

Parse: Cannot sign up a user created automatically

I'm using Parse 1.7.1 for iOS and I am trying to sign up a user. I chose to let the user interact with the app before I force the sign up / login process. The problem is that as soon as I call signUp the session object disappears from the server and causes any subsequent calls to return error 209.
Here's some code:
AppDelegate:
[PFUser enableAutomaticUser];
[[PFUser currentUser] incrementKey:#"runCount"];
[[PFUser currentUser] saveInBackground];
When I check the Parse Core console I can see a valid User & Session.
MyController:
PFUser *user = [PFUser currentUser];
if (! user) {
user = [PFUser user];
}
user.email = #"my#email.com";
user.password = #"somepassword";
user.username = #"whatever";
// I also tried Save instead of signUpInBackground... same result
[user signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (succeeded) {
NSLog(#"Success signing up");
}
else {
NSLog(#"Error %#", [error localizedDescription]);
}
}];
When I check the console there is an updated user but there is no Session anymore.
Any other API call
[Error]: invalid session token (Code: 209, Version: 1.7.1)
Despite the fact that the callback returns success as soon as I try to interact with the Parse API I get a 209, invalid session token. This is fair enough, since the session object is not present in the console.
Does anyone know what I am doing wrong?
Note: this a brand new app (not affected by the change made by Parse on the 25th of March)/.
I have raised this as a bug with Facebook and they are fixing it in 1.7.3
Here's the conversation I had with them.
Create button with selector -signUpSelector. And need implement this code:
-(void)signUpSelector
[PFUser becomeInBackground:#"session-token-here" block:^(PFUser *user, NSError *error) {
PFUser *newUser = nil;
if (error) {
newUser = [PFUser user];
} else {
newUser = user;
}
user.email = #"my#email.com";
user.password = #"somepassword";
user.username = #"whatever";
[user signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (succeeded) {
NSLog(#"Success signing up");
}
else {
NSLog(#"Error %#", [error localizedDescription]);
}
}];
}];

Parse -getObjectInBackgroundWithId not saving on the database

I have a code snippet that will update information in the Parse database. I set up an action so that when the information is saved, it gets updated in the background. The function is being executed, but it's not saving anything on the database. its going through the function, but no changes are being saved. The changed values are inside a text field and a switch.
- (IBAction)save:(id)sender {
NSLog(#"classnameinsave %#", self.productTitleField.text);
PFQuery *query = [PFQuery queryWithClassName:self.className];
[query getObjectInBackgroundWithId:self.productId block:^(PFObject *object, NSError *error) {
NSLog(#"inside getObjectsInBackgroundWithId function");
NSLog(#"priceinsave %#", object[#"price"]);
object[#"title"] = self.productTitleField.text;
object[#"price"] = self.priceField;
object[#"quantity"] = self.quantityField;
object[#"show"] = self.show;
[object saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if(succeeded){
NSLog(#"Succeeded in Saving");
}else if(error){
NSLog(#"Error with saving changes %#", error);
}
}];
}];
}
Most likely this happened because the PFObject you're looking for doesn't even exist! You forgot to add the if statement for verifying if the object exists. Also, I understand you want to make it as dynamic as possible by having the class name based on a UILabel, but please don't do this, this doesn't make sense at all. Replace your code with this:
PFQuery *query = [PFQuery queryWithClassName:#"ClassName"];
[query getObjectInBackgroundWithId:self.productId block:^(PFObject *object, NSError *error) {
if(object){
//Do everything here :)
}else{
//Display an UIAlertView to the user?
NSLog(error);
}
}];
Note: You should add the if statement, however it's not necessary.
Best regards,

Resources