Advertisement
Guest User

SessionManager

a guest
Dec 2nd, 2017
251
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Swift 14.80 KB | None | 0 0
  1. import Foundation
  2. import Firebase
  3. import FirebaseRemoteConfig
  4. import FirebaseAuth
  5. import FirebaseStorage
  6. import ObjectMapper
  7.  
  8. extension Notification.Name {
  9.    
  10.     static let SessionManagerDidUpdateLibrary = Notification.Name(rawValue: "SessionManagerDidUpdateLibrary")
  11.     static let SessionManagerDidUpdateDisabledBrands = Notification.Name(rawValue: "SessionManagerDidUpdateDisabledBrands")
  12.     static let SessionManagerDidUpdateCollectedModels = Notification.Name(rawValue: "SessionManagerDidUpdateCollectedModels")
  13. }
  14.  
  15. enum APIResponse<T: BaseMappable> {
  16.     case error(String)
  17.     case data(T)
  18.    
  19.     func logResponse() {
  20.        
  21.         switch self {
  22.            
  23.         case .error(let message):
  24.             log.error(message)
  25.            
  26.         case .data(let response):
  27.             log.info("\(T.self): \(response.toJSON())")
  28.         }
  29.     }
  30. }
  31.  
  32. class SessionManager {
  33.    
  34.     static let shared: SessionManager = SessionManager()
  35.    
  36.     let auth: Auth = Auth.auth()
  37.    
  38.     fileprivate var libraryObserver: DatabaseHandle? {
  39.         didSet {
  40.             if let id = libraryObserver
  41.             {
  42.                 Database.database().reference().removeObserver(withHandle: id)
  43.             }
  44.         }
  45.     }
  46.    
  47.     fileprivate var collectedModelsObserver: DatabaseHandle? {
  48.         didSet {
  49.             if let id = collectedModelsObserver
  50.             {
  51.                 Database.database().reference().removeObserver(withHandle: id)
  52.             }
  53.         }
  54.     }
  55.    
  56.     fileprivate var disabledBrandsObserver: DatabaseHandle? {
  57.         didSet {
  58.             if let id = disabledBrandsObserver
  59.             {
  60.                 Database.database().reference().removeObserver(withHandle: id)
  61.             }
  62.         }
  63.     }
  64.  
  65.     /// The firebase token for this instance
  66.     var firebaseToken: String? {
  67.         didSet {
  68.            
  69.             guard isUserAccountAttached else {
  70.                 return
  71.             }
  72.            
  73.             guard let userId = auth.currentUser?.uid else {
  74.                 return
  75.             }
  76.            
  77.             guard let validNewToken = firebaseToken else {
  78.                 return
  79.             }
  80.            
  81.             if let validOldToken = oldValue, validOldToken != validNewToken
  82.             {
  83.                 log.info("Removing old notification token: notificationTokens/\(userId)/\(validOldToken)")
  84.                 Database.database().reference(withPath: "notificationTokens/\(userId)/\(validOldToken)").removeValue()
  85.             }
  86.            
  87.             log.info("Adding notification token: notificationTokens/\(userId)/\(validNewToken)")
  88.             Database.database().reference(withPath: "notificationTokens/\(userId)/\(validNewToken)").setValue(true)
  89.         }
  90.     }
  91.    
  92.     /// Whether or not this device has a user account registered to it.
  93.     var isUserAccountAttached: Bool {
  94.         get {
  95.             return auth.currentUser != nil
  96.         }
  97.     }
  98.    
  99.     /// The current model libary contents
  100.     fileprivate(set) var libraryContents: Library? {
  101.         didSet {
  102.             NotificationCenter.default.post(name: .SessionManagerDidUpdateLibrary, object: nil)
  103.         }
  104.     }
  105.    
  106.     /// The model IDs this user has collected
  107.     fileprivate(set) var collectedModelIDs: [String] = [String]() {
  108.         didSet {
  109.             NotificationCenter.default.post(name: .SessionManagerDidUpdateCollectedModels, object: nil)
  110.         }
  111.     }
  112.    
  113.     // The model brands that are disabled by this user
  114.     fileprivate(set) var disabledBrands: [String] = [String]() {
  115.         didSet {
  116.             NotificationCenter.default.post(name: .SessionManagerDidUpdateDisabledBrands, object: nil)
  117.         }
  118.     }
  119.    
  120.     fileprivate init() {
  121.        
  122.         NotificationCenter.default.addObserver(self, selector: #selector(applicationWillEnterForeground), name: .UIApplicationWillEnterForeground, object: nil)
  123.        
  124.         if let user = auth.currentUser
  125.         {
  126.             self.setupCurrentUserObject(user: user)
  127.         }
  128.        
  129.         setupLibrary()
  130.     }
  131.    
  132.     deinit {
  133.         NotificationCenter.default.removeObserver(self)
  134.     }
  135.    
  136.     @objc fileprivate func applicationWillEnterForeground()
  137.     {
  138.         if let validNewToken = firebaseToken
  139.         {
  140.             firebaseToken = validNewToken
  141.         }
  142.     }
  143.    
  144.     fileprivate func setupLibrary() {
  145.        
  146.         libraryObserver = Database.database().reference(withPath: "library").observe(.value) { (snapshot) in
  147.            
  148.             guard let jsonData = snapshot.value as? [String : Any], let newLibrary = Mapper<Library>().map(JSON: jsonData) else {
  149.                 return
  150.             }
  151.            
  152.             self.libraryContents = newLibrary
  153.         }
  154.     }
  155.    
  156.     fileprivate func setupCurrentUserObject(user: User)
  157.     {
  158.         if let validNewToken = firebaseToken
  159.         {
  160.             firebaseToken = validNewToken
  161.         }
  162.        
  163.         collectedModelsObserver = Database.database().reference(withPath: "collectedModels/\(user.uid)").observe(.value, with: { (snapshot) in
  164.            
  165.             guard let jsonData = snapshot.value as? [String : Any] else {
  166.                 return
  167.             }
  168.            
  169.             self.collectedModelIDs = Array(jsonData.keys)
  170.         })
  171.        
  172.         disabledBrandsObserver = Database.database().reference(withPath: "disabledBrands/\(user.uid)").observe(.value, with: { (snapshot) in
  173.            
  174.             guard let jsonData = snapshot.value as? [String : Any] else {
  175.                 return
  176.             }
  177.            
  178.             self.disabledBrands = Array(jsonData.keys)
  179.         })
  180.        
  181.         setupLibrary()
  182.     }
  183.    
  184.     func logout()
  185.     {
  186.         collectedModelsObserver = nil
  187.         disabledBrandsObserver = nil
  188.        
  189.         disabledBrands = [String]()
  190.         collectedModelIDs = [String]()
  191.        
  192.         _ = try? auth.signOut()
  193.     }
  194. }
  195.  
  196. extension SessionManager {
  197.    
  198.     fileprivate func firAuthErrorToString(error: Error) -> String
  199.     {
  200.         switch AuthErrorCode(rawValue: (error as NSError).code)! {
  201.            
  202.         case .operationNotAllowed:
  203.             return NSLocalizedString("Logins through this provider are currently disabled.", comment: "Logins through this provider are currently disabled.")
  204.            
  205.         case .userDisabled:
  206.             return NSLocalizedString("This account has been disabled. Please contact support.", comment: "This account has been disabled. Please contact support.")
  207.            
  208.         case .wrongPassword:
  209.             return NSLocalizedString("That's not the right email address or password.", comment: "That's not the right email address or password.")
  210.            
  211.         case .invalidEmail:
  212.             return NSLocalizedString("That email address doesn't look correct.", comment: "That email address doesn't look correct.")
  213.            
  214.         case .userNotFound:
  215.             return NSLocalizedString("That's not the right email address or password.", comment: "That's not the right email address or password.")
  216.            
  217.         case .emailAlreadyInUse:
  218.             return NSLocalizedString("This email address is already in use by another user.", comment: "This email address is already in use by another user.")
  219.            
  220.         case .weakPassword:
  221.             return (error as NSError).localizedFailureReason ?? NSLocalizedString("Your password is too weak. Try a stronger password.", comment: "Your password is too weak. Try a stronger password.")
  222.            
  223.         case .credentialAlreadyInUse:
  224.             return NSLocalizedString("This account is already linked to another user.", comment: "This account is already linked to another user.")
  225.            
  226.         default:
  227.             return error.localizedDescription
  228.         }
  229.     }
  230.    
  231.     /// Login a user, given an email address / password
  232.     func loginUser(email: String, password: String, completion: ((_ response: APIResponse<NullResponse>) -> ())?)
  233.     {
  234.         let oldUser = auth.currentUser
  235.        
  236.         auth.signIn(withEmail: email, password: password) { (user, error) in
  237.            
  238.             guard error == nil else {
  239.                
  240.                 completion?(APIResponse.error(self.firAuthErrorToString(error: error!)))
  241.                 return
  242.             }
  243.            
  244.             if !user!.isEmailVerified
  245.             {
  246.                 user?.sendEmailVerification(completion: nil)
  247.             }
  248.            
  249.             if oldUser?.isAnonymous == true
  250.             {
  251.                 oldUser?.delete(completion: nil)
  252.             }
  253.            
  254.             // No error, assume we received a user object.
  255.             self.setupCurrentUserObject(user: user!)
  256.            
  257.             completion?(APIResponse.data(NullResponse()))
  258.         }
  259.     }
  260.    
  261.     func loginAnonymousUser(completion: ((_ response: APIResponse<NullResponse>) -> ())?)
  262.     {
  263.         let oldUser = auth.currentUser
  264.         auth.signInAnonymously { (user, error) in
  265.        
  266.             guard error == nil else {
  267.                
  268.                 completion?(APIResponse.error(self.firAuthErrorToString(error: error!)))
  269.                 return
  270.             }
  271.            
  272.             if !user!.isEmailVerified
  273.             {
  274.                 user?.sendEmailVerification(completion: nil)
  275.             }
  276.            
  277.             if oldUser?.isAnonymous == true
  278.             {
  279.                 oldUser?.delete(completion: nil)
  280.             }
  281.            
  282.             // No error, assume we received a user object.
  283.             self.setupCurrentUserObject(user: user!)
  284.            
  285.             completion?(APIResponse.data(NullResponse()))
  286.         }
  287.     }
  288.    
  289.     /// Register a user from an email signup model
  290.     func registerUser(email: String, password: String, completion: ((_ response: APIResponse<NullResponse>) -> ())?)
  291.     {
  292.         let oldUser = auth.currentUser
  293.        
  294.         auth.createUser(withEmail: email, password: password) { (user, error) in
  295.            
  296.             guard error == nil else {
  297.                
  298.                 completion?(APIResponse.error(self.firAuthErrorToString(error: error!)))
  299.                 return
  300.             }
  301.            
  302.             user?.sendEmailVerification(completion: nil)
  303.            
  304.             if oldUser?.isAnonymous == true
  305.             {
  306.                 oldUser?.delete(completion: nil)
  307.             }
  308.            
  309.             // No error, assume we received a user object.
  310.             self.setupCurrentUserObject(user: user!)
  311.            
  312.             completion?(APIResponse.data(NullResponse()))
  313.         }
  314.     }
  315.  
  316.     /// Update the email address for a user
  317.     func updateUserEmailAddress(email: String, password: String, completion: ((_ response: APIResponse<NullResponse>) -> ())?)
  318.     {
  319.         guard let currentEmail = auth.currentUser?.email else {
  320.            
  321.             completion?(APIResponse.error(NSLocalizedString("We had trouble locating the current email address for your account. Please try again later.", comment: "We had trouble locating the current email address for your account. Please try again later.")))
  322.             return
  323.         }
  324.        
  325.         let credential = EmailAuthProvider.credential(withEmail: currentEmail, password: password)
  326.        
  327.         // Re-authenticate
  328.         auth.currentUser?.reauthenticate(with: credential, completion: { (error) in
  329.            
  330.             guard error == nil else {
  331.                
  332.                 completion?(APIResponse.error(self.firAuthErrorToString(error: error!)))
  333.                 return
  334.             }
  335.            
  336.             // Change email
  337.             self.auth.currentUser?.updateEmail(to: email, completion: { (error) in
  338.                
  339.                 guard error == nil else {
  340.                    
  341.                     completion?(APIResponse.error(self.firAuthErrorToString(error: error!)))
  342.                     return
  343.                 }
  344.                
  345.                 completion?(APIResponse.data(NullResponse()))
  346.             })
  347.         })
  348.     }
  349.    
  350.     /// Update the password of a user
  351.     func updateUserPassword(oldPassword: String, password: String, completion: ((_ response: APIResponse<NullResponse>) -> ())?)
  352.     {
  353.         guard let currentEmail = auth.currentUser?.email else {
  354.            
  355.             completion?(APIResponse.error(NSLocalizedString("We had trouble locating the current email address for your account. Please try again later.", comment: "We had trouble locating the current email address for your account. Please try again later.")))
  356.             return
  357.         }
  358.        
  359.         let credential = EmailAuthProvider.credential(withEmail: currentEmail, password: oldPassword)
  360.        
  361.         // Re-authenticate
  362.         auth.currentUser?.reauthenticate(with: credential, completion: { (error) in
  363.            
  364.             guard error == nil else {
  365.                
  366.                 completion?(APIResponse.error(self.firAuthErrorToString(error: error!)))
  367.                 return
  368.             }
  369.            
  370.             // Change email
  371.             self.auth.currentUser?.updatePassword(to: password, completion: { (error) in
  372.                
  373.                 guard error == nil else {
  374.                    
  375.                     completion?(APIResponse.error(self.firAuthErrorToString(error: error!)))
  376.                     return
  377.                 }
  378.                
  379.                 completion?(APIResponse.data(NullResponse()))
  380.             })
  381.         })
  382.     }
  383. }
  384.  
  385. extension SessionManager {
  386.    
  387.     func setModelCollected(model: Model, isCollected: Bool) {
  388.        
  389.         guard let user = auth.currentUser else {
  390.             return
  391.         }
  392.        
  393.         var currentCollection = collectedModelIDs.filter({ $0 != model.uuid })
  394.        
  395.         if isCollected
  396.         {
  397.             currentCollection.append(model.uuid)
  398.         }
  399.        
  400.         var nodeDictionary = [String : Bool]()
  401.        
  402.         for item in currentCollection
  403.         {
  404.             nodeDictionary[item] = true
  405.         }
  406.        
  407.         nodeDictionary["_value"] = true
  408.        
  409.         Database.database().reference(withPath: "collectedModels/\(user.uid)").setValue(nodeDictionary)
  410.     }
  411.  
  412.     func setBrandDisabled(brand: String, isDisabled: Bool) {
  413.        
  414.         guard let user = auth.currentUser else {
  415.             return
  416.         }
  417.        
  418.         var currentCollection = disabledBrands.filter({ $0 != brand })
  419.        
  420.         if isDisabled
  421.         {
  422.             currentCollection.append(brand)
  423.         }
  424.        
  425.         var nodeDictionary = [String : Bool]()
  426.        
  427.         for item in currentCollection
  428.         {
  429.             nodeDictionary[item] = true
  430.         }
  431.        
  432.         nodeDictionary["_value"] = true
  433.        
  434.         Database.database().reference(withPath: "disabledBrands/\(user.uid)").setValue(nodeDictionary)
  435.     }
  436. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement