I'm having trouble understanding Firebase's documentation. In my Login ViewController, I have a button that allows users to reset password. So when user presses the button, it opens an alert controller where user would have to input their email to be sent a password reset/ recovery.
#IBAction func forgottenPassword(sender: AnyObject) {
var loginTextField: UITextField?
let alertController = UIAlertController(title: "Password Recovery", message: "Please enter your email address", preferredStyle: .Alert)
let ok = UIAlertAction(title: "OK", style: .Default, handler: { (action) -> Void in
if loginTextField?.text != "" {
DataService.dataService.BASE_REF.resetPasswordForUser(loginTextField?.text, withCompletionBlock: { (error) in
if (error == nil) {
self.showErrorAlert("Password reset", msg: "Check your inbox to reset your password")
} else {
print(error)
self.showErrorAlert("Unidentified email address", msg: "Please re-enter the email you registered with")
}
})
}
print("textfield is empty")
})
let cancel = UIAlertAction(title: "Cancel", style: .Cancel) { (action) -> Void in
}
alertController.addAction(ok)
alertController.addAction(cancel)
alertController.addTextFieldWithConfigurationHandler { (textField) -> Void in
// Enter the textfiled customization code here.
loginTextField = textField
loginTextField?.placeholder = "Enter your login ID"
}
presentViewController(alertController, animated: true, completion: nil)
}
func showErrorAlert(title: String, msg: String) {
let alert = UIAlertController(title: title, message: msg, preferredStyle: .Alert)
let action = UIAlertAction(title: "OK", style: .Default, handler: nil)
alert.addAction(action)
presentViewController(alert, animated: true, completion: nil)
}
Does the Firebase Backend server automatically generate the code to send the user a reset to their email?
Would i have to provide further code? Such as sendPasswordResetForEmail()? ... Or does the Firebase Backend service handles it from here? ...
Is that the function you are looking for ?
resetPasswordForUser(email:withCompletionBlock:)
Just call it on your Firebase instance.
Then go to your app dashboard to customize email that will be send to user upon password changes.
Related
I was hoping someone could help me with storing the data inputted into my alertView textField to firebase firestore. I have a collection called "HelpRequests" and I want the information to be stored in that collection. Below is the code for the alert.
#objc func alertTapped(sender:UIButton!){
let alert = UIAlertController(title: "Report an issue", message: "Please allow 24hour to respond", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Done", style: .default) { (action) in
if let te = alert.textFields?.first?.text , te.count > 0 {
}
})
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { (action) in
// Respond to user selection of the action.
})
alert.addTextField { (textField) in
textField.placeholder = ""
}
self.present(alert, animated: true)
}
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.
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)
}))
In the following code, it is successfully implemented. Just need one modification. When the app initially opens the admin password should take a default password "Hello" and then when the user has access to the admin password, will edited and save it and then it will be in the key "admin password"
How can I make that default password possible on the first?
func enableSectionAlert() {
let alertController = UIAlertController(title: "Admin Password", message: "Please input admin password", preferredStyle: .alert)
let enable = UIAlertAction(title: "Enable", style: .default) { (_) in
let field = alertController.textFields?[0].text
if let x = UserDefaults.standard.string(forKey: "admin password"), x == field {
self.demosSelectionEnabled()
self.showSection.isUserInteractionEnabled = false
self.showSection.textLabel?.textColor = UIColor.lightGray
}
else{
let wrongPwd = UIAlertController(title: "Wrong Admin Password", message: nil, preferredStyle:UIAlertControllerStyle.alert)
wrongPwd.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil))
self.present(wrongPwd, animated: true, completion: nil)
}
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (_) in }
alertController.addTextField { (textField) in
textField.placeholder = "Admin Password"
textField.isSecureTextEntry = true
}
alertController.addAction(enable)
alertController.addAction(cancelAction)
self.present(alertController, animated: true, completion: nil)
}
}
You can initialize a textfield with initial text this way
alertController.addTextField { (textField) in
textField.text = "Hello"
textField.isSecureTextEntry = true
}
I believe you want the default password to be "Hello", and have the option to change this later, and persist in userDefaults.
If this is the case, why not initially set the default value as follows:
UserDefaults.standard.set("Hello", forKey: "admin password")
Set it just once in maybe AppDelegate, using the following method:
private func setDefaultPassword() {
if UserDefaults.standard.string(forKey: "admin password") == nil {
UserDefaults.standard.set("Hello", forKey: "admin password")
}
}
If I understand you correctly you want that the password "Hello" allows the user to login after they installed the app. Once they are logged in they can change the password, right?
Do archive this check in the applicationDidLaunch method of your AppDelegate if a value for the key admin password is set. UserDefaults.standard.string returns nil if there is no value set for this key. If you get nil from this call just set the string to Hello.
This allows the user to login with Hello until the password save in the user defaults is changed.
I'm having problems getting a text fields value from a UIAlertController. I am getting the value, but It seems to be executing my code in the wrong order. In the function below, I expect the function call to return a string, but the value is not set at the time the function returns.
#IBAction func btnSaveSession(sender: AnyObject) {
//Prompt user to enter session name
var sessionName: String = ""
sessionName = promptUserToEnterSessionName("Save Session", message: "Please enter the name of your custom session below.");
print("session Name: " + sessionName)
//Save session to firebase.
//redirect to create session controller.
}
func promptUserToEnterSessionName(title: String, message: String) -> String{
var sessionName: String = ""
//1. Create the alert controller.
let alert = UIAlertController(title: title, message: message, preferredStyle: .Alert)
//2. Add the text field. You can configure it however you need.
alert.addTextFieldWithConfigurationHandler({ (textField) -> Void in
textField.text = "Enter session name."
})
//3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: { (action) -> Void in
let textField = alert.textFields![0] as UITextField
print("Text field: \(textField.text)")
sessionName = textField.text!
}))
// 4. Present the alert.
self.presentViewController(alert, animated: true, completion: nil)
return sessionName
}
If anyone is having problems understanding my question, please comment and I will do my best to explain.
your ok action handler(closure) will call when you click on ok button. so instead of assign value to local variable sessionName , make a sessionName variable in class.
class YourClass {
var sessionName: String?
...
#IBAction func btnSaveSession(sender: AnyObject) {
//Prompt user to enter session name
promptUserToEnterSessionName("Save Session", message: "Please enter the name of your custom session below.");
}
func promptUserToEnterSessionName(title: String, message: String) {
//1. Create the alert controller.
let alert = UIAlertController(title: title, message: message, preferredStyle: .Alert)
//2. Add the text field. You can configure it however you need.
alert.addTextFieldWithConfigurationHandler({ (textField) -> Void in
textField.text = "Enter session name."
})
//3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: { (action) -> Void in
let textField = alert.textFields![0] as UITextField
print("Text field: \(textField.text)")
self.sessionName = textField.text!
self.testDemo()
}))
// 4. Present the alert.
self.presentViewController(alert, animated: true, completion: nil)
}
fun TestDemo() {
print("session Name: " + self.sessionName)
//Save session to firebase.
//redirect to create session controller.
}
}
You can use a Callback to get the value, like this:
func AlertPrompt(vista:UIViewController, titulo:String , mensaje:String, aceptar:String, completion: #escaping (_ resultado: String)->()) {
let miAlerta = UIAlertController(title: titulo, message: mensaje, preferredStyle: UIAlertControllerStyle.alert)
miAlerta.addTextField(configurationHandler: {
(textField) -> Void in
})
let okBoton = UIAlertAction(title: aceptar, style: UIAlertActionStyle.default, handler: {
(action) -> Void in
let result = miAlerta.textFields![0] as UITextField
// You return the value here
completion(result.text! as String)
})
miAlerta.addAction(okBoton)
let cancelBoton = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel, handler: nil)
miAlerta.addAction(cancelBoton)
vista.present(miAlerta, animated: true, completion: nil)
}
And call the function like this:
AlertPrompt(vista: self, titulo: "Title", mensaje: "some message", aceptar: "Acept"){(resultado)->() in
print(resultado)
}
That works perfect for me, hope this help
This code:
let textField = alert.textFields![0] as UITextField
print("Text field: \(textField.text)")
sessionName = textField.text!
will be called only at the moment the button corresponding to the defined action is clicked. So at the moment of creation the UIAlertController it's not called.
Read about blocks in Swift, it should be clearer then.