-
Notifications
You must be signed in to change notification settings - Fork 1
feat: #30 - 회원가입, 로그인 api 연결 #31
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| // | ||
| // AuthRepository.swift | ||
| // Data | ||
| // | ||
| // Created by kimnahun on 2026-02-18. | ||
| // Copyright © 2026 NDGL-iOS. All rights reserved. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| import Domain | ||
| import Networks | ||
|
|
||
| public final class AuthRepository: AuthRepositoryInterface { | ||
| private let service: AuthServiceProtocol | ||
|
|
||
| public init(service: AuthServiceProtocol) { | ||
| self.service = service | ||
| } | ||
|
|
||
| public func signup(info: SignupInfo) async throws -> SignupResult { | ||
| do { | ||
| let request = SignupRequest(fcmToken: info.fcmToken) | ||
| return try await service.signup(request: request).toDomain() | ||
| } catch { | ||
| throw error.toNDGLError() | ||
| } | ||
| } | ||
|
|
||
| public func login(uuid: String) async throws -> LoginResult { | ||
| do { | ||
| let request = LoginRequest(uuid: uuid) | ||
| return try await service.login(request: request).toDomain() | ||
| } catch { | ||
| throw error.toNDGLError() | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| // | ||
| // AuthTransform.swift | ||
| // Data | ||
| // | ||
| // Created by kimnahun on 2026-02-18. | ||
| // Copyright © 2026 NDGL-iOS. All rights reserved. | ||
| // | ||
|
|
||
| import Domain | ||
| import Networks | ||
|
|
||
| extension SignupResponse { | ||
| func toDomain() -> SignupResult { | ||
| SignupResult( | ||
| uuid: uuid, | ||
| accessToken: accessToken, | ||
| nickname: nickname | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| extension LoginResponse { | ||
| func toDomain() -> LoginResult { | ||
| LoginResult( | ||
| uuid: uuid, | ||
| accessToken: accessToken, | ||
| nickname: nickname | ||
| ) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| // | ||
| // LoginResult.swift | ||
| // Domain | ||
| // | ||
| // Created by kimnahun on 2026-02-18. | ||
| // Copyright © 2026 NDGL-iOS. All rights reserved. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| public struct LoginResult: Sendable { | ||
| public let uuid: String | ||
| public let accessToken: String | ||
| public let nickname: String | ||
|
|
||
| public init(uuid: String, accessToken: String, nickname: String) { | ||
| self.uuid = uuid | ||
| self.accessToken = accessToken | ||
| self.nickname = nickname | ||
| } | ||
| } |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,9 @@ | |
| // Copyright © 2026 NDGL-iOS. All rights reserved. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| import Domain | ||
| import RIBs | ||
| import RxSwift | ||
|
|
||
|
|
@@ -35,20 +38,58 @@ final class RootInteractor: PresentableInteractor<RootPresentable>, RootInteract | |
| weak var router: RootRouting? | ||
| weak var listener: RootListener? | ||
|
|
||
| private let authRepository: AuthRepositoryInterface | ||
| private let tokenRepository: TokenRepositoryProtocol | ||
| private let disposeBag = DisposeBag() | ||
|
|
||
| override init(presenter: RootPresentable) { | ||
| init( | ||
| presenter: RootPresentable, | ||
| authRepository: AuthRepositoryInterface, | ||
| tokenRepository: TokenRepositoryProtocol | ||
| ) { | ||
| self.authRepository = authRepository | ||
| self.tokenRepository = tokenRepository | ||
| super.init(presenter: presenter) | ||
| presenter.listener = self | ||
| } | ||
|
|
||
| override func didBecomeActive() { | ||
| super.didBecomeActive() | ||
| performAuthFlow() | ||
| } | ||
|
|
||
| override func willResignActive() { | ||
| super.willResignActive() | ||
| } | ||
|
|
||
| private func performAuthFlow() { | ||
| Task { [weak self] in | ||
| guard let self else { return } | ||
|
|
||
| do { | ||
| if let uuid = self.tokenRepository.get(.uuid) { | ||
| let loginResult = try await self.authRepository.login(uuid: uuid) | ||
| self.tokenRepository.save(loginResult.accessToken, for: .accessToken) | ||
| } else { | ||
| let fcmToken = self.tokenRepository.get(.fcmToken) ?? UUID().uuidString | ||
| let signupResult = try await self.authRepository.signup( | ||
| info: SignupInfo(fcmToken: fcmToken) | ||
| ) | ||
| self.tokenRepository.save(signupResult.uuid, for: .uuid) | ||
| self.tokenRepository.save(signupResult.accessToken, for: .accessToken) | ||
|
|
||
| let loginResult = try await self.authRepository.login(uuid: signupResult.uuid) | ||
| self.tokenRepository.save(loginResult.accessToken, for: .accessToken) | ||
| } | ||
|
|
||
| await MainActor.run { | ||
| self.router?.attachMain() | ||
| } | ||
| } catch { | ||
| print("[RootInteractor] Auth flow failed: \(error)") | ||
| } | ||
| } | ||
| } | ||
|
Comment on lines
+65
to
+92
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
🛡️ Task 저장 및 취소 처리 제안 final class RootInteractor: PresentableInteractor<RootPresentable>, RootInteractable {
weak var router: RootRouting?
weak var listener: RootListener?
private let authRepository: AuthRepositoryInterface
private let tokenRepository: TokenRepositoryProtocol
private let disposeBag = DisposeBag()
+ private var authTask: Task<Void, Never>?
// ...
- override func willResignActive() {
- super.willResignActive()
- }
+ override func willResignActive() {
+ super.willResignActive()
+ authTask?.cancel()
+ authTask = nil
+ }
private func performAuthFlow() {
- Task { [weak self] in
+ authTask = Task { [weak self] in
guard let self else { return }
// ...
}
}
}추가로, Task 내부에서 🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| // MARK: - RootPresentableListener | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| // | ||
| // LoginDTO.swift | ||
| // Networks | ||
| // | ||
| // Created by kimnahun on 2026-02-18. | ||
| // Copyright © 2026 NDGL-iOS. All rights reserved. | ||
| // | ||
|
|
||
| import Foundation | ||
|
|
||
| public struct LoginRequest: Encodable, Sendable { | ||
| public let uuid: String | ||
|
|
||
| public init(uuid: String) { | ||
| self.uuid = uuid | ||
| } | ||
| } | ||
|
|
||
| public struct LoginResponse: Decodable, Sendable { | ||
| public let uuid: String | ||
| public let accessToken: String | ||
| public let nickname: String | ||
| } | ||
|
Comment on lines
+19
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: rg -n "keyDecodingStrategy|convertFromSnakeCase|CodingKeys" --type swift -C 3Repository: YAPP-Github/27th-App-Team-1-iOS Length of output: 57 🏁 Script executed: cat -n "Projects/Modules/Networks/Sources/DTO/Auth/LoginDTO.swift"Repository: YAPP-Github/27th-App-Team-1-iOS Length of output: 680 🏁 Script executed: rg -n "JSONDecoder" --type swift -C 2Repository: YAPP-Github/27th-App-Team-1-iOS Length of output: 2511
현재 코드는 JSON 디코딩 시 다음 중 하나를 선택하세요:
🤖 Prompt for AI Agents |
||
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
인증 실패 시
print만 하고 있어 사용자에게 어떤 피드백도 제공되지 않습니다.PR 목표에서 에러 처리가 미구현이라고 언급되어 있지만, 현재 상태로는 인증 실패 시 앱이 빈 화면에 머물게 됩니다. 최소한 재시도 로직이나 에러 화면 전환을 위한 TODO를 명시해두면 추후 추적에 도움이 됩니다.
} catch { - print("[RootInteractor] Auth flow failed: \(error)") + // TODO: 인증 실패 시 재시도 또는 에러 화면 처리 필요 (추후 구현) + print("[RootInteractor] Auth flow failed: \(error)") }에러 처리 로직(재시도/에러 화면) 구현을 위한 이슈를 생성해 드릴까요?
🤖 Prompt for AI Agents