Creating users in new Firebase and Swift - swift

I'm trying to make a register view, where the users can register through email, password, username, phone number and city.
Here's the code for creating the users through email and password:
#IBAction func Register(sender: AnyObject) {
guard let email = EmailTextField.text?.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()) where !email.isEmpty else {
print("Email is empty")
return
}
guard let password = PasswordTextField.text where !password.isEmpty
else {
print("Password is empty")
return
}
guard let repeatPassword = RePasswordTextField.text where !repeatPassword.isEmpty
else {
print("Repeat Password is empty")
return
}
guard password == repeatPassword else {
print("Password does not match")
return
}
FIRAuth.auth()?.createUserWithEmail(EmailTextField.text!, password: PasswordTextField.text!, completion: { user, error in
if let error = error {
print(error)
} else {
if let user = user {
print(user)
}
}
})
}
the question is how can I add the other values like username to firebase dashboard?
in the previous version of firebase I was creating a dictionary then use the setValue function!
But in the new firebase how can I do that?

For storing data in user's respective uid
let ref = FIRDatabase.database().reference() //Global Variable
...
...
#IBAction func Register(sender: AnyObject) {
guard let email = EmailTextField.text?.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()) where !email.isEmpty else {
print("Email is empty")
return
}
guard let password = PasswordTextField.text where !password.isEmpty
else {
print("Password is empty")
return
}
guard let repeatPassword = RePasswordTextField.text where !repeatPassword.isEmpty
else {
print("Repeat Password is empty")
return
}
guard password == repeatPassword else {
print("Password does not match")
return
}
FIRAuth.auth()?.createUserWithEmail(EmailTextField.text!, password: PasswordTextField.text!, completion: { user, error in
if let error = error {
print(error)
} else {
ref.child("UserProfile").child(user!.uid).setValue([
"username" : usernameTextField.text!, //Or whatever way you are extracting these information
"phoneNumber" : phoneNumberTextField.text!, //Or whatever way you are extracting these information
"city" : cityTextField.text! //Or whatever way you are extracting these information
])
}
})
}
Your JSON tree will look something like this :-
{UserProfile : {
user_ID_1 :{
userName : "Tim",
phoneNumber : +1(23)....,
city : "Los Angeles"
}
user_ID_2 :{
userName : "Hnery",
phoneNumber : +1(073)....,
city : "New York"
}
}
}

Related

when i second time signup it clears realtime database from firebase in swift

When I signup second time from my app It allow me sign up but when I chek In data base my old acc was removed, I really need help in this please your help would be greatful for me.
Here is my Appdelegate func
var oldToken = ""
var dToken = ""
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
Database.database().isPersistenceEnabled = true
let preferences = UserDefaults.standard
if preferences.object(forKey: "dtoken") != nil {
oldToken = preferences.object(forKey: "dtoken") as! String
}
if let uuid = UIDevice.current.identifierForVendor?.uuidString {
dToken = uuid
print(uuid)
if oldToken != dToken && oldToken != "" {
preferences.set(dToken, forKey: "dtoken")
preferences.set(oldToken, forKey: "dtoken_old")
preferences.synchronize()
print("ohoh TOKEN CHANGED!!!")
//Change Tokens in DB.
}
}
return true
}
Here is My Signup Viewcontroller
func guidancefromcoach() {
guard let email = txtEmail.text else { return }
guard let pass = txtPassword.text else { return }
Auth.auth().createUser(withEmail: email, password: pass) { result, error in
if error != nil {
self.Alert(title: "Error", message: error!.localizedDescription)
}else {
if self.currentReachabilityStatus == .notReachable {
print("There is no internet connection")
self.retryAlert()
} else {
let preferences = UserDefaults.standard
preferences.set(dToken, forKey: "dtoken")
userIsCoach = false
preferences.set(userIsCoach, forKey: "userIsCoach")
authorizedCoachCode = self.txtEnterCoachId.text!
preferences.set(authorizedCoachCode, forKey: "authorizedCoachCode")
preferences.synchronize()
let userItem = UserStruct(dToken, self.txtFName.text!, self.txtLName.text!, self.txtEmail.text!, self.txtPhone.text!, coachCode, authorizedCoachCode, userIsCoach)
self.ref.child(dToken).setValue(userItem.toAnyObject())
print("dtoken......\(dToken)")
print("saved new user")
self.performSegue(withIdentifier: "fromSignupSegue", sender: Any?.self)
}
}
}
}
Here is my USERSTRUCT
struct UserStruct {
let ref: DatabaseReference?
var token = ""
var fname = ""
var lname = ""
var email = ""
var phone = ""
var coachCode = ""
var authorizedCoachCode = ""
var isCoach = false
init(_ token:String, _ fname:String, _ lname:String, _ email:String, _ phone:String, _ coachCode:String, _ authorizedCoachCode:String, _ isCoach:Bool) {
self.ref = nil
self.token = token
self.fname = fname
self.lname = lname
self.email = email
self.phone = phone
self.coachCode = coachCode
self.authorizedCoachCode = authorizedCoachCode
self.isCoach = isCoach
}
init?(snapshot: DataSnapshot) {
guard
let value = snapshot.value as? [String: AnyObject],
let token = value["token"] as? String,
let fname = value["fname"] as? String,
let lname = value["lname"] as? String,
let email = value["email"] as? String,
let phone = value["phone"] as? String,
let coachCode = value["coachCode"] as? String,
let authorizedCoachCode = value["authorizedCoachCode"] as? String,
let isCoach = value["isCoach"] as? Bool else {
return nil
}
self.ref = snapshot.ref
//self.key = snapshot.key
self.token = token
self.fname = fname
self.lname = lname
self.email = email
self.phone = phone
self.coachCode = coachCode
self.authorizedCoachCode = authorizedCoachCode
self.isCoach = isCoach
}
func toAnyObject() -> Any {
return [
"token": token,
"fname": fname,
"lname": lname,
"email": email,
"phone": phone,
"coachCode": coachCode,
"authorizedCoachCode": authorizedCoachCode,
"isCoach": isCoach
]
}
Your help would be really greatful Thankyou in advance.
It seems that you're calling SetValue(), your old account isn't getting removed, it's getting set to different info. I'm not sure what the problem is but i suggest using this code:
Auth.auth().createUser(withEmail: email, password: pass) { (result, error) in
if err != nil {
//error code here
}
else {
guard let userID = Auth.auth().currentUser?.uid else { return }Firestore.firestore().collection("users").document(userID).setData(["email": email]) { (error) in
if error != nil {
//error happened
}
}
//Success, email has been saved to database
}
}
You can add all your other stuff to this code(userDefaults, etc.)
but this alone should be able to add a new document every time.

Firestore database does not store data

I've created an app in which, when the user signs up, should create two values in the Firestore server in the user's document, that is level and subjects (meaning it's in /users/userid).
I've tried manually creating the 'users' collection, but nothing is being created when the user signs up.
The following is my code (SignUpViewController):
import Firebase
var reference: DocumentReference!
func firebaseAuth() {
let userDisplayName = textfieldDisplayName.text!
let userEmail = textfieldEmail.text!
let userPassword = textfieldPassword.text!
if userEmail == "" || userPassword == "" {
labelMessage.isHidden = false
labelMessage.textColor = UIColor.red
labelMessage.text = "Error: A compulsory field is left blank."
} else {
Auth.auth().createUser(withEmail: userEmail, password: userPassword) { (user, error) in
if user != nil && error == nil {
let changeRequest = Auth.auth().currentUser?.createProfileChangeRequest()
changeRequest?.displayName = userDisplayName
changeRequest?.commitChanges(completion: { (error) in
if error == nil {
let userID = Auth.auth().currentUser?.uid
let dataToSave: [String: Any] = ["level":0, "subjects":[""]]
self.reference = Firestore.firestore().collection("users").document(userID ?? "")
self.reference.setData(dataToSave, completion: { (error) in
if error == nil {
self.performSegue(withIdentifier: "presentInitial", sender: self)
} else {
self.labelMessage.isHidden = false
self.labelMessage.textColor = UIColor.red
self.labelMessage.text = "Error: \(error?.localizedDescription ?? "")"
}
})
self.performSegue(withIdentifier: "presentInitial", sender: self)
} else {
self.labelMessage.isHidden = false
self.labelMessage.textColor = UIColor.red
self.labelMessage.text = "Error: \(error?.localizedDescription ?? "")"
}
})
} else {
self.labelMessage.isHidden = false
self.labelMessage.textColor = UIColor.red
self.labelMessage.text = "Error: \(error?.localizedDescription ?? "")"
}
}
}
}
The following code is from another View Controller which SignUpViewController redirects to (HomeViewController):
import Firebase
var reference: DocumentReference!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let userID = Auth.auth().currentUser?.uid
reference.getDocument { (docSnapshot, error) in // Fatal error occured here
let data = docSnapshot?.data()
let userLevel = data?["level"] as? String ?? ""
if userLevel == "" {
self.performSegue(withIdentifier: "performSetup", sender: self)
}
}
}
I expected that when redirected to the homepage (segued through presentInitial), the homepage will then read the value of 'level'. However, the app crashed with a fatal error: "Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value" where 'level' was meant to be read from the server.
I think the problem is not with Firestore. According to the error message, the code wraps an optional value but failed because it is nil, so the problem is probably about these three lines:
let userDisplayName = textfieldDisplayName.text!
let userEmail = textfieldEmail.text!
let userPassword = textfieldPassword.text!
Sometimes, when a UITextField has no text, its text is nil instead of "", which may cause the problem. You can replace the three lines with the following:
let userDisplayName = textfieldDisplayName.text ?? ""
let userEmail = textfieldEmail.text ?? ""
let userPassword = textfieldPassword.text ?? ""
In this way, these three variables will always be "" when there are no text, and your logic of checking blank fields will still work.
Edit: For future reference, the real problem is not in the question but in the comments of this answer.
Did you check your database rules ?
you need to setup the rules when to work and when not to so no one can access the database but your apps
for a test now use this code to verify it woks then you should change it
{
"rules": {
".read": true,
".write": true
}
}

Updating child in firebase not working as expected

I am trying to save data into firebase, by first generating a child using .childByAutoId() and then update the child with the necessary data. But it doesn't seem to work as expected.
The structure I am trying to achieve is
events
attendees
-L0P1D5arR0OkBf8h
userEmail: "user#user.com"
userName: "User name"
userPhone: "0864567182"
Here's what I have done so far:
guard let fee = events?["eventFee"] else {
return
}
guard let key = events?["eventKey"] else {
return
}
guard let eventTitle = events?["title"] else {
return
}
if fee == "0" {
var values = [String: String]()
self.ref = Database.database().reference()
let attendeekey = ref.child("events").child(key).child("attendees").childByAutoId().key
let userDetails = UserDetails()
for user in userDetails.currentUserDetails {
guard let userEmail = user.email else {
return
}
guard let firstName = user.firstName, let lastName = user.lastName else {
return
}
guard let userPhone = user.phoneNo else {
return
}
let userName = "\(firstName) \(lastName)"
values = ["userEmail": userEmail, "userName": userName, "userPhone": userPhone as! String]
}
ref.updateChildValues(["events/\(key)/attendees/\(attendeekey)": values], withCompletionBlock: {
(err, ref) in
if err != nil {
self.displayAlertMessage(message: err as! String, title: "Oops!")
//print(err ?? "An error occured")
return
}
let message = "You have successfully registered for \(eventTitle)"
self.displayAlertMessage(message: message, title: "Success!")
})
}
Is anything wrong with my approach?

Swift Firebase check if email is already in use

I want to be able to check if an email address is already been used (so if somebody put test1#test.com but another user already registered with that email account).
I have a simple test if it has NOT been used an image view shows a green arrow, if it HAS been used then it is red x
when I create the user I use the following code
FIRAuth.auth()?.createUser(withEmail: email, password: password, completion: { (user, error) in
if error == nil {
self.ref.child("userEmails").child((user?.uid)!).setValue(email)
FIRAuth.auth()!.signIn(withEmail: email,
password: password)
} else {
//registration failure
}
what I am trying to do to check is
func checkIfEmailExists(textField: UITextField) {
let ref = FIRDatabase.database().reference()
let email = firstContainerTextField.text ?? ""
ref.child("userEmails").queryEqual(toValue: email)
.observe(.value, with: { snapshot in
if (self.firstContainerTextField.text?.isEmpty)! {
self.firstContainerImage.image = UIImage.init(named: "emptyBlue.png")
} else if !(self.firstContainerTextField.text?.isEmpty)! && !snapshot.exists() {
self.firstContainerImage.image = UIImage.init(named: "redEx.png")
} else if snapshot.exists() {
self.firstContainerImage.image = UIImage.init(named: "greenCheck.png")
}
});
}
So far it does not work as I can see in my database that test1#test.com exists.
Can somebody tell me what I missed?
EDIT
I have updated my code. I am using hasChildren and I searched for similar questions and they seem to point this direction, but I still cannot get the result I am looking for
func checkIfEmailExists(textField: UITextField) {
let ref = FIRDatabase.database().reference()
let email = firstContainerTextField.text ?? ""
ref.child("userEmails").queryEqual(toValue: email)
.observe(.value, with: { snapshot in
if !snapshot.hasChildren() {
self.firstContainerImage.image = UIImage.init(named: "redEx.png")
} else {
for child in snapshot.children.allObjects as! [FIRDataSnapshot] {
let tmp = child.value as! String
if tmp == email {
self.firstContainerImage.image = UIImage.init(named: "greenCheck.png")
}
}
}
});
}
Edit 2
I changed how I set my user up
self.ref.child("users").child((user?.uid)!).setValue(["Email": email])
so now my database looks like this
users
*****uid*****
Email: "test#test.com
As I commented earlier: you'll need to check whether the query has any results by calling snapshot.hasChildren().
func checkIfEmailExists(textField: UITextField) {
let ref = FIRDatabase.database().reference()
let email = firstContainerTextField.text ?? ""
ref.child("userEmails").queryEqual(toValue: email)
.observe(.value, with: { snapshot in
if (!snapshot.hasChildren()) {
// User doesn't exist yet...
}
});
}
The following is the structure of the Firebase function you might be looking for (Swift 4):
Auth.auth().fetchProviders(forEmail: emailAddress, completion: {
(providers, error) in
if let error = error {
print(error.localizedDescription)
} else if let providers = providers {
print(providers)
}
})
If the email address is already registered to a user, you will get a list of the providers that the email address is used for. Otherwise, the list of providers will be empty, and thus the email address is not registered.

How do you update a users profile settings using firebase and swift?

I am trying to update a users email and full name. This is my code:
func saveTapped() {
var performSegue = false
if updateEmail.text == "" && updateFullName.text == "" {
self.cleanUrCodeRohan("Please fill in one or more of the missing text fields that you would like to update.")
}
if updateEmail.text != "" {
let user = FIRAuth.auth()?.currentUser
user?.updateEmail(updateEmail.text!) { error in
self.ref.child("users").child(self.currentUser).child("email").setValue(self.updateEmail.text!)
}
let emailUpdateRef = FIRDatabase.database().reference().child(currentUser).child("email")
print(emailUpdateRef)
emailUpdateRef.setValue(self.updateEmail.text)
performSegue = true
}
if updateFullName.text != "" {
let user = FIRAuth.auth()?.currentUser
if let user = user {
let changeRequest = user.profileChangeRequest()
changeRequest.displayName = self.updateFullName.text!
}
performSegue = true
}
if performSegue == true {
self.navigationController!.popViewControllerAnimated(true)
}
}
I am able to update the email under authorization but not under the database. Any help would be appreciated.
If JSON tree is something like this:-
appName{
users :{
userID :{
email : "..",
username : ".."
}
}
}
Use this Code to update your node's child value's:-
func saveTapped(){
if ((updateEmail.text != "" || updateFullName.text != "") && (updateEmail.text != nil || updateFullName.text != nil)){
let userRef = FIRDatabase.database().reference().child("users").child(FIRAuth.auth()!.currentUser!.uid)
if let new_Email = updateEmail.text as? String{
FIRAuth.auth()!.currentUser!.updateEmail(updateEmail.text!) { error in
if error == nil{
userRef.updateChildValues(["email" : new_Email ], withCompletionBlock: {(errEM, referenceEM) in
if errEM == nil{
print(referenceEM)
}else{
print(errEM?.localizedDescription)
}
})
}
}else{
self.cleanUrCodeRohan("Email couldn't be updated in auth")
}
}
if let new_Name = updateFullName.text as? String{
userRef.updateChildValues(["username" : new_Name ], withCompletionBlock: {(errNM, referenceNM) in
if errNM == nil{
print(referenceNM)
}else{
print(errNM?.localizedDescription)
}
})
}
}else{
self.cleanUrCodeRohan("Please fill in one or more of the missing text fields that you would like to update.")
}
}