Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto close on success event behaviour and customization #370

Merged
merged 5 commits into from
Jan 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Lock.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@
5BCDE1341DDDF12100AA2A6C /* EnterpriseActiveAuthPresenterSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnterpriseActiveAuthPresenterSpec.swift; sourceTree = "<group>"; };
5BCED4C51DD1FCF200E2CE8A /* EnterpriseDomainPresenterSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnterpriseDomainPresenterSpec.swift; sourceTree = "<group>"; };
5F0FCF8F1E20117E00E3D53B /* ObserverStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObserverStore.swift; sourceTree = "<group>"; };
5F0FCF911E201CF300E3D53B /* ObserverStoreSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObserverStoreSpec.swift; sourceTree = "<group>"; };
5F0FCF911E201CF300E3D53B /* ObserverStoreSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = ObserverStoreSpec.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
5F1456591D5130E80085DF9C /* Colors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Colors.swift; path = Lock/Colors.swift; sourceTree = SOURCE_ROOT; };
5F1C498D1D8360AA005B74FC /* Style.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Style.swift; path = Lock/Style.swift; sourceTree = SOURCE_ROOT; };
5F1C498F1D8360BF005B74FC /* ConnectionLoadingPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ConnectionLoadingPresenter.swift; path = Lock/ConnectionLoadingPresenter.swift; sourceTree = SOURCE_ROOT; };
Expand Down
4 changes: 3 additions & 1 deletion Lock/DatabaseForgotPasswordPresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ class DatabaseForgotPasswordPresenter: Presentable, Loggable {
self.logger.error("Failed with error \(error)")
} else {
let message = "We've just sent you an email to reset your password".i18n(key: "com.auth0.lock.database.forgot.success.message", comment: "forgot password email sent")
self.messagePresenter?.showSuccess(message)
if self.options.allow.contains(.Login) || !self.options.autoClose {
self.messagePresenter?.showSuccess(message)
}
guard self.options.allow.contains(.Login) else { return }
self.navigator.navigate(.root)
}
Expand Down
5 changes: 4 additions & 1 deletion Lock/DatabasePasswordInteractor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import Auth0
struct DatabasePasswordInteractor: PasswordRecoverable {

private var user: DatabaseUser
private let dispatcher: Dispatcher

var email: String? { return self.user.email }
var validEmail: Bool { return self.user.validEmail }
Expand All @@ -34,10 +35,11 @@ struct DatabasePasswordInteractor: PasswordRecoverable {
let connections: Connections
let emailValidator: InputValidator = EmailValidator()

init(connections: Connections, authentication: Authentication, user: DatabaseUser) {
init(connections: Connections, authentication: Authentication, user: DatabaseUser, dispatcher: Dispatcher) {
self.authentication = authentication
self.connections = connections
self.user = user
self.dispatcher = dispatcher
}

mutating func updateEmail(_ value: String?) throws {
Expand All @@ -55,6 +57,7 @@ struct DatabasePasswordInteractor: PasswordRecoverable {
.resetPassword(email: email, connection: connection)
.start {
guard case .success = $0 else { return callback(.emailNotSent) }
self.dispatcher.dispatch(result: .forgotPassword(email))
callback(nil)
}
}
Expand Down
8 changes: 7 additions & 1 deletion Lock/DatabasePresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ class DatabasePresenter: Presentable, Loggable {
button.inProgress = false
guard let error = error else {
self.logger.debug("Logged in!")
let message = "You have logged in successfully.".i18n(key: "com.auth0.lock.database.login.success.message", comment: "User logged in")
if !self.options.autoClose {
self.messagePresenter?.showSuccess(message)
}
return
}
if case DatabaseAuthenticatableError.multifactorRequired = error {
Expand Down Expand Up @@ -162,7 +166,9 @@ class DatabasePresenter: Presentable, Loggable {
if let databaseView = self.databaseView, self.options.allow.contains(.Login) {
self.showLogin(inView: databaseView, identifier: self.creator.identifier)
}
self.messagePresenter?.showSuccess(message)
if self.options.allow.contains(.Login) || !self.options.autoClose {
self.messagePresenter?.showSuccess(message)
}
}
return
}
Expand Down
1 change: 1 addition & 0 deletions Lock/Lock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ public class Lock: NSObject {
var builder: OptionBuildable = self.optionsBuilder
closure(&builder)
self.optionsBuilder = builder
self.observerStore.options = self.options
_ = self.authentication.logging(enabled: self.options.logHttpRequest)
_ = self.webAuth.logging(enabled: self.options.logHttpRequest)
return self
Expand Down
1 change: 1 addition & 0 deletions Lock/LockOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ struct LockOptions: OptionBuildable {
var scope: String = "openid"
var parameters: [String : Any] = [:]
var allow: DatabaseMode = [.Login, .Signup, .ResetPassword]
var autoClose: Bool = true
var initialScreen: DatabaseScreen = .login
var usernameStyle: DatabaseIdentifierStyle = [.Username, .Email]
var customSignupFields: [CustomTextField] = []
Expand Down
23 changes: 19 additions & 4 deletions Lock/ObserverStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,38 @@ struct ObserverStore: Dispatcher {
var onFailure: (Error) -> () = { _ in }
var onCancel: () -> () = { }
var onSignUp: (String, [String: Any]) -> () = { _ in }
var onForgotPassword: (String) -> () = { _ in }
var options: Options = LockOptions()

weak var controller: UIViewController?

func dispatch(result: Result) {
let closure: () -> ()
switch result {
case .auth(let credentials):
closure = dismiss(from: controller?.presentingViewController, completion: { self.onAuth(credentials) })
if self.options.autoClose {
closure = dismiss(from: controller?.presentingViewController, completion: { self.onAuth(credentials) })
} else {
closure = { self.onAuth(credentials) }
}
case .error(let error):
closure = { self.onFailure(error) }
case .cancel:
closure = dismiss(from: controller?.presentingViewController, completion: { self.onCancel() })
case .signUp(let email, let attributes):
closure = { self.onSignUp(email, attributes) }
default:
closure = {}
if !self.options.allow.contains(.Login) && self.options.autoClose {
closure = dismiss(from: controller?.presentingViewController, completion: { self.onSignUp(email, attributes) })
} else {
closure = { self.onSignUp(email, attributes) }
}
case .forgotPassword(let email):
if !self.options.allow.contains(.Login) && self.options.autoClose {
closure = dismiss(from: controller?.presentingViewController, completion: { self.onForgotPassword(email) })
} else {
closure = { self.onForgotPassword(email) }
}
}

Queue.main.async(closure)
}

Expand Down
4 changes: 4 additions & 0 deletions Lock/OptionBuildable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ public protocol OptionBuildable: Options {
/// What database modes are allowed and must be at least one. By default all modes are allowed.
var allow: DatabaseMode { get set }

/// Should Lock close if only mode available. By default is true
var autoClose: Bool { get set }

/// Initial screen displayed by Lock when a database connection is available. By default is Login
var initialScreen: DatabaseScreen { get set }

Expand Down Expand Up @@ -87,6 +90,7 @@ internal extension OptionBuildable {
func validate() -> UnrecoverableError? {
guard !self.allow.isEmpty else { return UnrecoverableError.invalidOptions(cause: "Must allow at least one database mode") }
guard !self.usernameStyle.isEmpty else { return UnrecoverableError.invalidOptions(cause: "Must specify at least one username style") }
guard self.allow.contains(.Login) || self.closable || self.autoClose else { return UnrecoverableError.invalidOptions(cause: "Must enable autoclose or enable closable") }
return nil
}
}
Expand Down
1 change: 1 addition & 0 deletions Lock/Options.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public protocol Options {
var scope: String { get }
var parameters: [String: Any] { get }
var allow: DatabaseMode { get }
var autoClose: Bool { get }
var initialScreen: DatabaseScreen { get }
var usernameStyle: DatabaseIdentifierStyle { get }
var customSignupFields: [CustomTextField] { get }
Expand Down
2 changes: 1 addition & 1 deletion Lock/Router.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ struct Router: Navigable {
exit(withError: UnrecoverableError.clientWithNoConnections)
return nil
}
let interactor = DatabasePasswordInteractor(connections: connections, authentication: self.lock.authentication, user: self.user)
let interactor = DatabasePasswordInteractor(connections: connections, authentication: self.lock.authentication, user: self.user, dispatcher: lock.observerStore)
let presenter = DatabaseForgotPasswordPresenter(interactor: interactor, connections: connections, navigator: self, options: self.lock.options)
presenter.customLogger = self.lock.logger
return presenter
Expand Down
63 changes: 13 additions & 50 deletions LockTests/Interactors/DatabaseInteractorSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,16 @@ class DatabaseInteractorSpec: QuickSpec {

describe("init") {

let options = LockOptions()
let dispatcher = ObserverStore()

it("should build with authentication") {
let database = DatabaseInteractor(connection: DatabaseConnection(name: "db", requiresUsername: true), authentication: authentication, user: User(), options: LockOptions(), dispatcher: ObserverStore())
let database = DatabaseInteractor(connection: DatabaseConnection(name: "db", requiresUsername: true), authentication: authentication, user: User(), options: options, dispatcher: dispatcher)
expect(database).toNot(beNil())
}

it("should have authentication object") {
let database = DatabaseInteractor(connection: DatabaseConnection(name: "db", requiresUsername: true), authentication: authentication, user: User(), options: LockOptions(), dispatcher: ObserverStore())
let database = DatabaseInteractor(connection: DatabaseConnection(name: "db", requiresUsername: true), authentication: authentication, user: User(), options: options, dispatcher: dispatcher)
expect(database.credentialAuth.authentication.clientId) == "CLIENT_ID"
expect(database.credentialAuth.authentication.url.host) == "samples.auth0.com"
expect(database.credentialAuth.oidc) == false
Expand All @@ -56,12 +59,16 @@ class DatabaseInteractorSpec: QuickSpec {
var database: DatabaseInteractor!
var user: User!
var options: OptionBuildable!
var dispatcher: ObserverStore!

beforeEach {
options = LockOptions()
dispatcher = ObserverStore()

Auth0Stubs.failUnknown()
user = User()
let db = DatabaseConnection(name: connection, requiresUsername: true, usernameValidator: UsernameValidator(withLength: 1...15, characterSet: UsernameValidator.auth0), passwordValidator: PasswordPolicyValidator(policy: .good))
database = DatabaseInteractor(connection: db, authentication: authentication, user: user, options: LockOptions(), dispatcher: ObserverStore())
database = DatabaseInteractor(connection: db, authentication: authentication, user: user, options: options, dispatcher: dispatcher)
}

describe("updateAttribute") {
Expand Down Expand Up @@ -559,7 +566,6 @@ class DatabaseInteractorSpec: QuickSpec {
}
}
}

}

describe("login OIDC Conformant") {
Expand Down Expand Up @@ -733,7 +739,6 @@ class DatabaseInteractorSpec: QuickSpec {
}
}
}

}

// MARK: - Signup
Expand Down Expand Up @@ -796,7 +801,7 @@ class DatabaseInteractorSpec: QuickSpec {
}
}

context("Auto log in after sign up") {
context("auto log in after sign up") {

var options = LockOptions()

Expand Down Expand Up @@ -1020,48 +1025,6 @@ class DatabaseInteractorSpec: QuickSpec {
}
}

context("auto login disabled") {

var options: LockOptions!
var newUserEmail: String?

beforeEach {
newUserEmail = nil
options = LockOptions()
options.loginAfterSignup = false
var dispatcher = ObserverStore()
dispatcher.onSignUp = { email, _ in
newUserEmail = email
}
let db = DatabaseConnection(name: connection, requiresUsername: true, usernameValidator: UsernameValidator(withLength: 1...15, characterSet: UsernameValidator.auth0), passwordValidator: PasswordPolicyValidator(policy: .good))
database = DatabaseInteractor(connection: db, authentication: authentication, user: user, options: options, dispatcher: dispatcher)
stub(condition: databaseLogin(identifier: email, password: password, connection: connection)) { _ in return Auth0Stubs.failure() }
stub(condition: databaseSignUp(email: email, username: username, password: password, connection: connection)) { _ in return Auth0Stubs.createdUser(email) }
}

it("should only signup user") {
try! database.update(.email, value: email)
try! database.update(.username, value: username)
try! database.update(.password(enforcePolicy: false), value: password)
waitUntil(timeout: 2) { done in
database.create { create, login in
expect(create).to(beNil())
expect(login).to(beNil())
done()
}
}
}

it("should dispatch signup event") {
try! database.update(.email, value: email)
try! database.update(.username, value: username)
try! database.update(.password(enforcePolicy: false), value: password)
database.create { _ in }
expect(newUserEmail).toEventually(equal(email))
}

}

describe("signup OIDC Conformnant") {

beforeEach {
Expand Down Expand Up @@ -1253,7 +1216,7 @@ class DatabaseInteractorSpec: QuickSpec {
}
}
}

it("should send parameters on login") {
let state = UUID().uuidString
var options = LockOptions()
Expand All @@ -1272,7 +1235,7 @@ class DatabaseInteractorSpec: QuickSpec {
}
}
}

}

}
Expand Down
11 changes: 6 additions & 5 deletions LockTests/Interactors/DatabasePasswordInteractorSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class DatabasePasswordInteractorSpec: QuickSpec {
}

describe("init") {
let database = DatabasePasswordInteractor(connections: OfflineConnections(), authentication: authentication, user: User())
let database = DatabasePasswordInteractor(connections: OfflineConnections(), authentication: authentication, user: User(), dispatcher: ObserverStore())

it("should build with authentication") {
expect(database).toNot(beNil())
Expand All @@ -54,12 +54,14 @@ class DatabasePasswordInteractorSpec: QuickSpec {
var user: User!
var connections: OfflineConnections!
var forgot: DatabasePasswordInteractor!
var dispatcher: Dispatcher!

beforeEach {
dispatcher = ObserverStore()
connections = OfflineConnections()
connections.database(name: connection, requiresUsername: true)
user = User()
forgot = DatabasePasswordInteractor(connections: connections, authentication: authentication, user: user)
forgot = DatabasePasswordInteractor(connections: connections, authentication: authentication, user: user, dispatcher: dispatcher)
}

describe("updateEmail") {
Expand Down Expand Up @@ -102,7 +104,7 @@ class DatabasePasswordInteractorSpec: QuickSpec {
describe("request email") {

it("should fail if no db connection is found") {
forgot = DatabasePasswordInteractor(connections: OfflineConnections(), authentication: authentication, user: user)
forgot = DatabasePasswordInteractor(connections: OfflineConnections(), authentication: authentication, user: user, dispatcher: dispatcher)
try! forgot.updateEmail(email)
waitUntil(timeout: 2) { done in
forgot.requestEmail { error in
Expand Down Expand Up @@ -142,8 +144,7 @@ class DatabasePasswordInteractorSpec: QuickSpec {
}
}
}

}
}

}
Loading