How to restore in-App purchases with Parse? - swift

I would like to create a "Restore in-App" button because it is required by Apple. I am using Parse for my iAP product and I used this code to do that:
PFPurchase.buyProduct("iapbanner", block: { (error:NSError!) -> Void in
if error != nil {
let alert = UIAlertController(title: "Errore", message: error?.localizedDescription, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
} else {
self.opzioniTableView.reloadData()
}
})
This works fine. Though, in the Parse's documentation it's not mentioned how to restore your iAp so I'm asking you.

Use PFPurchase.restore() to restore purchases with Parse. I'm not sure why they don't have this in their docs.

Related

Password reset not checking for existing users

In my password reset function the user can put in whatever he/she wants. It does not even needs to be a email address.
I would like to check for a valid email address, and that the email is registered in Parse Server
#IBAction func forgotPasswordButtonTapped(_ sender: Any) {
let forgotPasswordAlert = UIAlertController(title: "Forgot password?", message: "Please enter your email address", preferredStyle: .alert)
forgotPasswordAlert.view.tintColor = UIColor.red
forgotPasswordAlert.addTextField { (textField) in
textField.placeholder = "Email address"
}
forgotPasswordAlert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
forgotPasswordAlert.addAction(UIAlertAction(title: "Reset password", style: .default, handler: { (action) in
let resetEmail = forgotPasswordAlert.textFields?.first?.text
PFUser.requestPasswordResetForEmail(inBackground: resetEmail!, block: { (success, error) in
if error != nil {
let resetFailedAlert = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
resetFailedAlert.view.tintColor = UIColor.red
resetFailedAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(resetFailedAlert, animated: true, completion: nil)
} else {
let resetEmailSentAlert = UIAlertController(title: "Password reset instructions sendt", message: "Please check your email", preferredStyle: .alert)
resetEmailSentAlert.view.tintColor = UIColor.red
resetEmailSentAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(resetEmailSentAlert, animated: true, completion: nil)
}
})
}))
//PRESENT ALERT
self.present(forgotPasswordAlert, animated: true, completion: nil)
}
In your action you can check for email validity:-
forgotPasswordAlert.addAction(UIAlertAction(title: "Reset password", style: .default, handler: { (action) in
let resetEmail = forgotPasswordAlert.textFields?.first?.text
if self.isValidEmail(testStr: resetEmail) {
// Check of email registered on server should be done via this API and API should return error based on that.
PFUser.requestPasswordResetForEmail(inBackground: resetEmail!, block: { (success, error) in
if error != nil {
let resetFailedAlert = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
resetFailedAlert.view.tintColor = UIColor.red
resetFailedAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(resetFailedAlert, animated: true, completion: nil)
} else {
let resetEmailSentAlert = UIAlertController(title: "Password reset instructions sendt", message: "Please check your email", preferredStyle: .alert)
resetEmailSentAlert.view.tintColor = UIColor.red
resetEmailSentAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(resetEmailSentAlert, animated: true, completion: nil)
}
})
} else {
//Show error that email entered is not correct format
// present the reset email alertbox again.
}
}))
func isValidEmail(testStr:String) -> Bool {
let emailRegEx = "[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
let emailTest = NSPredicate(format:"SELF MATCHES %#", emailRegEx)
return emailTest.evaluate(with: testStr)
}
There is a parse email adapter to verify emails.
Verifying user email addresses and enabling password reset via email requires an email adapter. As part of the parse-server package we provide an adapter for sending email through Mailgun. To use it, sign up for Mailgun, and add this to your initialization code:
https://github.com/parse-community/parse-server
In regard to Parse Server not notifying the client that a user with the provided email address does not exist:
Pre 3.1.0 of Parse Server the request to reset a password returned an error if the email address was not found however this is a security risk as it allows an attacker to obtain user data for use in a brute force attack - see this explanation.
You can also take a look at the changelog and the PR that implemented this change.
It would still be possible to implement this yourself by querying the User class before making the password reset request. However, this should not be done in client code as it would require user data to be publicly accessible which is a major breach of privacy. It could also be implemented in cloud code using the master key so that user data could remain inaccessible to the public but this would present the same security risk mentioned above.

Display an alert within an alert

I am trying to display an alert that takes user input and then pops up the text that has been given
#IBAction func forgotPassword(_ sender: Any) {
//1. Create the alert controller.
let alert = UIAlertController(title: "Email Recovery", message: "Enter your email to recover your account", preferredStyle: .alert)
//2. Add the text field. You can configure it however you need.
alert.addTextField { (textField) in
textField.text = ""
}
// 3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert] (_) in
let textField = alert?.textFields![0] // Force unwrapping because we know it exists.
print("An email has been sent to \(String(describing: textField?.text)) for account recovery")
}))
// 4. Present the alert.
self.present(alert, animated: true, completion: nil)
}
The input works fine as well the output although instead of giving another alert, it just prints what I need in the console.
Am I missing something?
I guess you misunderstood a bit: "print" is just printing on your console, if you want to open a new alert after touching on the "ok" button, you may want to complete your code with:
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert, weak self] (_) in
let message = "An email has been sent to \(alert?.textFields?.first?.text ?? "") for account recovery"
let innerAlert = UIAlertController(title: nil, message: message, preferredStyle: .alert)
innerAlert.addAction(UIAlertAction(title: "OK", style: .default, handler:nil))
self?.present(innerAlert, animated: true, completion: nil)
}))

Error in console using UIAlertAction Xcode 7.3 beta

I am trying to print the error to the user using alertview.
Here is my code :::
if error != nil{
let DisplayAlert = UIAlertController(title: "Error!!", message: error?.description, preferredStyle: .Alert)
DisplayAlert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
}
When I run the code I see the following in the console and I do not see any alert displayed to user.
"Attempting to load the view of a view controller while it is deallocating is not allowed and may result in undefined behavior"
What should i do to fix this issue.? Pls help.
Thanks !!!
Looks like you have forgot to present the alert
if error != nil{
let DisplayAlert = UIAlertController(title: "Error!!", message: error?.description, preferredStyle: .Alert)
DisplayAlert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
self.presentViewController(DisplayAlert, animated: true, completion: nil)
}

Cannot call value of non-function type UIAlertAction

I'm not sure what's wrong with this function. I'm trying to present an alert asking if the user would like to delete the selected photo.
If the function that deletes the photo returns an error, I would like to show that error to the user.
Xcode is failing on the errorController.addAction line with the message that "cannot call value of non-function type UIAlertAction"
I'm using Swift 2
#IBAction func deletePhoto(sender: AnyObject) {
let alertController = UIAlertController(title: "Delete Photo", message: "Are you sure you want to delete this photo?", preferredStyle: .Alert)
let okAction = UIAlertAction(title: "OK", style: .Default) { UIAlertAction in
self.photoGateway!.delete(self.photo!.id!, completion: { (withError: Bool) -> Void in
if (withError == true) {
let errorController = UIAlertController(title: "Delete Failed", message: "blah", preferredStyle: UIAlertControllerStyle.Alert)
// The next line is causing the error
errorController.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(errorController, animated: true, completion: nil)
} else {
self.dismissViewControllerAnimated(true, completion: nil)
}
})
}
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { UIAlertAction in
print("Cancelled")
}
alertController.addAction(okAction)
alertController.addAction(cancelAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
If I take out the offending line then all works well, just the user has no way of dismissing the alert
Fixed it. Changed:
errorController.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
to:
errorController.addAction(UIKit.UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
The reason this is happening is because the parameter for your callbacks is called UIAlertAction (lines 3 and 20 above) and this is overriding the declaration in UIKit. This is likely a mistake of code-completion. Just rename it to action or something like that or just _ as you don't reference it.

UIAlertController Showing With Delay

I am having a lot of delay with my UIAlert, whenever it loads I have to wait before I can click and then again for it to fully disappear. I have looked at other answers that recommended using dispatch_async(dispatch_get_main_queue(), {}). I have tried using this but to no avail. The alert pops up during the render loop for a scene kit game I am making (the scene is just a cube and when I pause the scene it is still delayed). Shouldn't rendering be done in the render thread anyway. I looked the through the time profile log to see if something was blocking the Main Thread but I did not see anything that caught my attention (I fairly new to the instruments).
Here is my code where I am creating the alert:
func share(){
print("share funciton")
let alert = UIAlertController(title: "Share", message: "Where do you want to share?", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Twitter", style: .Default, handler: {(alert: UIAlertAction!) in
print("twitter")
self.showTwitter()
}))
self.presentViewController(alert, animated: false, completion: nil)
}
private func showTwitter() {
if SLComposeViewController.isAvailableForServiceType(SLServiceTypeTwitter) {
let tweetShare:SLComposeViewController = SLComposeViewController(forServiceType: SLServiceTypeTwitter)
self.presentViewController(tweetShare, animated: true, completion: nil)
} else {
let alert = UIAlertController(title: "Accounts", message: "Please login to a Twitter account to tweet.", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
}
Then I call share() when in the render loop with a dispatch_asych. I've been working at this bug for three days but have no idea what's causing the delay.
Try turning slow animations off. Open simulator -> debug -> slow animations