pEpForiOS/UI/Settings/Setting/AccountSettings/ViewModel/AccountSettingsViewModel.swift
author buff <andreas@pep-project.org>
Thu, 21 Mar 2019 13:28:13 +0100
branchIOS-1521
changeset 8036 5715e9871572
parent 8018 5c633191f4ed
parent 7999 eb9680b63e70
child 8156 0e7ddb9f1170
permissions -rw-r--r--
merge refactor
     1 //
     2 //  AccountSettingsViewModel.swift
     3 //  pEpForiOS
     4 //
     5 //  Created by Xavier Algarra on 13/06/2017.
     6 //  Copyright © 2017 p≡p Security S.A. All rights reserved.
     7 //
     8 
     9 import Foundation
    10 import MessageModel
    11 import pEpIOSToolbox
    12 
    13 public class AccountSettingsViewModel {
    14     public struct ServerViewModel {
    15         var address: String?
    16         var port: String?
    17         var transport: String?
    18     }
    19 
    20     public struct SecurityViewModel {
    21         var options = Server.Transport.toArray()
    22         var size : Int {
    23             get {
    24                 return options.count
    25             }
    26         }
    27 
    28         subscript(option: Int) -> String {
    29             get {
    30                 return options[option].asString()
    31             }
    32         }
    33     }
    34 
    35     private (set) var account: Account
    36     private let headers = [
    37         NSLocalizedString("Account", comment: "Account settings"),
    38         NSLocalizedString("IMAP Settings", comment: "Account settings title IMAP"),
    39         NSLocalizedString("SMTP Settings", comment: "Account settings title SMTP")
    40     ]
    41     private var controlWord = "noRealPassword"
    42 
    43     public let svm = SecurityViewModel()
    44     public let isOAuth2: Bool
    45 
    46     public init(account: Account) {
    47         // We are using a copy here. The outside world must not know changed settings until they
    48         // have been verified.
    49         self.account = Account(withDataFrom: account)
    50         isOAuth2 = account.server(with: .imap)?.authMethod == AuthMethod.saslXoauth2.rawValue
    51     }
    52 
    53     var email: String {
    54         get {
    55             return account.user.address
    56         }
    57     }
    58 
    59     var loginName: String {
    60         get {
    61             // the email model is based on the assumption that imap.loginName == smtp.loginName
    62             return account.server(with: .imap)?.credentials.loginName ?? ""
    63         }
    64     }
    65 
    66     var name: String {
    67         get {
    68             return account.user.userName ?? ""
    69         }
    70     }
    71 
    72     var smtpServer: ServerViewModel {
    73         get {
    74             if let server = account.smtpServer {
    75                 return ServerViewModel(address: server.address,
    76                                        port: "\(server.port)",
    77                     transport: server.transport.asString())
    78             }
    79             return ServerViewModel()
    80         }
    81     }
    82 
    83     var imapServer: ServerViewModel {
    84         get {
    85             if let server = account.imapServer {
    86                 return ServerViewModel(address: server.address,
    87                                        port: "\(server.port)",
    88                     transport: server.transport.asString())
    89             }
    90             return ServerViewModel()
    91         }
    92     }
    93 
    94     var messageSyncService: MessageSyncServiceProtocol?
    95     weak var delegate: AccountVerificationResultDelegate?
    96 
    97     //Currently we assume imap and smtp servers exist already (update).
    98     // If we run into problems here modify to updateOrCreate
    99     func update(loginName: String, name: String, password: String? = nil, imap: ServerViewModel,
   100                 smtp: ServerViewModel) {
   101         guard let serverImap = account.imapServer,
   102             let serverSmtp = account.smtpServer else {
   103                 Logger.frontendLogger.errorAndCrash("Account misses imap or smtp server.")
   104                 return
   105         }
   106         let pass : String?
   107         if let p = password {
   108             pass = p
   109         } else {
   110             pass = serverImap.credentials.password
   111         }
   112         guard let editedServerImap = server(from: imap, serverType: .imap,
   113                                             loginName: loginName,
   114                                             password: pass,
   115                                             key: serverImap.credentials.key),
   116             let editedServerSmtp = server(from: smtp,
   117                                           serverType: .smtp,
   118                                           loginName: loginName,
   119                                           password: pass,
   120                                           key: serverSmtp.credentials.key)
   121             else {
   122                 Logger.frontendLogger.errorAndCrash("Invalid input.")
   123                 return
   124         }
   125 
   126         serverImap.updateValues(with: editedServerImap)
   127         serverSmtp.updateValues(with: editedServerSmtp)
   128 
   129         self.account.user.userName = name
   130 
   131         guard let ms = messageSyncService else {
   132             Logger.frontendLogger.errorAndCrash("no MessageSyncService")
   133             return
   134         }
   135         ms.requestVerification(account: account, delegate: self)
   136     }
   137 
   138     func sectionIsValid(section: Int) -> Bool {
   139         return section >= 0 && section < headers.count
   140     }
   141 
   142     var count: Int {
   143         get {
   144             return headers.count
   145         }
   146     }
   147 
   148     subscript(section: Int) -> String {
   149         get {
   150             assert(sectionIsValid(section: section), "Section out of range")
   151             return headers[section]
   152         }
   153     }
   154 
   155     private func server(from viewModel:ServerViewModel, serverType:Server.ServerType,
   156                         loginName: String, password: String?, key: String? = nil) -> Server? {
   157         guard let viewModelPort = viewModel.port,
   158             let port = UInt16(viewModelPort),
   159             let address = viewModel.address else {
   160                 Logger.frontendLogger.errorAndCrash("viewModel misses required data.")
   161                 return nil
   162         }
   163         guard let transport = Server.Transport(fromString: viewModel.transport) else {
   164             Log.shared.errorAndCrash(component: #function, errorString: "No transport")
   165             return nil
   166         }
   167 
   168         let credentials = ServerCredentials.create(loginName: loginName, key: key)
   169         if password != nil && password != "" {
   170             credentials.password = password
   171         }
   172 
   173         let server = Server.create(serverType: serverType, port: port, address: address,
   174                                    transport: transport, credentials: credentials)
   175 
   176         return server
   177     }
   178 
   179     func updateToken(accessToken: OAuth2AccessTokenProtocol) {
   180         guard let imapServer = account.imapServer,
   181             let smtpServer = account.smtpServer else {
   182                 return
   183         }
   184         let password = accessToken.persistBase64Encoded()
   185         imapServer.credentials.password = password
   186         smtpServer.credentials.password = password
   187     }
   188 }
   189 
   190 // MARK: - AccountVerificationServiceDelegate
   191 
   192 extension AccountSettingsViewModel: AccountVerificationServiceDelegate {
   193     public func verified(account: Account,
   194                   service: AccountVerificationServiceProtocol,
   195                   result: AccountVerificationResult) {
   196         if result == .ok {
   197             MessageModelUtil.performAndWait {
   198                 account.save()
   199             }
   200         }
   201         GCD.onMainWait { [weak self] in
   202             guard let me = self else {
   203                 Logger.frontendLogger.lostMySelf()
   204                 return
   205             }
   206             me.delegate?.didVerify(result: result, accountInput: nil)
   207         }
   208     }
   209 }