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
4 changes: 3 additions & 1 deletion Mark-In/Sources/App/DIContainer+.swift
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ private extension DIContainer {
)
let withdrawalUseCase: WithdrawalUseCase = WithdrawalUseCaseImpl(
keychainStore: resolve(),
authUserManager: resolve()
authUserManager: resolve(),
linkRepository: resolve(),
folderRepsoitory: resolve()
)

register(fetchLinkListUseCase)
Expand Down
20 changes: 20 additions & 0 deletions Mark-In/Sources/Data/Repositories/FolderRepositoryImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,24 @@ struct FolderRepositoryImpl: FolderRepository {
/// 2. Folder 삭제
try await folderDocRef.delete()
}

func deleteAll(userID: String) async throws {
/// 1. Folders 컬렉션 참조 생성
let path = FirebaseEndpoint.FirestoreDB.folders(userID: userID).path
let folderColRef = db.collection(path)

/// 2. 컬렉션의 모든 문서 가져오기
let snapshot = try await folderColRef.getDocuments()

/// 3. 모든 데이터 병렬 작업으로 삭제
try await withThrowingTaskGroup(of: Void.self) { group in
snapshot.documents.forEach { document in
group.addTask {
try await document.reference.delete()
}
}

try await group.waitForAll()
}
}
}
27 changes: 27 additions & 0 deletions Mark-In/Sources/Data/Repositories/LinkRepositoryImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,33 @@ struct LinkRepositoryImpl: LinkRepository {
/// 3. Link 삭제
try await linkDocRef.delete()
}

func deleteAll(userID: String) async throws {
/// 1. Links 컬렉션 참조 생성
let path = FirebaseEndpoint.FirestoreDB.links(userID: userID).path
let linkColRef = db.collection(path)

/// 2. 컬렉션의 모든 문서 가져오기
let snapshot = try await linkColRef.getDocuments()

/// 3. 병렬 작업으로 데이터 삭제
try await withThrowingTaskGroup(of: Void.self) { group in
/// 모둔 문서에 순차 접근
snapshot.documents.forEach { document in
/// Link 데이터 삭제
group.addTask {
try await document.reference.delete()
}

/// 이미지 데이터 삭제
group.addTask {
try await deleteImageData(userID: userID, fileID: document.documentID)
}
}

try await group.waitForAll()
}
}
}

private extension LinkRepositoryImpl {
Expand Down
1 change: 1 addition & 0 deletions Mark-In/Sources/Domain/Interfaces/FolderRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ protocol FolderRepository {
func fetchAll(userID: String) async throws -> [Folder]
func update(userID: String, folder: Folder) async throws
func delete(userID: String, folder: Folder) async throws
func deleteAll(userID: String) async throws
}
1 change: 1 addition & 0 deletions Mark-In/Sources/Domain/Interfaces/LinkRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ protocol LinkRepository {
func fetchAll(userID: String) async throws -> [WebLink]
func update(userID: String, link: WebLink) async throws
func delete(userID: String, link: WebLink) async throws
func deleteAll(userID: String) async throws
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,40 +15,75 @@ struct WithdrawalUseCaseImpl: WithdrawalUseCase {
private let keychainStore: KeychainStore
private let authUserManager: AuthUserManager

init(keychainStore: KeychainStore, authUserManager: AuthUserManager) {
private let linkRepository: LinkRepository
private let folderRepsoitory: FolderRepository

init(
keychainStore: KeychainStore,
authUserManager: AuthUserManager,
linkRepository: LinkRepository,
folderRepsoitory: FolderRepository
) {
self.keychainStore = keychainStore
self.authUserManager = authUserManager
self.linkRepository = linkRepository
self.folderRepsoitory = folderRepsoitory
}

func execute() async throws {
/// 현재 로그인 된 유저 상태 확인 후 인증 정보 삭제
do {
try await Auth.auth().currentUser?.delete()
} catch {
throw WithdrawalError.credentialTooOld
}

guard let provider = authUserManager.user?.provider else { return }
guard let user = authUserManager.user else { return }

switch provider {
case .apple:
let token: String? = try? keychainStore.load(forKey: .refreshToken)
guard let token else { return }
/// 사용자의 모든 데이터(링크, 폴더) 삭제
try await withThrowingTaskGroup(of: Void.self) { group in
group.addTask {
try await linkRepository.deleteAll(userID: user.id)
}

let url = URL(string: "https://\(Config.value(forKey: .revokeTokenURL))/revokeToken?refresh_token=\(token)"
.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!
group.addTask {
try await folderRepsoitory.deleteAll(userID: user.id)
}

_ = try await URLSession.shared.data(from: url)

try keychainStore.delete(forKey: .refreshToken)
try await group.waitForAll()
}

/// OAuth 인증 해제
switch user.provider {
case .apple:
try await revokeAppleAuthorization()

case .google:
try? await GIDSignIn.sharedInstance.disconnect()
GIDSignIn.sharedInstance.signOut()
try await revokeGoogleAuthorization()

@unknown default:
fatalError("")
fatalError("Do not implement revoke function for provider: \(user.provider)")
}

authUserManager.clear()
}
}

private extension WithdrawalUseCaseImpl {
func revokeAppleAuthorization() async throws {
let token: String? = try? keychainStore.load(forKey: .refreshToken)
guard let token else { return }

let url = URL(string: "https://\(Config.value(forKey: .revokeTokenURL))/revokeToken?refresh_token=\(token)"
.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!

_ = try await URLSession.shared.data(from: url)

try keychainStore.delete(forKey: .refreshToken)
}

func revokeGoogleAuthorization() async throws {
try? await GIDSignIn.sharedInstance.disconnect()
GIDSignIn.sharedInstance.signOut()
}
}
Loading