Commit f00be3c6 authored by Kateryna Kostiuk's avatar Kateryna Kostiuk

account creation: save name

- save registered name for  new account
- refactor account creation to support multiple accounts
this patch include changes from
Romain Bertozzi <romain.bertozzi@savoirfairelinux.com> patches:
https://gerrit-ring.savoirfairelinux.com/c/ring-client-ios/+/8661
and https://gerrit-ring.savoirfairelinux.com/c/ring-client-ios/+/8666

Change-Id: I5a827f0215f820eddfde5c4e90f76713670695b2
Gitlab: #24
parent a3a17453
......@@ -236,7 +236,7 @@ class CreateAccountViewModel: Stateable, ViewModel {
}()
required init (with injectionBag: InjectionBag) {
var isPageDisplayed = false
// var isPageDisplayed = false
self.accountService = injectionBag.accountService
self.nameService = injectionBag.nameService
......@@ -257,53 +257,32 @@ class CreateAccountViewModel: Stateable, ViewModel {
self?.usernameValidationState.value = .available
}
}).disposed(by: self.disposeBag)
}
//Name registration observer
self.accountService
.sharedResponseStream
.filter({ [unowned self] (event) in
return event.eventType == ServiceEventType.registrationStateChanged &&
event.getEventInput(ServiceEventInput.registrationState) == Unregistered &&
self.registerUsername.value
})
.subscribe(onNext: { [unowned self] _ in
func createAccount() {
self.accountCreationState.value = .started
//Launch the process of name registration
if let currentAccountId = self.accountService.currentAccount?.id {
self.nameService.registerName(withAccount: currentAccountId,
password: self.password.value,
name: self.username.value)
}
})
.disposed(by: disposeBag)
let username = self.username.value
let password = self.password.value
//Account creation state observer
self.accountService
.sharedResponseStream
.subscribe(onNext: { [unowned self] event in
if event.getEventInput(ServiceEventInput.registrationState) == Unregistered {
self.accountCreationState.value = .success
if !isPageDisplayed {
DispatchQueue.main.async {
self.stateSubject.onNext(WalkthroughState.accountCreated)
}
isPageDisplayed = true
}
} else if event.getEventInput(ServiceEventInput.registrationState) == ErrorGeneric {
self.accountCreationState.value = .error(error: AccountCreationError.generic)
} else if event.getEventInput(ServiceEventInput.registrationState) == ErrorNetwork {
self.accountCreationState.value = .error(error: AccountCreationError.network)
.addRingAccount(username: username, password: password)
.subscribe(onNext: { [unowned self] (account) in
self.accountCreationState.value = .success
DispatchQueue.main.async {
self.stateSubject.onNext(WalkthroughState.accountCreated)
}
}, onError: { [unowned self] _ in
self.accountCreationState.value = .error(error: AccountCreationError.unknown)
}).disposed(by: disposeBag)
}
func createAccount() {
self.accountCreationState.value = .started
self.accountService.addRingAccount(withUsername: self.username.value,
password: self.password.value, enable: self.notificationSwitch.value)
self.nameService.registerName(withAccount: account.id,
password: password,
name: username)
}, onError: { [unowned self] (error) in
if let error = error as? AccountCreationError {
self.accountCreationState.value = .error(error: error)
} else {
self.accountCreationState.value = .error(error: AccountCreationError.unknown)
}
})
.disposed(by: self.disposeBag)
self.enablePushNotifications(enable: self.notificationSwitch.value)
}
......
......@@ -25,6 +25,7 @@ enum NotificationUserInfoKeys: String {
case name
case messageContent
case participantID
case accountID
}
enum NotificationCallTitle: String {
......
......@@ -38,6 +38,7 @@ enum DeviceRevocationState: Int {
enum AddAccountError: Error {
case templateNotConform
case unknownError
case noAccountFound
}
enum NotificationName: String {
......@@ -45,6 +46,7 @@ enum NotificationName: String {
case disablePushNotifications
case answerCallFromNotifications
case refuseCallFromNotifications
case nameRegistered
}
// swiftlint:disable type_body_length
......@@ -153,7 +155,9 @@ class AccountsService: AccountAdapterDelegate {
//~ Registering to the accountAdatpter with self as delegate in order to receive delegation
//~ callbacks.
AccountAdapter.delegate = self
NotificationCenter.default.addObserver(self, selector: #selector(self.saveAccountConfiguration(_:)),
name: NSNotification.Name(rawValue: NotificationName.nameRegistered.rawValue),
object: nil)
}
fileprivate func loadAccountsFromDaemon() {
......@@ -162,7 +166,6 @@ class AccountsService: AccountAdapterDelegate {
self.accountList.append(AccountModel(withAccountId: id))
}
}
reloadAccounts()
}
......@@ -194,53 +197,60 @@ class AccountsService: AccountAdapterDelegate {
}
}
/**
Entry point to create a brand-new Ring account.
- Parameter username: the username chosen by the user, if any
- Parameter password: the password chosen by the user
*/
func addRingAccount(withUsername username: String?, password: String, enable: Bool) {
do {
var ringDetails = try self.getRingInitialAccountDetails()
if username != nil {
ringDetails.updateValue(username!, forKey: ConfigKey.accountRegisteredName.rawValue)
/// Adds a new Ring account.
///
/// - Parameters:
/// - username: an optional username for the new account
/// - password: the required password for the new account
/// - Returns: an observable of an AccountModel: the created one
func addRingAccount(username: String?, password: String) -> Observable<AccountModel> {
//~ Single asking the daemon to add a new account with the associated metadata
let createAccountSingle: Single<AccountModel> = Single.create(subscribe: { (single) -> Disposable in
do {
var ringDetails = try self.getRingInitialAccountDetails()
if let username = username {
ringDetails.updateValue(username, forKey: ConfigKey.accountRegisteredName.rawValue)
}
if !password.isEmpty {
ringDetails.updateValue(password, forKey: ConfigKey.archivePassword.rawValue)
}
guard let accountId = self.accountAdapter.addAccount(ringDetails) else {
throw AddAccountError.unknownError
}
let account = try self.buildAccountFromDaemon(accountId: accountId)
single(.success(account))
} catch {
single(.error(error))
}
ringDetails.updateValue(password, forKey: ConfigKey.archivePassword.rawValue)
ringDetails.updateValue(enable.toString(), forKey: ConfigKey.proxyEnabled.rawValue)
let accountId = self.accountAdapter.addAccount(ringDetails)
guard accountId != nil else {
throw AddAccountError.unknownError
return Disposables.create {
}
var account = self.getAccount(fromAccountId: accountId!)
if account == nil {
let details = self.getAccountDetails(fromAccountId: accountId!)
let volatileDetails = self.getVolatileAccountDetails(fromAccountId: accountId!)
let credentials = try self.getAccountCredentials(fromAccountId: accountId!)
let devices = getKnownRingDevices(fromAccountId: accountId!)
account = try AccountModel(withAccountId: accountId!,
details: details,
volatileDetails: volatileDetails,
credentials: credentials,
devices: devices)
setRingtonePath(forAccountId: accountId!)
let accountModelHelper = AccountModelHelper(withAccount: account!)
var accountAddedEvent = ServiceEvent(withEventType: .accountAdded)
accountAddedEvent.addEventInput(.id, value: account?.id)
accountAddedEvent.addEventInput(.state, value: accountModelHelper.getRegistrationState())
self.responseStream.onNext(accountAddedEvent)
})
//~ Filter the daemon signals to isolate the "account created" one.
let filteredDaemonSignals = self.sharedResponseStream
.filter { (serviceEvent) -> Bool in
if serviceEvent.getEventInput(ServiceEventInput.registrationState) == ErrorGeneric {
throw AccountCreationError.generic
} else if serviceEvent.getEventInput(ServiceEventInput.registrationState) == ErrorNetwork {
throw AccountCreationError.network
}
self.currentAccount = account
} catch {
self.responseStream.onError(error)
let isRegistrationStateChanged = serviceEvent.eventType == ServiceEventType.registrationStateChanged
let isRegistered = serviceEvent.getEventInput(ServiceEventInput.registrationState) == Registered
let notRegistered = serviceEvent.getEventInput(ServiceEventInput.registrationState) == Unregistered
return isRegistrationStateChanged && (isRegistered || notRegistered)
}
//~ Make sure that we have the correct account added in the daemon, and return it.
return Observable
.combineLatest(createAccountSingle.asObservable(), filteredDaemonSignals.asObservable()) { (accountModel, serviceEvent) -> AccountModel in
guard accountModel.id == serviceEvent.getEventInput(ServiceEventInput.accountId) else {
throw AddAccountError.unknownError
}
return accountModel
}.take(1)
.flatMap({ [unowned self] (accountModel) -> Observable<AccountModel> in
return self.getAccountFromDaemon(fromAccountId: accountModel.id).asObservable()
})
}
func setRingtonePath(forAccountId accountId: String) {
......@@ -312,6 +322,21 @@ class AccountsService: AccountAdapterDelegate {
return nil
}
/// Gets the account from the daemon responding to the given id.
///
/// - Parameter id: the id of the account to get.
/// - Returns: a single of an AccountModel
func getAccountFromDaemon(fromAccountId id: String) -> Single<AccountModel> {
return self.loadAccounts().map({ (accountModels) -> AccountModel in
guard let account = accountModels.filter({ (accountModel) -> Bool in
return id == accountModel.id
}).first else {
throw AddAccountError.noAccountFound
}
return account
})
}
/**
Gets all the details of an account from the daemon.
......@@ -381,6 +406,14 @@ class AccountsService: AccountAdapterDelegate {
}
}
@objc func saveAccountConfiguration(_ notification: NSNotification) {
guard let accountID = notification.userInfo?[NotificationUserInfoKeys.accountID.rawValue] as? String else {
return
}
let accountDetails = self.getAccountDetails(fromAccountId: accountID)
self.setAccountDetails(forAccountId: accountID, withDetails: accountDetails)
}
/**
Gets the known Ring devices of an account from the daemon.
......@@ -464,17 +497,14 @@ class AccountsService: AccountAdapterDelegate {
func registrationStateChanged(with response: RegistrationResponse) {
log.debug("RegistrationStateChanged.")
if let state = response.state, state == Registered {
if let account = self.currentAccount {
if let ringID = AccountModelHelper(withAccount: account).ringId {
dbManager.profileObservable(for: ringID, createIfNotExists: true)
.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background))
.subscribe()
.disposed(by: self.disposeBag)
}
}
dbManager.profileObservable(for: response.accountId, createIfNotExists: true)
.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background))
.subscribe()
.disposed(by: self.disposeBag)
}
var event = ServiceEvent(withEventType: .registrationStateChanged)
event.addEventInput(.registrationState, value: response.state)
event.addEventInput(.accountId, value: response.accountId)
self.responseStream.onNext(event)
}
......@@ -679,3 +709,22 @@ class AccountsService: AccountAdapterDelegate {
return accountDevices.concat(newDevice)
}
}
// MARK: - Private daemon wrappers
extension AccountsService {
fileprivate func buildAccountFromDaemon(accountId id: String) throws -> AccountModel {
let accountModel = AccountModel(withAccountId: id)
accountModel.details = self.getAccountDetails(fromAccountId: id)
accountModel.volatileDetails = self.getVolatileAccountDetails(fromAccountId: id)
accountModel.devices = self.getKnownRingDevices(fromAccountId: id)
do {
let credentialDetails = try self.getAccountCredentials(fromAccountId: id)
accountModel.credentialDetails.removeAll()
accountModel.credentialDetails.append(contentsOf: credentialDetails)
} catch {
throw error
}
return accountModel
}
}
......@@ -117,6 +117,9 @@ class NameService: NameRegistrationAdapterDelegate {
internal func nameRegistrationEnded(with response: NameRegistrationResponse) {
if response.state == .success {
var data = [String: String]()
data[NotificationUserInfoKeys.accountID.rawValue] = response.accountId
NotificationCenter.default.post(name: NSNotification.Name(NotificationName.nameRegistered.rawValue), object: nil, userInfo: data)
log.debug("Registred name : \(response.name ?? "no name")")
} else {
log.debug("Name Registration failed. State = \(response.state.rawValue)")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment