Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
5 changes: 4 additions & 1 deletion Projects/App/Sources/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {

assembler = Assembler([
KeychainAssembly(),
PresentationAssembly()
PresentationAssembly(),
DataSourceAssembly(),
RepositoryAssembly(),
UseCaseAssembly()
], container: AppDelegate.container)
return true
}
Expand Down
5 changes: 5 additions & 0 deletions Projects/App/Support/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>API_BASE_URL</key>
<string>$(API_BASE_URL)</string>
<key>AppIdentifierPrefix</key>
Expand Down
3 changes: 0 additions & 3 deletions Projects/Core/Sources/JwtStore/JwtStore.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
public enum KeychainType: String {
case accessToken = "ACCESS-TOKEN"
case refreshToken = "REFRESH-TOKEN"
case accessExpiresAt = "ACCESS-EXPIRED-AT"
case refreshExpiresAt = "REFRESH-EXPIRED-AT"
}

public protocol Keychain {
Expand Down
6 changes: 6 additions & 0 deletions Projects/Core/Sources/Steps/EmailLoginStep.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import RxFlow

public enum EmailLoginStep: Step {
case emailLoginisRequired
case tabIsRequired
}
47 changes: 47 additions & 0 deletions Projects/Data/Sources/Auth/DataSource/API/AuthAPI.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import Moya
import Domain
import AppNetwork

enum AuthAPI {
case login(LoginRequestQuery)
case signup(SignupRequestQuery)
}

extension AuthAPI: EmotingAPI {
typealias ErrorType = Error

var domain: EmotingDomain {
.auth
}

var urlPath: String {
switch self {
case .login:
return "/login"
case .signup:
return "/signup"
}
}

var method: Method {
return .post
}

var task: Task {
switch self {
case let .login(req):
return .requestJSONEncodable(req)

case let .signup(req):
return .requestJSONEncodable(req)
}
}

var jwtTokenType: JwtTokenType {
return .none
}

var errorMap: [Int: ErrorType]? {
return nil
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import RxSwift
import Domain
import AppNetwork

protocol RemoteAuthDataSource {
func login(req: LoginRequestQuery) -> Single<TokenDTO>
func signup(req: SignupRequestQuery) -> Completable
}

final class RemoteAuthDataSourceImpl: RemoteBaseDataSource<AuthAPI>, RemoteAuthDataSource {
func login(req: LoginRequestQuery) -> Single<TokenDTO> {
return request(.login(req))
.map(TokenDTO.self)
}

func signup(req: SignupRequestQuery) -> Completable {
return request(.signup(req))
.asCompletable()
}

}
19 changes: 19 additions & 0 deletions Projects/Data/Sources/Auth/Repository/AuthRepositoryImpl.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import RxSwift
import Domain

struct AuthRepositoryImpl: AuthRepository {
private let remoteAuthDataSource: any RemoteAuthDataSource

init(remoteAuthDataSource: any RemoteAuthDataSource) {
self.remoteAuthDataSource = remoteAuthDataSource
}

func login(req: Domain.LoginRequestQuery) -> RxSwift.Completable {
remoteAuthDataSource.login(req: req)
.asCompletable()
}

func signup(req: Domain.SignupRequestQuery) -> RxSwift.Completable {
remoteAuthDataSource.signup(req: req)
}
}
51 changes: 51 additions & 0 deletions Projects/Data/Sources/Base/BaseRemoteDataSource.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import Moya
import Domain
import AppNetwork
import Foundation
import RxSwift
import RxMoya
import Core
import Alamofire

class RemoteBaseDataSource<API: EmotingAPI> {
private let keychain: any Keychain

private let provider: MoyaProvider<API>

init(keychain: any Keychain) {
self.keychain = keychain
#if DEBUG
self.provider = MoyaProvider<API>(plugins: [JwtPlugin(keychain: keychain), MoyaLogginPlugin()])
#else
self.provider = MoyaProvider<API>(plugins: [JwtPlugin(keychain: keychain)])
#endif
}

func request(_ api: API) -> Single<Response> {
return .create { single in
var disposables: [Disposable] = []
disposables.append(
self.defaultRequest(api)
.subscribe(
onSuccess: { single(.success($0)) },
onFailure: { single(.failure($0)) }
)
)
return Disposables.create(disposables)
}
}
}

private extension RemoteBaseDataSource {
func defaultRequest(_ api: API) -> Single<Response> {
return provider.rx
.request(api)
.timeout(.seconds(120), scheduler: MainScheduler.asyncInstance)
.catch { error in
guard let code = (error as? MoyaError)?.response?.statusCode else {
return .error(error)
}
return .error(api.errorMap?[code] ?? error)
}
}
}
18 changes: 18 additions & 0 deletions Projects/Data/Sources/DI/DataSourceAssembly.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Foundation
import Swinject
import Core
import Domain

public final class DataSourceAssembly: Assembly {
public init() {}

private let keychain = { (resolver: Resolver) in
resolver.resolve(Keychain.self)!
}

public func assemble(container: Container) {
container.register(RemoteAuthDataSource.self) { resolver in
RemoteAuthDataSourceImpl(keychain: self.keychain(resolver))
}
}
}
15 changes: 15 additions & 0 deletions Projects/Data/Sources/DI/RepositoryAssembly.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Foundation
import Swinject
import Domain

public final class RepositoryAssembly: Assembly {
public init() {}

// swiftlint:disable function_body_length
public func assemble(container: Container) {
container.register(AuthRepository.self) { resolver in
AuthRepositoryImpl(remoteAuthDataSource: resolver.resolve(RemoteAuthDataSource.self)!)
}
}
// swiftlint:enable function_body_length
}
23 changes: 23 additions & 0 deletions Projects/Data/Sources/DI/UseCaseAssembly.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Foundation
import Swinject
import Domain

public final class UseCaseAssembly: Assembly {
public init() {}

// swiftlint:disable function_body_length
public func assemble(container: Container) {
// Auth
container.register(LoginUseCase.self) { resolver in
LoginUseCase(
authRepository: resolver.resolve(AuthRepository.self)!
)
}
container.register(SignupUseCase.self) { resolver in
SignupUseCase(
authRepository: resolver.resolve(AuthRepository.self)!
)
}
}
// swiftlint:enable function_body_length
}
1 change: 0 additions & 1 deletion Projects/Data/Sources/TempFile.swift

This file was deleted.

11 changes: 11 additions & 0 deletions Projects/Domain/Sources/Auth/Parameter/LoginRequestQuery.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Foundation

public struct LoginRequestQuery: Encodable {
public let email: String
public let password: String

public init(email: String, password: String) {
self.email = email
self.password = password
}
}
15 changes: 15 additions & 0 deletions Projects/Domain/Sources/Auth/Parameter/SignupRequestQuery.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Foundation

public struct SignupRequestQuery: Encodable {
public let email: String
public let password: String
public let nickname: String
public let age: Int

public init(email: String, password: String, nickname: String, age: Int) {
self.email = email
self.password = password
self.nickname = nickname
self.age = age
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import RxSwift

public protocol AuthRepository {
func login(req: LoginRequestQuery) -> Completable
func signup(req: SignupRequestQuery) -> Completable
}
13 changes: 13 additions & 0 deletions Projects/Domain/Sources/Auth/UseCase/LoginUseCase.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import RxSwift

public struct LoginUseCase {
public init(authRepository: AuthRepository) {
self.authRepository = authRepository
}

private let authRepository: AuthRepository

public func execute(req: LoginRequestQuery) -> Completable {
return authRepository.login(req: req)
}
}
13 changes: 13 additions & 0 deletions Projects/Domain/Sources/Auth/UseCase/SignupUseCase.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import RxSwift

public struct SignupUseCase {
public init(authRepository: AuthRepository) {
self.authRepository = authRepository
}

private let authRepository: AuthRepository

public func execute(req: SignupRequestQuery) -> Completable {
return authRepository.signup(req: req)
}
}
1 change: 0 additions & 1 deletion Projects/Domain/Sources/TempFile.swift

This file was deleted.

4 changes: 2 additions & 2 deletions Projects/Flow/Sources/AgeSignupFlow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ private extension AgeSignupFlow {
}

return .one(flowContributor: .contribute(
withNextPresentable: rootViewController,
withNextStepper: rootViewController.reactor
withNextPresentable: profilSignupFlow,
withNextStepper: OneStepper(withSingleStep: ProfilSignupStep.profilSignupIsRequired)
))
}
}
2 changes: 1 addition & 1 deletion Projects/Flow/Sources/AppStepper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ public final class AppStepper: Stepper {
public init() {}

public var initialStep: Step {
return AppStep.testIsRequired
return AppStep.onboardingIsRequired
}
}
40 changes: 40 additions & 0 deletions Projects/Flow/Sources/EmailLoginFlow.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import UIKit
import RxFlow
import RxSwift
import Core
import Swinject
import Presentation

public final class EmailLoginFlow: Flow {
public let container: Container
public var root: Presentable {
return self.rootViewController
}

public let rootViewController: EmailLoginViewController

public init(container: Container) {
self.container = container
self.rootViewController = container.resolve(EmailLoginViewController.self)!
}

public func navigate(to step: Step) -> FlowContributors {
guard let step = step as? EmailLoginStep else { return .none }

switch step {
case .emailLoginisRequired:
return navigationToEmailLogin()
case .tabIsRequired:
return .end(forwardToParentFlowWithStep: OauthLoginStep.tabIsRequired)
}
}
}

private extension EmailLoginFlow {
func navigationToEmailLogin() -> FlowContributors {
return .one(flowContributor: .contribute(
withNextPresentable: rootViewController,
withNextStepper: rootViewController.reactor
))
}
}
15 changes: 7 additions & 8 deletions Projects/Flow/Sources/OauthLoginFlow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public final class OauthLoginFlow: Flow {
case .emailSignupIsRequired:
return navigationToEmailSignup()
case .tabIsRequired:
return .end(forwardToParentFlowWithStep: OnboardingStep.tabIsRequired)
return .end(forwardToParentFlowWithStep: AppStep.tabIsRequired)
}
}
}
Expand All @@ -50,16 +50,15 @@ private extension OauthLoginFlow {
}

func navigationToEmailLogin() -> FlowContributors {
let emailLoginViewController = container.resolve(EmailLoginViewController.self)!
let emailLoginFlow = EmailLoginFlow(container: container)

self.rootViewController.pushViewController(
emailLoginViewController,
animated: true
)
Flows.use(emailLoginFlow, when: .created) { (root) in
self.rootViewController.pushViewController(root, animated: true)
}

return .one(flowContributor: .contribute(
withNextPresentable: emailLoginViewController,
withNextStepper: emailLoginViewController.reactor
withNextPresentable: emailLoginFlow,
withNextStepper: OneStepper(withSingleStep: EmailLoginStep.emailLoginisRequired)
))
}

Expand Down
Loading