#objc func registerButtonClicked()
{
//After Firebase is configured this is called
guard let email = emailTextField.text else {
alertBox(title: "Error", message: "All fields are mandatory")
return }
guard let password = passwordTextField.text else { return }
guard let name = nameTextField.text else { return }
Auth.auth().createUser(withEmail: email, password: password) { (data, error) in
if error != nil{
print(error.debugDescription)
print("Error occurred")
} else
{
print("Data -- >\(String(describing: data))")
self.saveDataInFirebase(name: name, password: password, email: email)
//here the data is saved in authentication table in firebase so next step //was to save its detail in db in json
}
}
}
func saveDataInFirebase(name: String, password: String, email: String)
{
let userData = ["name" : name, "email" : email]
print("name \(name) --- Email \(email)")
// printing the details to be saved in DB
let firebaseRef = Database.database().reference(fromURL: "https://chatdemo1-d3423.firebaseio.com/")
firebaseRef.updateChildValues(userData) { (error, dbRef) in
if error != nil{
print("------------------")
print(error.debugDescription)
print("----------------------")
}
else
{
print("Data Saved Successfully")
}
}
}
The code in the question is probably not what you want to use as it will overwrite your entire Firebase each time it's run.
The reason for that is you're not writing data to a child node of your Firbase, you are writing it to the main node. This is what's being written:
your_firebase //<- this is where you're writing too each time
email: "some email"
name: "some name"
my guess is you want to stucture it like this
your_firebase
user_id
email: "some email"
name: "some name"
and the code to do that would be
var ref: DatabaseReference!
func viewDidLoad() {
self.ref = Database.database().reference()
.
.
.
}
func createUser() {
let email = "some email"
let password = "some password"
let name = "some name"
Auth.auth().createUser(withEmail: email, password: password) { (authResult, error) in
if let x = error { //some fancy error checking
let err = x as NSError
switch err.code {
case AuthErrorCode.emailAlreadyInUse.rawValue:
print("email in use!")
default:
print("unknown error")
}
} else {
guard let user = authResult?.user else { return }
let uid = user.uid
let usersRef = self.ref.child("users")
let thisUserRef = usersRef.child(uid)
thisUserRef.child("email").setValue(email)
thisUserRef.child("name").setValue(name)
}
}
}
This code assumes the Firebase Rules allows the user permission to write the the users node
Related
I am trying to add an image to Firebase storage and then get the location of that image and store it in a Firestore document with the other user profile data. I am trying to do all of this when the user first creates an account. I was trying to use the image URL to do this but that does not appear to be working. When I run the code below it will sign up a new user and add the photo to Firebase storage but no document gets created in the Firestore database. What am I doing wrong?
#objc func handleSignUp() {
//Signup properties
guard let email = emailTextField.text else { return }
guard let password = passwordTextField.text else { return }
guard let fullName = fullNameTextField.text else { return }
guard let username = usernameTextField.text?.lowercased() else { return }
createUser(email: email,
password: password,
fullName: fullName,
userName: username)
}
func createUser(email: String, password: String, fullName: String, userName: String) {
Auth.auth().createUser(withEmail: email, password: password) { (authResult, error) in
//Handle error
if let error = error {
print("DEBUG: Failed to create user with error: ", error.localizedDescription)
return
}
guard let profileImg = self.plusPhotoBtn.imageView?.image else { return }
guard let uploadData = profileImg.jpegData(compressionQuality: 0.3) else { return }
let userID = Auth.auth().currentUser!.uid
let filename = NSUUID().uuidString
//Storage location for photo in Firebase
let storageRef = Storage.storage().reference().child("profile_images").child(userID).child(filename)
storageRef.putData(uploadData, metadata: nil, completion: { (metadata, error) in
//Handle error
if let error = error {
print("Failed to upload image to Firebase Storage with error", error.localizedDescription)
return
}
guard metadata != nil else { return }
let path = storageRef.fullPath;
guard let username = self.usernameTextField.text?.lowercased() else { return }
storageRef.downloadURL { (url, _) in
let data = ["name": fullName,
"username": username,
"profileImagePath": path,
"email" : email] as [String : Any]
self.addDocument(userData: data)
}
})
}
}
I think you should add the "downloadURL" part inside the "putData".
After completion of the put data process you should try to get the URL or else it will fail.
Try this and see if it works:
#objc func handleSignUp() {
//Signup properties
guard let email = email.text else { return }
guard let password = password.text else { return }
guard let fullName = name.text else { return }
guard let username = name.text?.lowercased() else { return }
createUser(email: email,
password: password,
fullName: fullName,
userName: username)
}
func createUser(email: String, password: String, fullName: String, userName: String) {
Auth.auth().createUser(withEmail: email, password: password) { (authResult, error) in
//Handle error
if let error = error {
print("DEBUG: Failed to create user with error: ", error.localizedDescription)
return
}
guard let profileImg = self.plusPhotoBtn.imageView?.image else { return }
guard let uploadData = profileImg.jpegData(compressionQuality: 0.3) else { return }
let filename = NSUUID().uuidString
//Storage location for photo in Firebase
let storageRef = Storage.storage().reference().child("profile_images").child(filename)
storageRef.putData(uploadData, metadata: nil, completion: { (metadata, error) in
//Handle error
if let error = error {
print("Failed to upload image to Firebase Storage with error", error.localizedDescription)
return
}
guard let metadata = metadata else { return }
guard let username = self.usernameTextField.text?.lowercased() else { return }
storageRef.downloadURL { (url, _) in
guard let downloadURL = url else {
print("DEBUG: Profile image url is nil")
return
}
let data = ["name": fullName,
"username": username,
"profileImageUrl": downloadURL,
"email" : email]
self.addDocument(userData: data)
}
})
}
}
func addDocument(userData: [String: Any]) {
Firestore.firestore().collection("profile_data").addDocument(data: userData) { (err) in
if let err = err {
debugPrint("Error adding document: \(err)")
} else {
self.navigationController?.popViewController(animated: true)
}
}
}
When creating a new user, I need to log them out and then send a verification email to ensure that they own the email address. Currently my code creates the user and executes the "sendEmailVerification" call but keeps the user logged in. How can I log my user out and check that they have verified their email?
func signUp(with email: String, password: String, firstName: String, lastName: String) {
self.presentActivityView()
Auth.auth().createUser(withEmail: email, password: password) {[unowned self] (user, error) in
DispatchQueue.main.async { [unowned self] in
self.dismissActivityView()
if let err = error {
self.addAlertController(title: "Error!", message: err.localizedDescription)
} else {
let changeReq = Auth.auth().currentUser?.createProfileChangeRequest()
changeReq?.displayName = firstName + " " + lastName
if let url = self.profilePicURLString {
changeReq?.photoURL = URL(string: url)
}
changeReq?.commitChanges(completion: { (error) in
if error == nil {
//Profile updated successfully
}else {
//Profile not updated successfully
}
})
Auth.auth().currentUser?.sendEmailVerification(completion: { (error) in
if error == nil {
//Verification initiated successfully
}else {
print("Error: \(error)")
}
})
let vc = MainStoryboard.instantiateViewController(withIdentifier: "SNStoryFeedController") as! SNStoryFeedController
let nc = UINavigationController(rootViewController: vc)
UIApplication.shared.keyWindow?.rootViewController = nc
}
}
}
}
The only thing you should do is sign out from your own application:
// for FIRAuth
try? Auth.auth()?.signOut()
// for GoogleSignIn
GIDSignIn.sharedInstance().signOut()
The safari part is handled by the system and you don't need to worry about.
I am trying to authenticate users. But the createNewUser() firebase method is returning nil in the closure for user?.user.uid and thus I cannot add the data under the correct node.
Bellow is my user creation method:
func createNewUser(email: String, password: String) {
Auth.auth().createUser(withEmail: email, password: password) { user, error in
if error == nil && user != nil { //user create works
print(user, "<-- User Created (user)")
} else { //user not create
print("Error creating user: \(error!.localizedDescription)")
}
//database integration
let ref = Database.database().reference()
let usersRef = ref.child("users2")
let uid = user?.user.uid
print(email, "<-- email")
print(uid, "<-- this is uid")
let newUserRef = usersRef.child(uid!)//This fails because UID is nil
newUserRef.setValue(["email": self.emailTextField.text!, "password": self.passwordTextField.text!, "fullName": self.fullNameTextField.text!, "username": self.usernameTextField.text!])
print(email, "<--- this is emaiL??")
} //end of create user
}
How do I fix this?
When I look at the docs for Firebase's "createUserWithEmail:password:completion:" method, it looks like you get an authResult, error back from Auth.auth().createUser(withEmail:....
And from that, to get the user, you'd do:
func createNewUser(email: String, password: String) {
Auth.auth().createUser(withEmail: email, password: password) { authResult, error in
guard let authResult = authResult, error == nil else {
print("Error creating user: \(error!.localizedDescription)")
return // an error!
}
if let user = authResult.user {
if let uid = user.uid {
print("uid is \(uid)")
}
if let email = user.email {
print("email is \(email)")
}
}
...
...
...
When i select register.. the data is sent to Firebase authentication but does not store in the database? Can anyone tell me where im going wrong?
func handleRegister(){
// Validation
guard let email = emailTextField.text, let password = PassTextField.text, let name = nameTextField.text
else{
print("Please provide an Email and Password")
return
}
FIRAuth.auth()?.createUser(withEmail: email, password: password, completion: { (user: FIRUser?, error) in
if error != nil {
print(error!)
return
}
// Successfully authenticated user
// Saving Data to the Database
let ref = FIRDatabase.database().reference(fromURL: "https://chat-47e5b.firebaseio.com/")
let values = ["name": name, "email": email]
ref.updateChildValues(values, withCompletionBlock: { (err,ref)
in
if err != nil {
print(err!)
return
}
print("Saved user successfully into Firebase")
})
})
}
You are not doing it right, you should first get a reference to the db:
self.ref = FIRDatabase.database().reference()
Then:
let values = ["name": name, "email": email]
self.ref.child("users").child(user.uid).setValue(values)
As a side note, convert this:
if error != nil {
print(error!)
return
}
To this:
guard let error = error else {
print(error)
return
}
I am building an app that uses Firebase's email and password login feature. I am having the user register with a username, email, and password. I am struggling with how to stop the user from being created if the username is not unique. I have been reading other questions (specifically Firebase-android-make-username-unique and how-prevent-username-from-duplicate-signup-infirebase) but I have still not gotten it to fully work.
I followed the instructions in the first link above and set up my data structure as:
app : {
users: {
"some-user-uid": {
email: "test#test.com"
username: "myname"
}
},
usernames: {
"myname": "some-user-uid"
}
}
and my security rules as:
"users": {
"$uid": {
".write": "auth !== null && auth.uid === $uid",
".read": "auth !== null && auth.provider === 'password'",
"username": {
".validate": "
!root.child('usernames').child(newData.val()).exists() ||
root.child('usernames').child(newData.val()).val() == $uid"
}
}
}
With this setup, if I try to create a new user with a username that already exists, it stops the user from being added to my data structure. When the below code is called, it prints "User Data could not be saved" if the username is a duplicate.
func createNewAccount(uid: String, user: Dictionary<String, String>) {
USER_REF.childByAppendingPath(uid).setValue(user, withCompletionBlock: {
(error:NSError?, ref:Firebase!) in
if (error != nil) {
print("User Data could not be saved.")
} else {
print("User Data saved successfully!")
}
})
}
func addUsernameToUsernamePath (userData: Dictionary<String, String>) {
USERNAME_REF.updateChildValues(userData)
}
Here is where I am stuck. My create account method below doesn't call the above two methods until createUser and authUser are called (Which I need to get the uid). My problem is the user still gets created as a registered user and my security rules just keep the users information from being added to my data structure. I need to figure out how to stop the user from being created if there is a duplicate username.
#IBAction func createAccount() {
let username = usernameField.text
let email = emailField.text
let password = passwordField.text
if username != "" && email != "" && password != "" {
// Set Email and Password for the New User.
DataService.dataService.BASE_REF.createUser(email, password: password, withValueCompletionBlock: { error, result in
if error != nil {
print("Error: \(error)")
if let errorCode = FAuthenticationError(rawValue: error.code) {
switch (errorCode) {
case .EmailTaken:
self.signupErrorAlert("Email In Use", message: "An account has already been created for this email address.")
default:
self.signupErrorAlert("Oops!", message: "Having some trouble creating your account. Please try again or check your internet connection.")
}
}
} else {
DataService.dataService.BASE_REF.authUser(email, password: password, withCompletionBlock: {
err, authData in
let user = ["provider": authData.provider!, "email": email!, "username": username!]
let userData = [username!: authData.uid!]
DataService.dataService.createNewAccount(authData.uid, user: user)
DataService.dataService.addUsernameToUsernamePath(userData)
})
EDIT
Here is my updated createAccount method that solved my issue.
#IBAction func createAccount() {
let username = usernameField.text
let email = emailField.text
let password = passwordField.text
if username != "" && email != "" && password != "" {
DataService.dataService.USERNAME_REF.observeEventType(.Value, withBlock: { snapshot in
var usernamesMatched = false
if snapshot.value is NSNull {
usernamesMatched = false
} else {
let usernameDictionary = snapshot.value
let usernameArray = Array(usernameDictionary.allKeys as! [String])
for storedUserName in usernameArray {
if storedUserName == self.usernameField.text! {
usernamesMatched = true
self.signupErrorAlert("Username Already Taken", message: "Please try a different username")
}
}
}
if !usernamesMatched {
// Set Email and Password for the New User.
DataService.dataService.BASE_REF.createUser(email, password: password, withValueCompletionBlock: { error, result in
if error != nil {
print("Error: \(error)")
if let errorCode = FAuthenticationError(rawValue: error.code) {
switch (errorCode) {
case .EmailTaken:
self.signupErrorAlert("Email In Use", message: "An account has already been created for this email address.")
default:
self.signupErrorAlert("Oops!", message: "Having some trouble creating your account. Please try again or check your internet connection.")
}
}
} else {
// Create and Login the New User with authUser
DataService.dataService.BASE_REF.authUser(email, password: password, withCompletionBlock: {
err, authData in
let user = ["provider": authData.provider!, "email": email!, "username": username!]
let userData = [username!: authData.uid!]
// Seal the deal in DataService.swift.
DataService.dataService.createNewAccount(authData.uid, user: user)
DataService.dataService.addUsernameToUsernamePath(userData)
})
You could allow sign up without a valid username, and have a separate "set username" screen that you show in the event of a partial registration.
Define your security rules to check for a non-null username before allowing writes to other parts of your database.
I was able to get it working by updating createAccount() to the code below.
#IBAction func createAccount() {
let username = usernameField.text
let email = emailField.text
let password = passwordField.text
if username != "" && email != "" && password != "" {
// Checks for internet connection before saving the meetup. Returns if there is no internet connection.
let reachability = try! Reachability.reachabilityForInternetConnection()
if reachability.currentReachabilityStatus == .NotReachable {
let internetAlert = UIAlertController(title: "No Internet Connection", message: "Please make sure your device is connected to the internet.", preferredStyle: .Alert)
let internetAlertAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
internetAlert.addAction(internetAlertAction)
presentViewController(internetAlert, animated: true, completion: nil)
return
}
DataService.dataService.USERNAME_REF.observeEventType(.Value, withBlock: { snapshot in
var usernamesMatched = false
if snapshot.value is NSNull {
usernamesMatched = false
} else {
let usernameDictionary = snapshot.value
let usernameArray = Array(usernameDictionary.allKeys as! [String])
for storedUserName in usernameArray {
if storedUserName == self.usernameField.text! {
usernamesMatched = true
self.signupErrorAlert("Username Already Taken", message: "Please try a different username")
}
}
}
if !usernamesMatched {
// Set Email and Password for the New User.
DataService.dataService.BASE_REF.createUser(email, password: password, withValueCompletionBlock: { error, result in
if error != nil {
print("Error: \(error)")
if let errorCode = FAuthenticationError(rawValue: error.code) {
switch (errorCode) {
case .EmailTaken:
self.signupErrorAlert("Email In Use", message: "An account has already been created for this email address.")
default:
self.signupErrorAlert("Oops!", message: "Having some trouble creating your account. Please try again or check your internet connection.")
}
}
} else {
// Create and Login the New User with authUser
DataService.dataService.BASE_REF.authUser(email, password: password, withCompletionBlock: {
err, authData in
let user = ["provider": authData.provider!, "email": email!, "username": username!]
let userData = [username!: authData.uid!]
// Seal the deal in DataService.swift.
DataService.dataService.createNewAccount(authData.uid, user: user)
DataService.dataService.addUsernameToUsernamePath(userData)
})