Skip to content

Instantly share code, notes, and snippets.

@MarksCode
Created May 8, 2017 20:46
Show Gist options
  • Save MarksCode/988483ba9f373e913d060837259572d1 to your computer and use it in GitHub Desktop.
Save MarksCode/988483ba9f373e913d060837259572d1 to your computer and use it in GitHub Desktop.
//
// SignInVC.swift
// Dog_Log
//
// Created by Ron Marks on 1/6/17.
// Copyright © 2017 Ron Marks. All rights reserved.
//
import UIKit
import Firebase
import GoogleSignIn
import CoreData
import FBSDKLoginKit
class LoginVC: UIViewController, GIDSignInUIDelegate, GIDSignInDelegate {
var managedObjectContext: NSManagedObjectContext!
@IBOutlet weak var googleButton: UIButton!
@IBOutlet weak var fbButton: UIButton!
var ref: FIRDatabaseReference!
override func viewDidLoad() {
super.viewDidLoad()
GIDSignIn.sharedInstance().uiDelegate = self
GIDSignIn.sharedInstance().delegate = self
ref = FIRDatabase.database().reference()
FBSDKLoginManager().logOut() // clear current token
}
// google sign in
@IBAction func googleTouch(_ sender: UIButton) {
disableGoogleButton()
GIDSignIn.sharedInstance().signIn()
}
// fb sign in
@IBAction func fbTouch(_ sender: Any) {
disableFacebookButton()
let login = FBSDKLoginManager()
login.logIn(withReadPermissions: ["public_profile", "email"], from: self, handler: { (result, error) in
if error == nil {
if !(result?.isCancelled)! {
self.getFBUserData()
} else {
self.enableFacebookButton()
}
} else {
print(error?.localizedDescription)
self.enableFacebookButton()
}
})
}
// attempt to sign in user with fb
// cases:
// 1) user's facebook does have email. This is common case
// - in this case, sign them into Firebase
// - could be that they previously didn't have email but now they do, so update Firebase user's email
// - could be that a firebase account with their email already exists, throw error
// - otherwise everything went fine, segue to home page
// 2) user's facebook account could have no email associated (or disabled email permissions). This is a rare case
// - in this case, take user to manual email input page
// - or user could've already done above step, in which case just log them in normally
func getFBUserData(){
if((FBSDKAccessToken.current()) != nil){
FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "name, email"]).start(completionHandler: { (connection, result, error) -> Void in
if error == nil, let res = result as? [String: String]{
let credential = FIRFacebookAuthProvider.credential(withAccessToken: FBSDKAccessToken.current().tokenString)
if res["email"] != nil { // facebook account has email
// CASE 1
print("user has email")
FIRAuth.auth()?.signIn(with: credential, completion: { (user, error) in // sign user into Firebase
if error == nil && user != nil {
if user!.email == nil { // Firebase user has no email
user!.updateEmail(res["email"]!, completion: { error in // user has no email, set email
if error != nil {
if let errCode = FIRAuthErrorCode(rawValue: error!._code) {
switch errCode {
case .errorCodeEmailAlreadyInUse: // email is already in use by another account
self.showEmailTakenAlert()
default:
self.showRegistrationErrorAlert()
}
}
self.enableFacebookButton()
} else { // user previously had no email but now does
print("email set")
self.setUserInfoAndSegue()
}
})
} else { // user has email, everything went fine
print("signed into Firebase with facebook successfully")
self.setUserInfoAndSegue()
}
} else { // some error happened
if let errCode = FIRAuthErrorCode(rawValue: error!._code) {
switch errCode {
case .errorCodeEmailAlreadyInUse: // email is already in use by another account
self.showEmailTakenAlert()
default:
self.showRegistrationErrorAlert()
}
self.enableFacebookButton()
}
}
})
} else { // no email associated with facebook account
// CASE 2
print("user has no email")
FIRAuth.auth()?.signIn(with: credential, completion: { (user, error) in
if let user = user {
if user.email != nil { // user has already typed in email manually
self.setUserInfoAndSegue()
} else { // make user type in email manually
print("user has no email")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "EmailTyper") as? EmailTyperVC
controller?.managedObjectContext = self.managedObjectContext
self.present(controller!, animated: true, completion: nil)
}
} else {
self.enableFacebookButton()
}
})
}
} else {
self.enableFacebookButton()
}
})
} else {
self.enableFacebookButton()
}
}
/// Handle Google Sign in
///
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
if error != nil {
self.showRegistrationErrorAlert()
self.enableGoogleButton()
return
}
guard let idToken = user.authentication.idToken else {
self.enableGoogleButton()
return
}
guard let accessToken = user.authentication.accessToken else { return }
let credentials = FIRGoogleAuthProvider.credential(withIDToken: idToken, accessToken: accessToken)
// check if account with email already exists
FIRAuth.auth()?.fetchProviders(forEmail: user.profile.email, completion: { result, error in
if let error = error {
self.showRegistrationErrorAlert()
return
}
if let result = result {
if result.count > 0 {
if result[0] == "facebook.com" { // facebook account already exists with email
self.showEmailTakenAlert()
self.enableGoogleButton()
return
}
}
}
FIRAuth.auth()?.signIn(with: credentials, completion: { (user, error) in
if error != nil {
self.showRegistrationErrorAlert()
self.enableGoogleButton()
return
}
print("Successfully logged into firebase with google")
self.setUserInfoAndSegue()
})
})
}
/// See if user is already in database, if not then set data. Then segue to home screen
///
func setUserInfoAndSegue(){
if let user = FIRAuth.auth()?.currentUser {
UserDefaults.standard.setValue(user.uid, forKey: "CurrentUser")
if let email = user.email, let name = user.displayName {
// See if user is already in database
let userRef = FIRDatabase.database().reference().child("users").child(user.uid)
userRef.observeSingleEvent(of: .value, with: { snapshot in
// User not in db yet, add data then segue to home view
if !snapshot.exists() {
let nameRef = FIRDatabase.database().reference().child("allUsers").child(email.cleanString())
nameRef.setValue(["name": name.lowercased(), "uid": user.uid])
userRef.setValue(["name": name, "pets": false, "invites": false, "email": email]) { (error, ref) -> Void in
if (error != nil){
print(error!)
} else {
self.dismiss(animated: true, completion: nil)
}
}
} else { // User is already in db, segue to home view
self.dismiss(animated: true, completion: nil)
}
})
}
}
}
// account with email already exists alert
func showEmailTakenAlert(){
let alert = UIAlertController(title: "Registration Error", message: "Your email is already registered with another account", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
// some errror occurred alert
func showRegistrationErrorAlert(){
let alert = UIAlertController(title: "Registration Error", message: "Something went wrong, please try again later", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
// for when user presses facebook button
func disableFacebookButton(){
self.fbButton.isEnabled = false
self.googleButton.isUserInteractionEnabled = false
}
func enableFacebookButton(){
self.fbButton.isEnabled = true
self.googleButton.isUserInteractionEnabled = true
}
// for when user pressed google button
func disableGoogleButton(){
self.googleButton.isEnabled = false
self.fbButton.isUserInteractionEnabled = false
}
func enableGoogleButton(){
self.googleButton.isEnabled = true
self.fbButton.isUserInteractionEnabled = true
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment