Skip to content

Commit

Permalink
Add back in KMM.
Browse files Browse the repository at this point in the history
Start hooking up login use cases
  • Loading branch information
martyu committed Oct 26, 2023
1 parent 42891ac commit ee6a441
Show file tree
Hide file tree
Showing 29 changed files with 579 additions and 427 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Foundation
import shared

public extension Error {
var kmmException: KMMException? { (self as NSError).kotlinException as? KMMException }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Foundation

public extension NotificationCenter {
func publisher(for name: String) -> Publisher {
publisher(for: Notification.Name(name), object: nil)
}
}
38 changes: 19 additions & 19 deletions iosApp/Modules/DI/ModuleLinker/Protocols/Data.swift
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import Foundation
import Models

public protocol UserManaging: ObservableObject {
var currentUser: User? { get }

func deleteUser() async throws
func createUser(nickname: String, email: String, password: String, passwordConfirmation: String, verificationCode: String) async throws
func resetPassword(email: String, password: String, confirmPassword: String, authCode: String) async throws
func fetchCurrentUser() async throws
func updateUserInfo(firstName: String?, lastName: String?, currentPassword: String?, newPassword: String?, confirmNewPassword: String?) async throws
}

public enum UserRepoError: LocalizedError {
case accountExists
case twoFAFailed
case dataUnavailable
case displayError(String)
}
//import Foundation
//import Models
//
//public protocol UserManaging: ObservableObject {
// var currentUser: User? { get }
//
// func deleteUser() async throws
// func createUser(nickname: String, email: String, password: String, passwordConfirmation: String, verificationCode: String) async throws
// func resetPassword(email: String, password: String, confirmPassword: String, authCode: String) async throws
// func fetchCurrentUser() async throws
// func updateUserInfo(firstName: String?, lastName: String?, currentPassword: String?, newPassword: String?, confirmNewPassword: String?) async throws
//}
//
//public enum UserRepoError: LocalizedError {
// case accountExists
// case twoFAFailed
// case dataUnavailable
// case displayError(String)
//}
3 changes: 0 additions & 3 deletions iosApp/Modules/Data/DataModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ public final class DataModule: ModuleProtocol {
public static let shared = DataModule()

public func registerAllServices() {
Resolver.register {
UserRepo.shared as any UserManaging
}
}
}

Expand Down
137 changes: 67 additions & 70 deletions iosApp/Modules/Data/Login/LoginRepo.swift
Original file line number Diff line number Diff line change
@@ -1,70 +1,67 @@
import Foundation
import API
import KeychainSwift
import FacebookLogin
import GoogleSignIn
import AuthenticationServices

enum LoginError: Error {
case facebookAccessTokenMissing
}

public class LoginRepo: ObservableObject {
//TODO: update this with user info
@Published public var userIsLoggedIn: Bool = false
private let api: LoginAPI

private var appleSignInID: String?

//TODO: make actor
// public static let shared = LoginRepo()

private init(api: LoginAPI = LoginAPI()) {
self.api = api
api.$userIsLoggedIn.assign(to: &$userIsLoggedIn)
}

public func loginWithFacebook(result: LoginManagerLoginResult) async throws {
do {
guard let token = result.token?.tokenString else {
throw LoginError.facebookAccessTokenMissing
}
try await api.login(method: .facebook(accessToken: token))
} catch {
Task { @MainActor in
FacebookLogin.LoginManager().logOut()
}
throw error
}
}

public func loginWithGoogle(result: GIDSignInResult) async throws {
let token = result.user.accessToken.tokenString
try await api.login(method: .google(accessToken: token))
}

public func login(email: String, password: String) async throws {
try await api.login(method: .email(email: email, password: password))
}

public func logOut() {
api.logOut()
FacebookLogin.LoginManager().logOut()
GIDSignIn.sharedInstance.signOut()
signOutOfApple()
UserRepo.shared.currentUser = nil
}

public func requestEmailVerificationCode(for email: String) async throws {
try await api.requestEmailVerificationCode(for: email)
}

public func loginWithApple(result: ASAuthorization) async throws {
let token = String(data: (result.credential as! ASAuthorizationAppleIDCredential).identityToken!, encoding: .utf8)!
try await api.login(method: .apple(idToken: token))
}

private func signOutOfApple() {
//TODO:
}
}
//import Foundation
//import API
//import KeychainSwift
//import FacebookLogin
//import GoogleSignIn
//import AuthenticationServices
//
//enum LoginError: Error {
// case facebookAccessTokenMissing
//}
//
//public class LoginRepo: ObservableObject {
// //TODO: update this with user info
// @Published public var userIsLoggedIn: Bool = false
// private let api: LoginAPI
//
// private var appleSignInID: String?
//
// private init(api: LoginAPI = LoginAPI()) {
// self.api = api
// api.$userIsLoggedIn.assign(to: &$userIsLoggedIn)
// }
//
// public func loginWithFacebook(result: LoginManagerLoginResult) async throws {
// do {
// guard let token = result.token?.tokenString else {
// throw LoginError.facebookAccessTokenMissing
// }
// try await api.login(method: .facebook(accessToken: token))
// } catch {
// Task { @MainActor in
// FacebookLogin.LoginManager().logOut()
// }
// throw error
// }
// }
//
// public func loginWithGoogle(result: GIDSignInResult) async throws {
// let token = result.user.accessToken.tokenString
// try await api.login(method: .google(accessToken: token))
// }
//
// public func login(email: String, password: String) async throws {
// try await api.login(method: .email(email: email, password: password))
// }
//
// public func logOut() {
// api.logOut()
// FacebookLogin.LoginManager().logOut()
// GIDSignIn.sharedInstance.signOut()
// signOutOfApple()
// UserRepo.shared.currentUser = nil
// }
//
// public func requestEmailVerificationCode(for email: String) async throws {
// try await api.requestEmailVerificationCode(for: email)
// }
//
// public func loginWithApple(result: ASAuthorization) async throws {
// let token = String(data: (result.credential as! ASAuthorizationAppleIDCredential).identityToken!, encoding: .utf8)!
// try await api.login(method: .apple(idToken: token))
// }
//
// private func signOutOfApple() {
// //TODO:
// }
//}
172 changes: 86 additions & 86 deletions iosApp/Modules/Data/User/UserRepo.swift
Original file line number Diff line number Diff line change
@@ -1,86 +1,86 @@
import Foundation
import API
import Models
import ModuleLinker
import Resolver

class UserRepo: UserManaging, ObservableObject {
private let api = UserAPI()
@Injected private var loginRepo: LoginRepo

@Published public var currentUser: User?

//TODO: make actor
public static let shared = UserRepo()

private init() {}

public func deleteUser() async throws {
do {
try await api.delete()
} catch {
try handleError(error)
}
loginRepo.logOut()
}

public func createUser(nickname: String, email: String, password: String, passwordConfirmation: String, verificationCode: String) async throws {
do {
try await api.create(nickname: nickname, email: email, password: password, passwordConfirmation: passwordConfirmation, verificationCode: verificationCode)
} catch {
try handleError(error)
}
}

public func resetPassword(email: String, password: String, confirmPassword: String, authCode: String) async throws {
do {
try await api.resetPassword(email: email, password: password, confirmPassword: confirmPassword, authCode: authCode)
} catch {
try handleError(error)
}
}

public func fetchCurrentUser() async throws {
do {
currentUser = try await api.getCurrentUser()
} catch {
try handleError(error)
}
}

public func updateUserInfo(firstName: String?, lastName: String?, currentPassword: String?, newPassword: String?, confirmNewPassword: String?) async throws {
let updatedUser = try UpdatedUser(
firstName: firstName?.nilIfEmpty,
lastName: lastName?.nilIfEmpty,
newPassword: newPassword?.nilIfEmpty,
confirmPassword: confirmNewPassword?.nilIfEmpty,
currentPassword: currentPassword?.nilIfEmpty
)
do {
try await api.update(user: updatedUser)
try await fetchCurrentUser()
} catch {
try handleError(error)
}
}

private func handleError(_ error: Error) throws {
if let error = error as? UserAPI.Error {
switch error {
case .accountExists:
throw UserRepoError.accountExists
case .twoFAFailed:
throw UserRepoError.twoFAFailed
case .unprocessableEntity(let cause):
throw UserRepoError.displayError(cause)
}
} else if let error = error as? APIError {
switch error {
case .invalidResponse:
throw UserRepoError.dataUnavailable
case .httpError(_, let cause):
throw UserRepoError.displayError(cause ?? "An unknown error occurred.")
}
}
}
}
//import Foundation
//import API
//import Models
//import ModuleLinker
//import Resolver
//
//class UserRepo: UserManaging, ObservableObject {
// private let api = UserAPI()
// @Injected private var loginRepo: LoginRepo
//
// @Published public var currentUser: User?
//
// //TODO: make actor
// public static let shared = UserRepo()
//
// private init() {}
//
// public func deleteUser() async throws {
// do {
// try await api.delete()
// } catch {
// try handleError(error)
// }
// loginRepo.logOut()
// }
//
// public func createUser(nickname: String, email: String, password: String, passwordConfirmation: String, verificationCode: String) async throws {
// do {
// try await api.create(nickname: nickname, email: email, password: password, passwordConfirmation: passwordConfirmation, verificationCode: verificationCode)
// } catch {
// try handleError(error)
// }
// }
//
// public func resetPassword(email: String, password: String, confirmPassword: String, authCode: String) async throws {
// do {
// try await api.resetPassword(email: email, password: password, confirmPassword: confirmPassword, authCode: authCode)
// } catch {
// try handleError(error)
// }
// }
//
// public func fetchCurrentUser() async throws {
// do {
// currentUser = try await api.getCurrentUser()
// } catch {
// try handleError(error)
// }
// }
//
// public func updateUserInfo(firstName: String?, lastName: String?, currentPassword: String?, newPassword: String?, confirmNewPassword: String?) async throws {
// let updatedUser = try UpdatedUser(
// firstName: firstName?.nilIfEmpty,
// lastName: lastName?.nilIfEmpty,
// newPassword: newPassword?.nilIfEmpty,
// confirmPassword: confirmNewPassword?.nilIfEmpty,
// currentPassword: currentPassword?.nilIfEmpty
// )
// do {
// try await api.update(user: updatedUser)
// try await fetchCurrentUser()
// } catch {
// try handleError(error)
// }
// }
//
// private func handleError(_ error: Error) throws {
// if let error = error as? UserAPI.Error {
// switch error {
// case .accountExists:
// throw UserRepoError.accountExists
// case .twoFAFailed:
// throw UserRepoError.twoFAFailed
// case .unprocessableEntity(let cause):
// throw UserRepoError.displayError(cause)
// }
// } else if let error = error as? APIError {
// switch error {
// case .invalidResponse:
// throw UserRepoError.dataUnavailable
// case .httpError(_, let cause):
// throw UserRepoError.displayError(cause ?? "An unknown error occurred.")
// }
// }
// }
//}
4 changes: 0 additions & 4 deletions iosApp/Modules/Screens/Home/HomeModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ extension HomeModule {
mockResolver.register {
MockHomeViewUIModelProvider(actionHandler: $0.resolve()) as HomeViewUIModelProviding
}

mockResolver.register {
MockUserRepo() as any UserManaging
}
}
}
#endif
Loading

0 comments on commit ee6a441

Please sign in to comment.