From 94dceb6fece9ab7cd26334e78f93d1e52ae13986 Mon Sep 17 00:00:00 2001 From: Kyle Browning Date: Mon, 15 Aug 2016 15:43:39 -0700 Subject: [PATCH] Adds Auth Button, LoginViewController, and bug fixes. --- src/Shared/Classes/waterwheel.swift | 276 +++++++++++++----- src/iOS/Buttons/waterwheelAuthButton.swift | 75 +++++ .../Views/waterwheelLoginViewController.swift | 266 +++++++++++++++++ waterwheel.podspec | 1 + 4 files changed, 542 insertions(+), 76 deletions(-) create mode 100644 src/iOS/Buttons/waterwheelAuthButton.swift create mode 100644 src/iOS/Views/waterwheelLoginViewController.swift diff --git a/src/Shared/Classes/waterwheel.swift b/src/Shared/Classes/waterwheel.swift index 4097b43..daea628 100644 --- a/src/Shared/Classes/waterwheel.swift +++ b/src/Shared/Classes/waterwheel.swift @@ -7,11 +7,39 @@ import Alamofire import SwiftyJSON +import SwiftyUserDefaults + +extension DefaultsKeys { + static let basicUsername = DefaultsKey("basicUsername") + static let basicPassword = DefaultsKey("basicPassword") + static let logoutToken = DefaultsKey("logoutToken") + static let csrfToken = DefaultsKey("csrfToken") + static let signRequestsBasic = DefaultsKey("signRequestsBasic") + static let signCSRFToken = DefaultsKey("signCSRFToken") + static let isLoggedIn = DefaultsKey("isLoggedIn") +} + public enum EntityType: String { case Node = "node", Comment = "comment" } + +public enum waterwheelNotifications: String { + case waterwheelDidLogin + case waterwheelDidLogout + case waterwheelDidStartRequest + case waterwheelDidFinishRequest +} + +public enum waterwheelNotificationsTypes: String { + case checkLoginStatus + case login + case logout + case getCSRF + case normalRequest +} + // MARK: - Typelias definitions public typealias completion = (success:Bool, response:Response?, json:SwiftyJSON.JSON?, error:NSError!) -> Void @@ -33,7 +61,7 @@ public class waterwheelManager { A shared instance of `waterwheelManager` */ public static let sharedInstance: waterwheelManager = { - return waterwheelManager() + return waterwheelManager(basicUsername: "", basicPassword: "", logoutToken: "", CSRFToken: "", signRequestsBasic: false, signCSRFToken: false, isLoggedIn: false) }() public let requestFormat = "?_format=json" @@ -42,20 +70,68 @@ public class waterwheelManager { "Accept":"application/json", ] public var URL : String = "" - public var basicUsername : String = "" - public var basicPassword : String = "" - public var CSRFToken : String = "" - public var signRequestsBasic : Bool = false - public var signCSRFToken : Bool = false + private var basicUsername : String = "" + private var basicPassword : String = "" + private var logoutToken : String = "" + private var CSRFToken : String = "" + private var signRequestsBasic : Bool = false + private var signCSRFToken : Bool = false private var isLoggedIn: Bool = false -} + /** + Initializes the `waterwheel` instance with the our defaults. + - returns: The new `waterwheel` instance. + */ + public init(basicUsername: String, basicPassword: String, logoutToken: String, CSRFToken: String, signRequestsBasic: Bool, signCSRFToken: Bool, isLoggedIn: Bool) { + + if let basicUsername = Defaults[.basicUsername] { + self.basicUsername = basicUsername + } else { + self.basicUsername = "" + } + if let basicPassword = Defaults[.basicPassword] { + self.basicPassword = basicPassword + } else { + self.basicPassword = "" + } + + if let logoutToken = Defaults[.logoutToken] { + self.logoutToken = logoutToken + } else { + self.logoutToken = "" + } + + if let CSRFToken = Defaults[.csrfToken] { + self.CSRFToken = CSRFToken + } else { + self.CSRFToken = "" + } + + if let signRequestsBasic = Defaults[.signRequestsBasic] { + self.signRequestsBasic = signRequestsBasic + } else { + self.signRequestsBasic = false + } + + if let signCSRFToken = Defaults[.signCSRFToken] { + self.signCSRFToken = signCSRFToken + } else { + self.signRequestsBasic = false + } + + if let isLoggedIn = Defaults[.isLoggedIn] { + self.isLoggedIn = isLoggedIn + } else { + self.isLoggedIn = false + } + } +} /** Sets the URL for all requests to be sent against. - + - parameter drupalURL: The URL for the Drupal Site - + */ public func setDrupalURL(drupalURL: String) { assert(drupalURL != "", waterwheelErrorString + "Missing Drupal URL") @@ -63,27 +139,13 @@ public func setDrupalURL(drupalURL: String) { waterwheel.checkLoginStatus() } -/** - Private function to set Logged in Status -*/ -private func setIsLoggedIn(isLoggedIn: Bool) { - waterwheelManager.sharedInstance.isLoggedIn = isLoggedIn -} - -/** - Public function to check if the user is logged in - - */ -public func isLoggedIn() -> Bool { - return waterwheelManager.sharedInstance.isLoggedIn -} - /** Private function to check Login Status with all cookies that have been set. */ private func checkLoginStatus() { + postNotification(waterwheelNotifications.waterwheelDidStartRequest.rawValue, requestName: waterwheelNotificationsTypes.checkLoginStatus.rawValue, object: nil) let urlString = waterwheelManager.sharedInstance.URL + "/user/login_status" + waterwheelManager.sharedInstance.requestFormat Alamofire.request(.GET, urlString) .validate(statusCode: 200..<300) @@ -91,20 +153,20 @@ private func checkLoginStatus() { if (response.result.error == nil) { let loginStatus = String(data: response.data!, encoding: NSUTF8StringEncoding) if (loginStatus == "1") { - waterwheelManager.sharedInstance.isLoggedIn = true + setIsLoggedIn(true) } else { - waterwheelManager.sharedInstance.isLoggedIn = false + setIsLoggedIn(false) } - } else { - waterwheelManager.sharedInstance.isLoggedIn = false + setIsLoggedIn(false) } + postNotification(waterwheelNotifications.waterwheelDidFinishRequest.rawValue, requestName: waterwheelNotificationsTypes.checkLoginStatus.rawValue, object: response.response) } } -// MARK: - Authentication methodss +// MARK: - Authentication methods /** Allows a username and password to be set for Basic Auth @@ -113,10 +175,13 @@ private func checkLoginStatus() { - parameter password: The password to login with */ -public func setBasicAuthUsernameAndPassword(username:String, password:String) { +public func setBasicAuthUsernameAndPassword(username:String, password:String, sign: Bool) { waterwheelManager.sharedInstance.basicUsername = username waterwheelManager.sharedInstance.basicPassword = password - waterwheelManager.sharedInstance.signRequestsBasic = true + waterwheelManager.sharedInstance.signRequestsBasic = sign + Defaults[.basicUsername] = username + Defaults[.basicPassword] = password + Defaults[.signRequestsBasic] = true setIsLoggedIn(true) } @@ -130,7 +195,7 @@ public func setBasicAuthUsernameAndPassword(username:String, password:String) { */ -public func login(username:String?, password:String?, completionHandler: stringcompletion?) { +public func login(username:String?, password:String?, completionHandler: completion?) { let urlString = waterwheelManager.sharedInstance.URL + "/user/login" + waterwheelManager.sharedInstance.requestFormat assert(username! != "", waterwheelErrorString + "Missing username.") @@ -141,26 +206,21 @@ public func login(username:String?, password:String?, completionHandler: stringc "pass":password! ] - // POST request to login. - Alamofire.request(.POST, urlString, headers: waterwheelManager.sharedInstance.headers, parameters: body, encoding: .JSON) - .validate(statusCode: 200..<300) - .responseString { response in - if (response.result.error == nil) { - waterwheel.setIsLoggedIn(true) - //We have to get our CSRF token in order to ensure we can make POST, PUT, and DELETE requests. - getCSRFToken({ (success, response, json, error) in - if (success) { - completionHandler?(success: true, response: response, json: nil, error: nil) - } else { - //Failed to get CSRF token for some reason - completionHandler?(success: false, response: response, json: nil, error: nil) - } - }) - } - else { - waterwheel.setIsLoggedIn(false) - completionHandler?(success: false, response: response, json: nil, error: response.result.error) - } + postNotification(waterwheelNotifications.waterwheelDidStartRequest.rawValue, requestName: waterwheelNotificationsTypes.login.rawValue, object: nil) + + sendRequest("user/login", method: .POST, params: body) { (success, response, json, error) in + switch response!.result { + case .Success(let _): + let csrfToken = json!["csrf_token"].string + let logoutToken = json!["logout_token"].string + setCSRF(csrfToken!, sign: true) + setLogoutToken(logoutToken!) + waterwheel.setIsLoggedIn(true) + completionHandler?(success: true, response: response, json: json, error: nil) + case .Failure(let error): + completionHandler?(success: false, response: response, json: nil, error: error) + } + postNotification(waterwheelNotifications.waterwheelDidFinishRequest.rawValue, requestName: waterwheelNotificationsTypes.login.rawValue, object: response?.response) } } @@ -173,34 +233,33 @@ public func login(username:String?, password:String?, completionHandler: stringc */ -public func logout(completionHandler completionHandler: stringcompletion?) { +public func logout(completionHandler completionHandler: completion?) { if waterwheelManager.sharedInstance.signRequestsBasic { waterwheelManager.sharedInstance.basicUsername = "" waterwheelManager.sharedInstance.basicPassword = "" waterwheelManager.sharedInstance.signRequestsBasic = false return } - let urlString = waterwheelManager.sharedInstance.URL + "/user/logout" - Alamofire.request(.GET, urlString) - .validate(statusCode: 200..<300) - .responseString { response in - if (response.result.error == nil) { - waterwheelManager.sharedInstance.CSRFToken = "" - waterwheelManager.sharedInstance.signCSRFToken = false - waterwheelManager.sharedInstance.isLoggedIn = false - completionHandler?(success: true, response: response, json: nil, error: response.result.error) - } - else { - completionHandler?(success: false, response: response, json: nil, error: response.result.error) - } + postNotification(waterwheelNotifications.waterwheelDidFinishRequest.rawValue, requestName: waterwheelNotificationsTypes.login.rawValue, object: nil) + + let urlString = waterwheelManager.sharedInstance.URL + "/user/logout" + waterwheelManager.sharedInstance.requestFormat + "&token=" + waterwheelManager.sharedInstance.logoutToken + sendRequestWithUrl(urlString, method: .POST, params: nil) { (success, response, json, error) in + if (response!.result.error == nil) { + setCSRF("", sign: false) + setIsLoggedIn(false) + completionHandler?(success: true, response: response, json: nil, error: response!.result.error) + } + else { + completionHandler?(success: false, response: response, json: nil, error: response!.result.error) + } + postNotification(waterwheelNotifications.waterwheelDidFinishRequest.rawValue, requestName: waterwheelNotificationsTypes.login.rawValue, object: response?.response) } - } /** - + Private function to get the CSRF Token - + */ private func getCSRFToken(completionHandler: stringcompletion?) { let urlString = waterwheelManager.sharedInstance.URL + "/rest/session/token" @@ -209,8 +268,7 @@ private func getCSRFToken(completionHandler: stringcompletion?) { .responseString{ response in if (response.result.error == nil) { let csrfToken = String(data: response.data!, encoding: NSUTF8StringEncoding) - waterwheelManager.sharedInstance.CSRFToken = csrfToken! - waterwheelManager.sharedInstance.signCSRFToken = true + setCSRF(csrfToken!, sign: true) completionHandler?(success: true, response: response, json: nil, error: nil) } else { @@ -223,7 +281,7 @@ private func getCSRFToken(completionHandler: stringcompletion?) { /** - Sends a request to Drupal + Sends a request to Drupal with a specified path - parameter path: The path for the request. - parameter method: The method, eg, GET, POST etc. @@ -233,11 +291,25 @@ private func getCSRFToken(completionHandler: stringcompletion?) { */ public func sendRequest(path:String, method:Alamofire.Method, params:paramType, completionHandler: completion?) { - assert(waterwheelManager.sharedInstance.URL != "", "waterwheel Error: Mission Drupal URL") - let urlString = waterwheelManager.sharedInstance.URL + "/" + path + waterwheelManager.sharedInstance.requestFormat + sendRequestWithUrl(urlString, method: method, params: params, completionHandler: completionHandler) +} + +/** + Sends a request to Drupal with an already generated URL + + - parameter path: The path for the request. + - parameter method: The method, eg, GET, POST etc. + - parameter params: The parameters for the request. + - parameter completionHandler: A completion handler that your delegate method should call if you want the response. + + */ +public func sendRequestWithUrl(urlString:String, method:Alamofire.Method, params:paramType, completionHandler: completion?) { + + assert(urlString != "", "waterwheel Error: Missing Drupal URL") + postNotification(waterwheelNotifications.waterwheelDidStartRequest.rawValue, requestName: waterwheelNotificationsTypes.normalRequest.rawValue, object: nil) if (waterwheelManager.sharedInstance.signRequestsBasic == true) { let plainString = waterwheelManager.sharedInstance.basicUsername + ":" + waterwheelManager.sharedInstance.basicPassword @@ -256,9 +328,12 @@ public func sendRequest(path:String, method:Alamofire.Method, params:paramType, case .Failure(let error): completionHandler?(success: false, response: response, json: nil, error: error) } + postNotification(waterwheelNotifications.waterwheelDidStartRequest.rawValue, requestName: waterwheelNotificationsTypes.normalRequest.rawValue, object: response?.response) }) } + + // MARK: - GET Requests /** @@ -431,9 +506,58 @@ public let entityDelete: (entityType: EntityType, entityId:String, params: param - parameter entityId The id of the entity - parameter params: The parameters for the request. - parameter completionHandler: A completion handler that your delegate method should call if you want the response. - + */ public let nodeDelete: (nodeId:String, params: paramType, completionHandler: completion?) -> Void = { (entityId, params, completionHandler) in - entityDelete(entityType: .Node, entityId: entityId, params: params, completionHandler: completionHandler) + entityDelete(entityType: .Node, entityId: entityId, params: params, completionHandler: completionHandler) +} + + +// MARK: - Helper Functions + +/** + Private function to set Logged in Status + */ +private func setIsLoggedIn(isLoggedIn: Bool) { + waterwheelManager.sharedInstance.isLoggedIn = isLoggedIn + Defaults[.isLoggedIn] = isLoggedIn +} + + +/** + Public function to check if the user is logged in + + */ +public func isLoggedIn() -> Bool { + return waterwheelManager.sharedInstance.isLoggedIn +} + +/** + Private function to set logoutToken + */ +private func setLogoutToken(logoutToken: String) { + waterwheelManager.sharedInstance.logoutToken = logoutToken + Defaults[.logoutToken] = logoutToken +} + +/** + Private function to set csrf settings + */ +private func setCSRF(csrfToken: String, sign: Bool) { + waterwheelManager.sharedInstance.CSRFToken = csrfToken + waterwheelManager.sharedInstance.signCSRFToken = sign + Defaults[.csrfToken] = csrfToken + Defaults[.signCSRFToken] = sign +} + + + + +private func postNotification(name: String, requestName: String, object: AnyObject?) { + var notification = Dictionary() + notification["name"] = name + notification["type"] = requestName + notification["object"] = object + NSNotificationCenter.defaultCenter().postNotificationName(name, object: notification) } diff --git a/src/iOS/Buttons/waterwheelAuthButton.swift b/src/iOS/Buttons/waterwheelAuthButton.swift new file mode 100644 index 0000000..f575365 --- /dev/null +++ b/src/iOS/Buttons/waterwheelAuthButton.swift @@ -0,0 +1,75 @@ +// +// waterwheelAuthButton.swift +// Only For use in iOS + + +import UIKit +import waterwheel +import Alamofire +import SwiftyJSON + +public enum AuthAction: String { + case Login = "Login", Logout = "Logout" +} + +public class waterwheelAuthButton: UIButton { + + var didPressLogin: () -> () = { _ in } + var didPressLogout: (success:Bool, error: NSError?) -> () = { success, error in } + + override init(frame: CGRect) { + super.init(frame: frame) + + // Incase of logout or login, we attach to the notification Center for the purpose of seeing requests. + NSNotificationCenter.defaultCenter().addObserver( + self, + selector: #selector(setupButton), + name: waterwheelNotifications.waterwheelDidFinishRequest.rawValue, + object: nil) + + self.translatesAutoresizingMaskIntoConstraints = false; + self.setupButton() + } + + + public func setupButton() { + // Default states for the button. + self.setTitleColor(UIButton(type: UIButtonType.System).titleColorForState(.Normal)!, forState: .Normal) + + if waterwheel.isLoggedIn() { + self.setTitle("Logout", forState: .Normal) + self.removeTarget(self, action: #selector(waterwheelAuthButton.loginAction), forControlEvents: .TouchUpInside) + self.addTarget(self, action: #selector(waterwheelAuthButton.logoutAction), forControlEvents: .TouchUpInside) + } else { + self.setTitle("Login", forState: .Normal) + self.removeTarget(self, action: #selector(waterwheelAuthButton.logoutAction), forControlEvents: .TouchUpInside) + self.addTarget(self, action: #selector(waterwheelAuthButton.loginAction), forControlEvents: .TouchUpInside) + } + } + + required public init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + /** + This method provies an action to take when the button is in a logged in state. + We automatically log the user out, but provide a closure that can be used to do anything else base on the outcome. + + */ + + public func logoutAction() { + waterwheel.logout { (success, response, json, error) in + self.didPressLogout(success: success, error: error) + } + } + + /** + This method provies an action to take when the button is in a logged out state. + + */ + public func loginAction() { + self.didPressLogin() + } +} + + diff --git a/src/iOS/Views/waterwheelLoginViewController.swift b/src/iOS/Views/waterwheelLoginViewController.swift new file mode 100644 index 0000000..1b14d9e --- /dev/null +++ b/src/iOS/Views/waterwheelLoginViewController.swift @@ -0,0 +1,266 @@ +// +// waterwheelLoginViewController.swift +// +// + +import UIKit +import waterwheel + +extension UIViewController { + +} +public class waterwheelLoginViewController: UIViewController { + + let usernameField = UITextField() + let passwordField = UITextField() + let submitButton = waterwheelAuthButton() + + /// Provide a closure for when a Login Request is completed. + var loginRequestCompleted: (success: Bool, error: NSError?) -> () = { _ in } + /// Provide a closure for when a Logout Request is completed. + var logoutRequestCompleted: (success: Bool, error: NSError?) -> () = { _ in } + + override public func viewDidLoad() { + super.viewDidLoad() + self.view.backgroundColor = .whiteColor() + if !waterwheel.isLoggedIn() { + self.setupAnonymousView() + } else { + self.setupAuthenticatedView() + } + // Incase of logout or login, we attach to the notification Center for the purpose of seeing requests. + NSNotificationCenter.defaultCenter().addObserver( + self, + selector: #selector(configure), + name: waterwheelNotifications.waterwheelDidFinishRequest.rawValue, + object: nil) + } + /** + Overridden viewDidAppear where decide if were logged in or not. + + - parameter animated: Is the view animated + */ + override public func viewDidAppear(animated: Bool) { + self.configure() + } + + /** + Configure this viewcontrollers view based on auth state. + */ + + public func configure() { + if !waterwheel.isLoggedIn() { + self.setupAnonymousView() + } else { + self.setupAuthenticatedView() + } + } + + /** + Setup the authenticated Subviews. + */ + public func setupAuthenticatedView() { + self.configureAuthenticatedSubviews() + self.addAuthenticatedSubviews() + self.layoutAuthenticatedSubviews() + + } + /** + Setup the Anonymous Subviews. + */ + public func setupAnonymousView() { + self.configureAnonymousSubviews() + self.addAnonymousSubviews() + self.layoutAnonymousSubviews() + } + + /** + Configure authenticated Subviews. + */ + public func configureAuthenticatedSubviews() { + self.configureAuthenticatedButton() + } + + /** + Configure Anonymous Subviews. + */ + public func configureAnonymousSubviews() { + self.configureUsernameField() + self.configurePasswordField() + self.configureAnonymousButton() + } + + /** + Configure the username field defaults. + */ + public func configureUsernameField() { + usernameField.autocorrectionType = .No + usernameField.attributedPlaceholder = NSAttributedString(string: "Email") + usernameField.translatesAutoresizingMaskIntoConstraints = false; + usernameField.backgroundColor = UIColor.lightGrayColor() + usernameField.textAlignment = .Center + usernameField.placeholder = "Username" + } + /** + Configure the password field defaults. + */ + public func configurePasswordField() { + passwordField.secureTextEntry = true + passwordField.autocorrectionType = .No + passwordField.attributedPlaceholder = NSAttributedString(string: "Password") + passwordField.backgroundColor = UIColor.lightGrayColor() + passwordField.textAlignment = .Center + passwordField.translatesAutoresizingMaskIntoConstraints = false; + passwordField.placeholder = "test" + passwordField.text = "test" + } + + /** + Configure Anonymous button defaults. + */ + public func configureAnonymousButton() { + submitButton.translatesAutoresizingMaskIntoConstraints = false; + submitButton.backgroundColor = UIColor.darkGrayColor() + submitButton.didPressLogin = { + self.loginAction() + } + } + + /** + Configure Authenticated Button defaults. + */ + public func configureAuthenticatedButton() { + submitButton.translatesAutoresizingMaskIntoConstraints = false; + submitButton.backgroundColor = UIColor.darkGrayColor() + submitButton.didPressLogout = { (success, error) in + self.logoutAction(success, error: error) + } + } + + /** + Layout the Anonymous Subviews. + */ + public func layoutAnonymousSubviews() { + self.layoutLoginField() + self.layoutPasswordField() + self.layoutAnonymousButton() + } + + /** + Layout the Authenticated Subviews. + */ + public func layoutAuthenticatedSubviews() { + self.layoutAuthenticatedButton() + } + + /** + Lays out the authenticated button. + */ + public func layoutAuthenticatedButton() { + submitButton.constrainEqual(.LeadingMargin, to: view) + submitButton.constrainEqual(.TrailingMargin, to: view) + submitButton.constrainEqual(.Bottom, to: view, .Bottom, multiplier: 1.0, constant: -100) + submitButton.heightAnchor.constraintEqualToConstant(50.0).active = true + } + + /** + Lays out the login field. + */ + public func layoutLoginField() { + usernameField.constrainEqual(.LeadingMargin, to: view) + usernameField.constrainEqual(.TrailingMargin, to: view) + usernameField.constrainEqual(.Top, to: view, .Top, multiplier: 1.0, constant: 44) + usernameField.heightAnchor.constraintEqualToConstant(50.0).active = true + } + + /** + Lays out the password field. + */ + public func layoutPasswordField() { + passwordField.constrainEqual(.LeadingMargin, to: view) + passwordField.constrainEqual(.TrailingMargin, to: view) + passwordField.constrainEqual(.BottomMargin, to: usernameField, .BottomMargin, multiplier: 1.0, constant: 55) + passwordField.heightAnchor.constraintEqualToConstant(50.0).active = true + } + + /** + Lays out the Anonymous Button + */ + public func layoutAnonymousButton() { + submitButton.constrainEqual(.LeadingMargin, to: view) + submitButton.constrainEqual(.TrailingMargin, to: view) + submitButton.constrainEqual(.BottomMargin, to: passwordField, .BottomMargin, multiplier: 1.0, constant: 55) + submitButton.heightAnchor.constraintEqualToConstant(50.0).active = true + } + + /** + Removes authenticated Subviews + */ + public func removeAuthenticatedSubviews() { + submitButton.removeFromSuperview() + submitButton.removeTarget(self, action: #selector(waterwheelLoginViewController.logoutAction), forControlEvents: .TouchUpInside) + } + + /** + Adds authenticated Subviews. + */ + public func addAuthenticatedSubviews() { + self.view.addSubview(submitButton) + } + + /** + Remove anonymous subviews. + */ + public func removeAnonymousSubviews() { + usernameField.removeFromSuperview() + passwordField.removeFromSuperview() + submitButton.removeFromSuperview() + submitButton.removeTarget(self, action: #selector(waterwheelLoginViewController.loginAction), forControlEvents: .TouchUpInside) + } + + /** + Add Anonymous subviews. + */ + public func addAnonymousSubviews() { + self.view.addSubview(usernameField) + self.view.addSubview(passwordField) + self.view.addSubview(submitButton) + } + + /** + Public Login Action function for the login button that runs our closure. + */ + public func loginAction() { + waterwheel.login(usernameField.text!, password: passwordField.text!) { (success, response, json, error) in + if (success) { + self.removeAnonymousSubviews() + self.setupAuthenticatedView() + } else { + print("failed to login") + } + self.loginRequestCompleted(success: success, error: error) + } + } + + /** + Public Logout action that runs our closure. + + - parameter success: success or failure + - parameter error: if error happened. + */ + public func logoutAction(success: Bool, error: NSError?) { + if (success) { + self.removeAuthenticatedSubviews() + self.setupAnonymousView() + } else { + print("failed to logout") + } + self.logoutRequestCompleted(success: success, error: error) + } + + + override public func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } +} \ No newline at end of file diff --git a/waterwheel.podspec b/waterwheel.podspec index 88e5d72..772de16 100644 --- a/waterwheel.podspec +++ b/waterwheel.podspec @@ -33,4 +33,5 @@ Pod::Spec.new do |s| s.license = { :type => 'MPL 1.1/GPL 2.0', :file => "LICENSE" } s.dependency 'Alamofire' s.dependency 'SwiftyJSON' + s.dependency 'SwiftyUserDefaults' end