Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
18 changes: 18 additions & 0 deletions DevLog/App/Assembler/DataAssembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,24 @@ final class DataAssembler: Assembler {
AuthSessionRepositoryImpl(authService: container.resolve(AuthService.self))
}

container.register(AuthDataRepository.self) {
AuthDataRepositoryImpl(
authService: container.resolve(AuthService.self),
appleAuthService: container.resolve(
AuthenticationService.self,
name: "AppleAuthenticationService"
),
githubAuthService: container.resolve(
AuthenticationService.self,
name: "GithubAuthenticationService"
),
googleAuthService: container.resolve(
AuthenticationService.self,
name: "GoogleAuthenticationService"
)
)
}

container.register(UserDataRepository.self) {
UserDataRepositoryImpl(userService: container.resolve(UserService.self))
}
Expand Down
12 changes: 12 additions & 0 deletions DevLog/App/Assembler/DomainAssembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,17 @@ final class DomainAssembler: Assembler {
container.register(FetchPushNotificationsUseCase.self) {
FetchPushNotificationsUseCaseImpl(container.resolve(PushNotificationRepository.self))
}

container.register(FetchAuthProvidersUseCase.self) {
FetchAuthProvidersUseCaseImpl(container.resolve(AuthDataRepository.self))
}

container.register(LinkAuthProviderUseCase.self) {
LinkAuthProviderUseCaseImpl(container.resolve(AuthDataRepository.self))
}

container.register(UnlinkAuthProviderUseCase.self) {
UnlinkAuthProviderUseCaseImpl(container.resolve(AuthDataRepository.self))
}
}
}
2 changes: 2 additions & 0 deletions DevLog/Data/Common/Error+.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import Foundation

enum AuthError: Error {
case notAuthenticated
case failedToUnlinkLastProvider
case unsupportedProvider
}

enum FirestoreError: Error, LocalizedError {
Expand Down
82 changes: 82 additions & 0 deletions DevLog/Data/Repository/AuthDataRepositoryImpl.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//
// AuthDataRepositoryImpl.swift
// DevLog
//
// Created by 최윤진 on 2/12/26.
//

import FirebaseAuth

final class AuthDataRepositoryImpl: AuthDataRepository {
private let authService: AuthService
private let appleAuthService: AuthenticationService
private let githubAuthService: AuthenticationService
private let googleAuthService: AuthenticationService

init(
authService: AuthService,
appleAuthService: AuthenticationService,
githubAuthService: AuthenticationService,
googleAuthService: AuthenticationService
) {
self.authService = authService
self.appleAuthService = appleAuthService
self.githubAuthService = githubAuthService
self.googleAuthService = googleAuthService
}

func fetchCurrentProvider() async throws -> AuthProvider? {
guard let providerString = try await authService.getProviderID() else {
return nil
}
return AuthProvider(rawValue: providerString)
}

func fetchAllProviders() async throws -> [AuthProvider] {
let providerStrings = authService.providerIDs ?? []
return providerStrings.compactMap { AuthProvider(rawValue: $0) }
}

func linkProvider(_ provider: AuthProvider) async throws {
guard let uid = authService.uid,
let user = Auth.auth().currentUser,
let email = user.email else {
throw AuthError.notAuthenticated
}

let service: AuthenticationService
switch provider {
case .apple:
service = appleAuthService
case .google:
service = googleAuthService
case .github:
service = githubAuthService
}

try await service.link(uid: uid, email: email)
}

func unlinkProvider(_ provider: AuthProvider) async throws {
guard let uid = authService.uid,
let user = Auth.auth().currentUser else {
throw AuthError.notAuthenticated
}

if user.providerData.count <= 1 {
throw AuthError.failedToUnlinkLastProvider
}

let service: AuthenticationService
switch provider {
case .apple:
service = appleAuthService
case .google:
service = googleAuthService
case .github:
service = githubAuthService
}

try await service.unlink(uid)
}
}
14 changes: 13 additions & 1 deletion DevLog/Domain/Protocol/AuthDataRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,16 @@
// Created by 최윤진 on 1/5/26.
//

import Foundation
protocol AuthDataRepository {
/// 현재 로그인한 프로바이더를 가져옵니다
func fetchCurrentProvider() async throws -> AuthProvider?

/// 연결된 모든 프로바이더 목록을 가져옵니다
func fetchAllProviders() async throws -> [AuthProvider]

/// 특정 프로바이더를 계정에 연결합니다
func linkProvider(_ provider: AuthProvider) async throws

/// 특정 프로바이더를 계정에서 해제합니다
func unlinkProvider(_ provider: AuthProvider) async throws
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//
// FetchAuthProvidersUseCase.swift
// DevLog
//
// Created by 최윤진 on 2/12/26.
//

protocol FetchAuthProvidersUseCase {
func execute() async throws -> (currentProvider: AuthProvider?, allProviders: [AuthProvider])
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// FetchAuthProvidersUseCaseImpl.swift
// DevLog
//
// Created by 최윤진 on 2/12/26.
//

final class FetchAuthProvidersUseCaseImpl: FetchAuthProvidersUseCase {
private let repository: AuthDataRepository

init(_ repository: AuthDataRepository) {
self.repository = repository
}

func execute() async throws -> (currentProvider: AuthProvider?, allProviders: [AuthProvider]) {
async let currentProvider = try await repository.fetchCurrentProvider()
async let allProviders = try await repository.fetchAllProviders()

return try await (currentProvider, allProviders)
}
}
10 changes: 10 additions & 0 deletions DevLog/Domain/UseCase/Auth/Provider/LinkAuthProviderUseCase.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//
// LinkAuthProviderUseCase.swift
// DevLog
//
// Created by 최윤진 on 2/12/26.
//

protocol LinkAuthProviderUseCase {
func execute(_ provider: AuthProvider) async throws
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// LinkAuthProviderUseCaseImpl.swift
// DevLog
//
// Created by 최윤진 on 2/12/26.
//

final class LinkAuthProviderUseCaseImpl: LinkAuthProviderUseCase {
private let repository: AuthDataRepository

init(_ repository: AuthDataRepository) {
self.repository = repository
}

func execute(_ provider: AuthProvider) async throws {
try await repository.linkProvider(provider)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//
// UnlinkAuthProviderUseCase.swift
// DevLog
//
// Created by 최윤진 on 2/12/26.
//

protocol UnlinkAuthProviderUseCase {
func execute(_ provider: AuthProvider) async throws
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// UnlinkAuthProviderUseCaseImpl.swift
// DevLog
//
// Created by 최윤진 on 2/12/26.
//

final class UnlinkAuthProviderUseCaseImpl: UnlinkAuthProviderUseCase {
private let repository: AuthDataRepository

init(_ repository: AuthDataRepository) {
self.repository = repository
}

func execute(_ provider: AuthProvider) async throws {
try await repository.unlinkProvider(provider)
}
}
Loading