diff --git a/CoreDataStack/Entity/Subscription.swift b/CoreDataStack/Entity/Subscription.swift index 6cb1902a1..e1824be1c 100644 --- a/CoreDataStack/Entity/Subscription.swift +++ b/CoreDataStack/Entity/Subscription.swift @@ -80,4 +80,8 @@ extension Subscription { return NSPredicate(format: "%K == %@", #keyPath(Subscription.policyRaw), policyRaw) } + public static func predicate(userToken: String) -> NSPredicate { + return NSPredicate(format: "%K == %@", #keyPath(Subscription.userToken), userToken) + } + } diff --git a/Mastodon/Service/NotificationService.swift b/Mastodon/Service/NotificationService.swift index 75a5953ed..e21a3cff8 100644 --- a/Mastodon/Service/NotificationService.swift +++ b/Mastodon/Service/NotificationService.swift @@ -100,8 +100,56 @@ extension NotificationService { return _notificationSubscription } - func handlePushNotification(notificationID: Mastodon.Entity.Notification.ID) { + func handle(mastodonPushNotification: MastodonPushNotification) { hasUnreadPushNotification.value = true + + // Subscription maybe failed to cancel when sign-out + // Try cancel again if receive that kind push notification + guard let managedObjectContext = authenticationService?.managedObjectContext else { return } + guard let apiService = apiService else { return } + + managedObjectContext.perform { + let subscriptionRequest = NotificationSubscription.sortedFetchRequest + subscriptionRequest.predicate = NotificationSubscription.predicate(userToken: mastodonPushNotification.accessToken) + let subscriptions = managedObjectContext.safeFetch(subscriptionRequest) + + // note: assert setting remove after cancel subscription + guard let subscription = subscriptions.first else { return } + guard let setting = subscription.setting else { return } + let domain = setting.domain + let userID = setting.userID + + let authenticationRequest = MastodonAuthentication.sortedFetchRequest + authenticationRequest.predicate = MastodonAuthentication.predicate(domain: domain, userID: userID) + let authentication = managedObjectContext.safeFetch(authenticationRequest).first + + guard authentication == nil else { + // do nothing if still sign-in + return + } + + // cancel subscription if sign-out + let accessToken = mastodonPushNotification.accessToken + let mastodonAuthenticationBox = AuthenticationService.MastodonAuthenticationBox( + domain: domain, + userID: userID, + appAuthorization: .init(accessToken: accessToken), + userAuthorization: .init(accessToken: accessToken) + ) + apiService + .cancelSubscription(mastodonAuthenticationBox: mastodonAuthenticationBox) + .sink { completion in + switch completion { + case .failure(let error): + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: [Push Notification] failed to cancel sign-out user subscription: %s", ((#file as NSString).lastPathComponent), #line, #function, error.localizedDescription) + case .finished: + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: [Push Notification] cancel sign-out user subscription", ((#file as NSString).lastPathComponent), #line, #function) + } + } receiveValue: { _ in + // do nothing + } + .store(in: &self.disposeBag) + } } } diff --git a/Mastodon/Supporting Files/AppDelegate.swift b/Mastodon/Supporting Files/AppDelegate.swift index 73a13bed1..6c49638da 100644 --- a/Mastodon/Supporting Files/AppDelegate.swift +++ b/Mastodon/Supporting Files/AppDelegate.swift @@ -76,7 +76,7 @@ extension AppDelegate: UNUserNotificationCenterDelegate { let notificationID = String(mastodonPushNotification.notificationID) os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: [Push Notification] notification %s", ((#file as NSString).lastPathComponent), #line, #function, notificationID) - appContext.notificationService.handlePushNotification(notificationID: notificationID) + appContext.notificationService.handle(mastodonPushNotification: mastodonPushNotification) completionHandler([.sound]) } @@ -95,7 +95,7 @@ extension AppDelegate: UNUserNotificationCenterDelegate { let notificationID = String(mastodonPushNotification.notificationID) os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: [Push Notification] notification %s", ((#file as NSString).lastPathComponent), #line, #function, notificationID) - appContext.notificationService.handlePushNotification(notificationID: notificationID) + appContext.notificationService.handle(mastodonPushNotification: mastodonPushNotification) appContext.notificationService.requestRevealNotificationPublisher.send(notificationID) completionHandler() }