Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
8 changes: 8 additions & 0 deletions DevLog/App/Assembler/DomainAssembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ private extension DomainAssembler {
DeletePushNotificationUseCaseImpl(container.resolve(PushNotificationRepository.self))
}

container.register(UndoDeletePushNotificationUseCase.self) {
UndoDeletePushNotificationUseCaseImpl(container.resolve(PushNotificationRepository.self))
}

container.register(FetchPushNotificationsUseCase.self) {
FetchPushNotificationsUseCaseImpl(container.resolve(PushNotificationRepository.self))
}
Expand All @@ -116,6 +120,10 @@ private extension DomainAssembler {
container.register(DeleteWebPageUseCase.self) {
DeleteWebPageUseCaseImpl(container.resolve(WebPageRepository.self))
}

container.register(UndoDeleteWebPageUseCase.self) {
UndoDeleteWebPageUseCaseImpl(container.resolve(WebPageRepository.self))
}
}

func registerUserPreferencesUseCases(_ container: DIContainer) {
Expand Down
4 changes: 4 additions & 0 deletions DevLog/Data/Repository/PushNotificationRepositoryImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ final class PushNotificationRepositoryImpl: PushNotificationRepository {
try await service.deleteNotification(notificationID)
}

func undoDeleteNotification(_ notificationID: String) async throws {
try await service.undoDeleteNotification(notificationID)
}

// 푸시 알림 읽음/안읽음 토글
func toggleNotificationRead(_ todoId: String) async throws {
try await service.toggleNotificationRead(todoId)
Expand Down
4 changes: 4 additions & 0 deletions DevLog/Data/Repository/WebPageRepositoryImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ final class WebPageRepositoryImpl: WebPageRepository {
try await webPageService.deleteWebPage(urlString)
await metadataService.removeCachedImage(for: urlString)
}

func undoDelete(_ urlString: String) async throws {
try await webPageService.undoDeleteWebPage(urlString)
}
}

private extension WebPageRepositoryImpl {
Expand Down
1 change: 1 addition & 0 deletions DevLog/Domain/Protocol/PushNotificationRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ protocol PushNotificationRepository {
limit: Int
) throws -> AnyPublisher<PushNotificationPage, Error>
func deleteNotification(_ notificationID: String) async throws
func undoDeleteNotification(_ notificationID: String) async throws
func toggleNotificationRead(_ todoId: String) async throws
}
1 change: 1 addition & 0 deletions DevLog/Domain/Protocol/WebPageRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ protocol WebPageRepository {
func fetch(_ query: String) async throws -> [WebPage]
func upsert(_ urlString: String) async throws
func delete(_ urlString: String) async throws
func undoDelete(_ urlString: String) async throws
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//
// UndoDeletePushNotificationUseCase.swift
// DevLog
//
// Created by opfic on 3/16/26.
//

protocol UndoDeletePushNotificationUseCase {
func execute(_ notificationID: String) async throws
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// UndoDeletePushNotificationUseCaseImpl.swift
// DevLog
//
// Created by opfic on 3/16/26.
//

final class UndoDeletePushNotificationUseCaseImpl: UndoDeletePushNotificationUseCase {
private let repository: PushNotificationRepository

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

func execute(_ notificationID: String) async throws {
try await repository.undoDeleteNotification(notificationID)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//
// UndoDeleteWebPageUseCase.swift
// DevLog
//
// Created by opfic on 3/16/26.
//

protocol UndoDeleteWebPageUseCase {
func execute(_ urlString: String) async throws
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// UndoDeleteWebPageUseCaseImpl.swift
// DevLog
//
// Created by opfic on 3/16/26.
//

final class UndoDeleteWebPageUseCaseImpl: UndoDeleteWebPageUseCase {
private let repository: WebPageRepository

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

func execute(_ urlString: String) async throws {
try await repository.undoDelete(urlString)
}
}
26 changes: 22 additions & 4 deletions DevLog/Infra/Service/PushNotificationService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,16 @@
import FirebaseAuth
import Combine
import FirebaseFirestore
import FirebaseFunctions

final class PushNotificationService {
private enum FunctionName: String {
case requestPushNotificationDeletion
case undoPushNotificationDeletion
}

private let store = Firestore.firestore()
private let functions = Functions.functions(region: "asia-northeast3")
private let logger = Logger(category: "PushNotificationService")

/// 푸시 알림 On/Off 설정
Expand Down Expand Up @@ -174,13 +181,24 @@ final class PushNotificationService {
/// 푸시 알림 기록 삭제
func deleteNotification(_ notificationID: String) async throws {
do {
guard let uid = Auth.auth().currentUser?.uid else { throw AuthError.notAuthenticated }
guard Auth.auth().currentUser?.uid != nil else { throw AuthError.notAuthenticated }

let docRef = store.collection("users/\(uid)/notifications").document(notificationID)
let function = functions.httpsCallable(FunctionName.requestPushNotificationDeletion)
_ = try await function.call(["notificationId": notificationID])
} catch {
logger.error("Failed to request notification deletion", error: error)
throw error
}
}

func undoDeleteNotification(_ notificationID: String) async throws {
do {
guard Auth.auth().currentUser?.uid != nil else { throw AuthError.notAuthenticated }

try await docRef.delete()
let function = functions.httpsCallable(FunctionName.undoPushNotificationDeletion)
_ = try await function.call(["notificationId": notificationID])
} catch {
logger.error("Failed to delete notification", error: error)
logger.error("Failed to undo notification deletion", error: error)
throw error
}
}
Expand Down
43 changes: 35 additions & 8 deletions DevLog/Infra/Service/WebPageService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,16 @@

import FirebaseAuth
import FirebaseFirestore
import FirebaseFunctions

final class WebPageService {
private enum FunctionName: String {
case requestWebPageDeletion
case undoWebPageDeletion
}

private let store = Firestore.firestore()
private let functions = Functions.functions(region: "asia-northeast3")
private let encoder = Firestore.Encoder()
private let logger = Logger(category: "WebPageService")

Expand Down Expand Up @@ -67,21 +74,37 @@ final class WebPageService {
}

func deleteWebPage(_ urlString: String) async throws {
logger.info("Deleting web page: \(urlString)")
logger.info("Requesting web page deletion: \(urlString)")

guard let uid = Auth.auth().currentUser?.uid else {
guard Auth.auth().currentUser?.uid != nil else {
logger.error("User not authenticated")
throw AuthError.notAuthenticated
}

do {
let function = functions.httpsCallable(FunctionName.requestWebPageDeletion)
_ = try await function.call(["urlString": urlString])
logger.info("Successfully requested web page deletion")
} catch {
logger.error("Failed to request web page deletion", error: error)
throw error
}
}

func undoDeleteWebPage(_ urlString: String) async throws {
logger.info("Undoing web page deletion: \(urlString)")

guard Auth.auth().currentUser?.uid != nil else {
logger.error("User not authenticated")
throw AuthError.notAuthenticated
}

do {
let documentID = documentID(for: urlString)
let docRef = store
.document("users/\(uid)/webPages/\(documentID)")
try await docRef.delete()
logger.info("Successfully deleted web page")
let function = functions.httpsCallable(FunctionName.undoWebPageDeletion)
_ = try await function.call(["urlString": urlString])
logger.info("Successfully undone web page deletion")
} catch {
logger.error("Failed to delete web page", error: error)
logger.error("Failed to undo web page deletion", error: error)
throw error
}
}
Expand All @@ -101,6 +124,9 @@ final class WebPageService {
private extension WebPageService {
func makeResponse(from snapshot: QueryDocumentSnapshot) -> WebPageResponse? {
let data = snapshot.data()
if data[WebPageFieldKey.deletingAt.rawValue] is Timestamp {
return nil
}
guard
let title = data[WebPageFieldKey.title.rawValue] as? String,
let url = data[WebPageFieldKey.url.rawValue] as? String,
Expand All @@ -123,5 +149,6 @@ private extension WebPageService {
case url
case displayURL
case imageURL
case deletingAt // 삭제 요청은 되었지만, 5초 유예 후 최종 삭제되기 전 상태
}
}
Loading