Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import Foundation
- import Firebase
- import FirebaseRemoteConfig
- import FirebaseAuth
- import FirebaseStorage
- import ObjectMapper
- extension Notification.Name {
- static let SessionManagerDidUpdateLibrary = Notification.Name(rawValue: "SessionManagerDidUpdateLibrary")
- static let SessionManagerDidUpdateDisabledBrands = Notification.Name(rawValue: "SessionManagerDidUpdateDisabledBrands")
- static let SessionManagerDidUpdateCollectedModels = Notification.Name(rawValue: "SessionManagerDidUpdateCollectedModels")
- }
- enum APIResponse<T: BaseMappable> {
- case error(String)
- case data(T)
- func logResponse() {
- switch self {
- case .error(let message):
- log.error(message)
- case .data(let response):
- log.info("\(T.self): \(response.toJSON())")
- }
- }
- }
- class SessionManager {
- static let shared: SessionManager = SessionManager()
- let auth: Auth = Auth.auth()
- fileprivate var libraryObserver: DatabaseHandle? {
- didSet {
- if let id = libraryObserver
- {
- Database.database().reference().removeObserver(withHandle: id)
- }
- }
- }
- fileprivate var collectedModelsObserver: DatabaseHandle? {
- didSet {
- if let id = collectedModelsObserver
- {
- Database.database().reference().removeObserver(withHandle: id)
- }
- }
- }
- fileprivate var disabledBrandsObserver: DatabaseHandle? {
- didSet {
- if let id = disabledBrandsObserver
- {
- Database.database().reference().removeObserver(withHandle: id)
- }
- }
- }
- /// The firebase token for this instance
- var firebaseToken: String? {
- didSet {
- guard isUserAccountAttached else {
- return
- }
- guard let userId = auth.currentUser?.uid else {
- return
- }
- guard let validNewToken = firebaseToken else {
- return
- }
- if let validOldToken = oldValue, validOldToken != validNewToken
- {
- log.info("Removing old notification token: notificationTokens/\(userId)/\(validOldToken)")
- Database.database().reference(withPath: "notificationTokens/\(userId)/\(validOldToken)").removeValue()
- }
- log.info("Adding notification token: notificationTokens/\(userId)/\(validNewToken)")
- Database.database().reference(withPath: "notificationTokens/\(userId)/\(validNewToken)").setValue(true)
- }
- }
- /// Whether or not this device has a user account registered to it.
- var isUserAccountAttached: Bool {
- get {
- return auth.currentUser != nil
- }
- }
- /// The current model libary contents
- fileprivate(set) var libraryContents: Library? {
- didSet {
- NotificationCenter.default.post(name: .SessionManagerDidUpdateLibrary, object: nil)
- }
- }
- /// The model IDs this user has collected
- fileprivate(set) var collectedModelIDs: [String] = [String]() {
- didSet {
- NotificationCenter.default.post(name: .SessionManagerDidUpdateCollectedModels, object: nil)
- }
- }
- // The model brands that are disabled by this user
- fileprivate(set) var disabledBrands: [String] = [String]() {
- didSet {
- NotificationCenter.default.post(name: .SessionManagerDidUpdateDisabledBrands, object: nil)
- }
- }
- fileprivate init() {
- NotificationCenter.default.addObserver(self, selector: #selector(applicationWillEnterForeground), name: .UIApplicationWillEnterForeground, object: nil)
- if let user = auth.currentUser
- {
- self.setupCurrentUserObject(user: user)
- }
- setupLibrary()
- }
- deinit {
- NotificationCenter.default.removeObserver(self)
- }
- @objc fileprivate func applicationWillEnterForeground()
- {
- if let validNewToken = firebaseToken
- {
- firebaseToken = validNewToken
- }
- }
- fileprivate func setupLibrary() {
- libraryObserver = Database.database().reference(withPath: "library").observe(.value) { (snapshot) in
- guard let jsonData = snapshot.value as? [String : Any], let newLibrary = Mapper<Library>().map(JSON: jsonData) else {
- return
- }
- self.libraryContents = newLibrary
- }
- }
- fileprivate func setupCurrentUserObject(user: User)
- {
- if let validNewToken = firebaseToken
- {
- firebaseToken = validNewToken
- }
- collectedModelsObserver = Database.database().reference(withPath: "collectedModels/\(user.uid)").observe(.value, with: { (snapshot) in
- guard let jsonData = snapshot.value as? [String : Any] else {
- return
- }
- self.collectedModelIDs = Array(jsonData.keys)
- })
- disabledBrandsObserver = Database.database().reference(withPath: "disabledBrands/\(user.uid)").observe(.value, with: { (snapshot) in
- guard let jsonData = snapshot.value as? [String : Any] else {
- return
- }
- self.disabledBrands = Array(jsonData.keys)
- })
- setupLibrary()
- }
- func logout()
- {
- collectedModelsObserver = nil
- disabledBrandsObserver = nil
- disabledBrands = [String]()
- collectedModelIDs = [String]()
- _ = try? auth.signOut()
- }
- }
- extension SessionManager {
- fileprivate func firAuthErrorToString(error: Error) -> String
- {
- switch AuthErrorCode(rawValue: (error as NSError).code)! {
- case .operationNotAllowed:
- return NSLocalizedString("Logins through this provider are currently disabled.", comment: "Logins through this provider are currently disabled.")
- case .userDisabled:
- return NSLocalizedString("This account has been disabled. Please contact support.", comment: "This account has been disabled. Please contact support.")
- case .wrongPassword:
- return NSLocalizedString("That's not the right email address or password.", comment: "That's not the right email address or password.")
- case .invalidEmail:
- return NSLocalizedString("That email address doesn't look correct.", comment: "That email address doesn't look correct.")
- case .userNotFound:
- return NSLocalizedString("That's not the right email address or password.", comment: "That's not the right email address or password.")
- case .emailAlreadyInUse:
- return NSLocalizedString("This email address is already in use by another user.", comment: "This email address is already in use by another user.")
- case .weakPassword:
- 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.")
- case .credentialAlreadyInUse:
- return NSLocalizedString("This account is already linked to another user.", comment: "This account is already linked to another user.")
- default:
- return error.localizedDescription
- }
- }
- /// Login a user, given an email address / password
- func loginUser(email: String, password: String, completion: ((_ response: APIResponse<NullResponse>) -> ())?)
- {
- let oldUser = auth.currentUser
- auth.signIn(withEmail: email, password: password) { (user, error) in
- guard error == nil else {
- completion?(APIResponse.error(self.firAuthErrorToString(error: error!)))
- return
- }
- if !user!.isEmailVerified
- {
- user?.sendEmailVerification(completion: nil)
- }
- if oldUser?.isAnonymous == true
- {
- oldUser?.delete(completion: nil)
- }
- // No error, assume we received a user object.
- self.setupCurrentUserObject(user: user!)
- completion?(APIResponse.data(NullResponse()))
- }
- }
- func loginAnonymousUser(completion: ((_ response: APIResponse<NullResponse>) -> ())?)
- {
- let oldUser = auth.currentUser
- auth.signInAnonymously { (user, error) in
- guard error == nil else {
- completion?(APIResponse.error(self.firAuthErrorToString(error: error!)))
- return
- }
- if !user!.isEmailVerified
- {
- user?.sendEmailVerification(completion: nil)
- }
- if oldUser?.isAnonymous == true
- {
- oldUser?.delete(completion: nil)
- }
- // No error, assume we received a user object.
- self.setupCurrentUserObject(user: user!)
- completion?(APIResponse.data(NullResponse()))
- }
- }
- /// Register a user from an email signup model
- func registerUser(email: String, password: String, completion: ((_ response: APIResponse<NullResponse>) -> ())?)
- {
- let oldUser = auth.currentUser
- auth.createUser(withEmail: email, password: password) { (user, error) in
- guard error == nil else {
- completion?(APIResponse.error(self.firAuthErrorToString(error: error!)))
- return
- }
- user?.sendEmailVerification(completion: nil)
- if oldUser?.isAnonymous == true
- {
- oldUser?.delete(completion: nil)
- }
- // No error, assume we received a user object.
- self.setupCurrentUserObject(user: user!)
- completion?(APIResponse.data(NullResponse()))
- }
- }
- /// Update the email address for a user
- func updateUserEmailAddress(email: String, password: String, completion: ((_ response: APIResponse<NullResponse>) -> ())?)
- {
- guard let currentEmail = auth.currentUser?.email else {
- 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.")))
- return
- }
- let credential = EmailAuthProvider.credential(withEmail: currentEmail, password: password)
- // Re-authenticate
- auth.currentUser?.reauthenticate(with: credential, completion: { (error) in
- guard error == nil else {
- completion?(APIResponse.error(self.firAuthErrorToString(error: error!)))
- return
- }
- // Change email
- self.auth.currentUser?.updateEmail(to: email, completion: { (error) in
- guard error == nil else {
- completion?(APIResponse.error(self.firAuthErrorToString(error: error!)))
- return
- }
- completion?(APIResponse.data(NullResponse()))
- })
- })
- }
- /// Update the password of a user
- func updateUserPassword(oldPassword: String, password: String, completion: ((_ response: APIResponse<NullResponse>) -> ())?)
- {
- guard let currentEmail = auth.currentUser?.email else {
- 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.")))
- return
- }
- let credential = EmailAuthProvider.credential(withEmail: currentEmail, password: oldPassword)
- // Re-authenticate
- auth.currentUser?.reauthenticate(with: credential, completion: { (error) in
- guard error == nil else {
- completion?(APIResponse.error(self.firAuthErrorToString(error: error!)))
- return
- }
- // Change email
- self.auth.currentUser?.updatePassword(to: password, completion: { (error) in
- guard error == nil else {
- completion?(APIResponse.error(self.firAuthErrorToString(error: error!)))
- return
- }
- completion?(APIResponse.data(NullResponse()))
- })
- })
- }
- }
- extension SessionManager {
- func setModelCollected(model: Model, isCollected: Bool) {
- guard let user = auth.currentUser else {
- return
- }
- var currentCollection = collectedModelIDs.filter({ $0 != model.uuid })
- if isCollected
- {
- currentCollection.append(model.uuid)
- }
- var nodeDictionary = [String : Bool]()
- for item in currentCollection
- {
- nodeDictionary[item] = true
- }
- nodeDictionary["_value"] = true
- Database.database().reference(withPath: "collectedModels/\(user.uid)").setValue(nodeDictionary)
- }
- func setBrandDisabled(brand: String, isDisabled: Bool) {
- guard let user = auth.currentUser else {
- return
- }
- var currentCollection = disabledBrands.filter({ $0 != brand })
- if isDisabled
- {
- currentCollection.append(brand)
- }
- var nodeDictionary = [String : Bool]()
- for item in currentCollection
- {
- nodeDictionary[item] = true
- }
- nodeDictionary["_value"] = true
- Database.database().reference(withPath: "disabledBrands/\(user.uid)").setValue(nodeDictionary)
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement