From 578936486f1d0a1ea456c983f8e84e0119aeae4e Mon Sep 17 00:00:00 2001 From: kean Date: Thu, 3 Apr 2025 08:56:24 -0400 Subject: [PATCH 1/6] Rewrite removeDefaultWordPressComAccount in Swift --- .../Services/AccountService+Swift.swift | 44 +++++++++++++ WordPress/Classes/Services/AccountService.h | 19 ------ WordPress/Classes/Services/AccountService.m | 66 +------------------ 3 files changed, 46 insertions(+), 83 deletions(-) diff --git a/WordPress/Classes/Services/AccountService+Swift.swift b/WordPress/Classes/Services/AccountService+Swift.swift index f0a0dba44eb8..f12a3b0027f6 100644 --- a/WordPress/Classes/Services/AccountService+Swift.swift +++ b/WordPress/Classes/Services/AccountService+Swift.swift @@ -1,8 +1,52 @@ import Foundation import WordPressShared import ShareExtensionCore +import WebKit extension AccountService { + + @objc public static let defaultDotcomAccountUUIDDefaultsKey = "AccountDefaultDotcomUUID" + + func removeDefaultWordPressComAccount() { + wpAssert(Thread.isMainThread, "This method should only be called from the main thread") + + PushNotificationsManager.shared.unregisterDeviceToken() + + guard let account = try? WPAccount.lookupDefaultWordPressComAccount(in: coreDataStack.mainContext) else { + return + } + + let objectID = TaggedManagedObjectID(account) + coreDataStack.performAndSave { context in + do { + let account = try context.existingObject(with: objectID) + context.delete(account) + } catch { + wpAssertionFailure("account missing") + } + } + + // Clear WordPress.com cookies + let cookieJars: [CookieJar] = [ + HTTPCookieStorage.shared, + WKWebsiteDataStore.default().httpCookieStore + ] + + for cookieJar in cookieJars { + cookieJar.removeWordPressComCookies(completion: {}) + } + + URLCache.shared.removeAllCachedResponses() + + // Remove defaults + UserPersistentStoreFactory.instance().removeObject(forKey: AccountService.defaultDotcomAccountUUIDDefaultsKey) + + WPAnalytics.refreshMetadata() + NotificationCenter.default.post(name: .WPAccountDefaultWordPressComAccountChanged, object: nil) + + StatsCache.clearCaches() + } + func setupAppExtensions() { let context = coreDataStack.mainContext context.performAndWait { diff --git a/WordPress/Classes/Services/AccountService.h b/WordPress/Classes/Services/AccountService.h index e924f05794ca..db32f386b4f2 100644 --- a/WordPress/Classes/Services/AccountService.h +++ b/WordPress/Classes/Services/AccountService.h @@ -31,14 +31,6 @@ extern NSNotificationName const WPAccountEmailAndDefaultBlogUpdatedNotification; */ - (void)setDefaultWordPressComAccount:(WPAccount *)account; -/** - Removes the default WordPress.com account. Should only be called from the Main Thread - - @see defaultWordPressComAccount - @see setDefaultWordPressComAccount: - */ -- (void)removeDefaultWordPressComAccount; - /** Query to check if an email address is paired to a wpcom account. Used in the magic links signup flow. @@ -49,17 +41,6 @@ extern NSNotificationName const WPAccountEmailAndDefaultBlogUpdatedNotification; */ - (void)isEmailAvailable:(NSString *)email success:(void (^)(BOOL available))success failure:(void (^)(NSError *error))failure; -/** - Query to check if a username is available. Used in the signup flow. - - @param email - @param success - @param failure - */ -- (void)isUsernameAvailable:(NSString *)username - success:(void (^)(BOOL available))success - failure:(void (^)(NSError *error))failure; - /** Requests a verification email to be sent to the email address associated with the current account. diff --git a/WordPress/Classes/Services/AccountService.m b/WordPress/Classes/Services/AccountService.m index f6ecc98abfda..42bd23dd43ba 100644 --- a/WordPress/Classes/Services/AccountService.m +++ b/WordPress/Classes/Services/AccountService.m @@ -13,9 +13,6 @@ #import "WordPress-Swift.h" #endif -static NSString * const DefaultDotcomAccountUUIDDefaultsKey = @"AccountDefaultDotcomUUID"; -static NSString * const DefaultDotcomAccountPasswordRemovedKey = @"DefaultDotcomAccountPasswordRemovedKey"; - static NSString * const WordPressDotcomXMLRPCKey = @"https://wordpress.com/xmlrpc.php"; NSNotificationName const WPAccountDefaultWordPressComAccountChangedNotification = @"WPAccountDefaultWordPressComAccountChangedNotification"; NSString * const WPAccountEmailAndDefaultBlogUpdatedNotification = @"WPAccountEmailAndDefaultBlogUpdatedNotification"; @@ -51,7 +48,7 @@ - (void)setDefaultWordPressComAccount:(WPAccount *)account return; } - [[UserPersistentStoreFactory userDefaultsInstance] setObject:account.uuid forKey:DefaultDotcomAccountUUIDDefaultsKey]; + [[UserPersistentStoreFactory userDefaultsInstance] setObject:account.uuid forKey:AccountService.defaultDotcomAccountUUIDDefaultsKey]; NSManagedObjectID *accountID = account.objectID; void (^notifyAccountChange)(void) = ^{ @@ -71,49 +68,6 @@ - (void)setDefaultWordPressComAccount:(WPAccount *)account } } -/** - Removes the default WordPress.com account - - @see defaultWordPressComAccount - @see setDefaultWordPressComAccount: - */ -- (void)removeDefaultWordPressComAccount -{ - NSAssert([NSThread isMainThread], @"This method should only be called from the main thread"); - - [[PushNotificationsManager shared] unregisterDeviceToken]; - - WPAccount *account = [WPAccount lookupDefaultWordPressComAccountInContext:self.coreDataStack.mainContext]; - if (account == nil) { - return; - } - - [self.coreDataStack performAndSaveUsingBlock:^(NSManagedObjectContext *context) { - WPAccount *accountInContext = [context existingObjectWithID:account.objectID error:nil]; - [context deleteObject:accountInContext]; - }]; - - // Clear WordPress.com cookies - NSArray> *cookieJars = @[ - (id)[NSHTTPCookieStorage sharedHTTPCookieStorage], - (id)[[WKWebsiteDataStore defaultDataStore] httpCookieStore] - ]; - - for (id cookieJar in cookieJars) { - [cookieJar removeWordPressComCookiesWithCompletion:^{}]; - } - - [[NSURLCache sharedURLCache] removeAllCachedResponses]; - - // Remove defaults - [[UserPersistentStoreFactory userDefaultsInstance] removeObjectForKey:DefaultDotcomAccountUUIDDefaultsKey]; - - [WPAnalytics refreshMetadata]; - [[NSNotificationCenter defaultCenter] postNotificationName:WPAccountDefaultWordPressComAccountChangedNotification object:nil]; - - [StatsCache clearCaches]; -} - - (void)isEmailAvailable:(NSString *)email success:(void (^)(BOOL available))success failure:(void (^)(NSError *error))failure { id remote = [self remoteForAnonymous]; @@ -128,22 +82,6 @@ - (void)isEmailAvailable:(NSString *)email success:(void (^)(BOOL available))suc }]; } -- (void)isUsernameAvailable:(NSString *)username - success:(void (^)(BOOL available))success - failure:(void (^)(NSError *error))failure -{ - id remote = [self remoteForAnonymous]; - [remote isUsernameAvailable:username success:^(BOOL available) { - if (success) { - success(available); - } - } failure:^(NSError *error) { - if (failure) { - failure(error); - } - }]; -} - - (void)requestVerificationEmail:(void (^)(void))success failure:(void (^)(NSError * _Nonnull))failure { NSAssert([NSThread isMainThread], @"This method should only be called from the main thread"); @@ -267,7 +205,7 @@ - (void)restoreDisassociatedAccountIfNecessary // Assume we have a good candidate account and make it the default account in the app. // Note that this should be the account with the most blogs. // Updates user defaults here vs the setter method to avoid potential side-effects from dispatched notifications. - [[UserPersistentStoreFactory userDefaultsInstance] setObject:account.uuid forKey:DefaultDotcomAccountUUIDDefaultsKey]; + [[UserPersistentStoreFactory userDefaultsInstance] setObject:account.uuid forKey:AccountService.defaultDotcomAccountUUIDDefaultsKey]; } } From 09147c1461c702d522b477360d5ccc8de15274e9 Mon Sep 17 00:00:00 2001 From: kean Date: Thu, 3 Apr 2025 09:01:14 -0400 Subject: [PATCH 2/6] Rewrite setDefaultWordPressComAccount in Swift --- .../Services/AccountService+Swift.swift | 33 ++++++++++++++- WordPress/Classes/Services/AccountService.h | 9 ----- WordPress/Classes/Services/AccountService.m | 40 ------------------- 3 files changed, 31 insertions(+), 51 deletions(-) diff --git a/WordPress/Classes/Services/AccountService+Swift.swift b/WordPress/Classes/Services/AccountService+Swift.swift index f12a3b0027f6..33b6f728f6eb 100644 --- a/WordPress/Classes/Services/AccountService+Swift.swift +++ b/WordPress/Classes/Services/AccountService+Swift.swift @@ -4,8 +4,33 @@ import ShareExtensionCore import WebKit extension AccountService { + func setDefaultWordPressComAccount(_ account: WPAccount) { + wpAssert(account.authToken?.isEmpty == false, "Account should have an authToken for WP.com") - @objc public static let defaultDotcomAccountUUIDDefaultsKey = "AccountDefaultDotcomUUID" + guard account.isDefaultWordPressComAccount else { + return + } + + UserPersistentStoreFactory.instance().set(account.uuid, forKey: Constants.defaultDotcomAccountUUIDDefaultsKey) + + let objectID = TaggedManagedObjectID(account) + let notifyAccountChange = { + let context = self.coreDataStack.mainContext + let account = try? context.existingObject(with: objectID) + NotificationCenter.default.post(name: .WPAccountDefaultWordPressComAccountChanged, object: account) + + PushNotificationsManager.shared.setupRemoteNotifications() + } + + if Thread.isMainThread { + // This is meant to help with testing account observers. + // Short version: dispatch_async and XCTest asynchronous helpers don't play nice with each other + // Long version: see the comment in https://github.com/wordpress-mobile/WordPress-iOS/blob/2f9a2100ca69d8f455acec47a1bbd6cbc5084546/WordPress/WordPressTest/AccountServiceRxTests.swift#L7 + notifyAccountChange() + } else { + DispatchQueue.main.async(execute: notifyAccountChange) + } + } func removeDefaultWordPressComAccount() { wpAssert(Thread.isMainThread, "This method should only be called from the main thread") @@ -39,7 +64,7 @@ extension AccountService { URLCache.shared.removeAllCachedResponses() // Remove defaults - UserPersistentStoreFactory.instance().removeObject(forKey: AccountService.defaultDotcomAccountUUIDDefaultsKey) + UserPersistentStoreFactory.instance().removeObject(forKey: Constants.defaultDotcomAccountUUIDDefaultsKey) WPAnalytics.refreshMetadata() NotificationCenter.default.post(name: .WPAccountDefaultWordPressComAccountChanged, object: nil) @@ -120,3 +145,7 @@ extension AccountService { } } + +private enum Constants { + static let defaultDotcomAccountUUIDDefaultsKey = "AccountDefaultDotcomUUID" +} diff --git a/WordPress/Classes/Services/AccountService.h b/WordPress/Classes/Services/AccountService.h index db32f386b4f2..7d511162587b 100644 --- a/WordPress/Classes/Services/AccountService.h +++ b/WordPress/Classes/Services/AccountService.h @@ -22,15 +22,6 @@ extern NSNotificationName const WPAccountEmailAndDefaultBlogUpdatedNotification; /// @name Default WordPress.com account ///------------------------------------ -/** - Sets the default WordPress.com account - - @param account the account to set as default for WordPress.com - @see defaultWordPressComAccount - @see removeDefaultWordPressComAccount - */ -- (void)setDefaultWordPressComAccount:(WPAccount *)account; - /** Query to check if an email address is paired to a wpcom account. Used in the magic links signup flow. diff --git a/WordPress/Classes/Services/AccountService.m b/WordPress/Classes/Services/AccountService.m index 42bd23dd43ba..14d1db73653e 100644 --- a/WordPress/Classes/Services/AccountService.m +++ b/WordPress/Classes/Services/AccountService.m @@ -28,46 +28,6 @@ - (instancetype)initWithCoreDataStack:(id)coreDataStack return self; } -///------------------------------------ -/// @name Default WordPress.com account -///------------------------------------ - -/** - Sets the default WordPress.com account - - @param account the account to set as default for WordPress.com - @see defaultWordPressComAccount - @see removeDefaultWordPressComAccount - */ -- (void)setDefaultWordPressComAccount:(WPAccount *)account -{ - NSParameterAssert(account != nil); - NSAssert(account.authToken.length > 0, @"Account should have an authToken for WP.com"); - - if ([account isDefaultWordPressComAccount]) { - return; - } - - [[UserPersistentStoreFactory userDefaultsInstance] setObject:account.uuid forKey:AccountService.defaultDotcomAccountUUIDDefaultsKey]; - - NSManagedObjectID *accountID = account.objectID; - void (^notifyAccountChange)(void) = ^{ - NSManagedObjectContext *mainContext = self.coreDataStack.mainContext; - NSManagedObject *accountInContext = [mainContext existingObjectWithID:accountID error:nil]; - [[NSNotificationCenter defaultCenter] postNotificationName:WPAccountDefaultWordPressComAccountChangedNotification object:accountInContext]; - - [[PushNotificationsManager shared] setupRemoteNotifications]; - }; - if ([NSThread isMainThread]) { - // This is meant to help with testing account observers. - // Short version: dispatch_async and XCTest asynchronous helpers don't play nice with each other - // Long version: see the comment in https://github.com/wordpress-mobile/WordPress-iOS/blob/2f9a2100ca69d8f455acec47a1bbd6cbc5084546/WordPress/WordPressTest/AccountServiceRxTests.swift#L7 - notifyAccountChange(); - } else { - dispatch_async(dispatch_get_main_queue(), notifyAccountChange); - } -} - - (void)isEmailAvailable:(NSString *)email success:(void (^)(BOOL available))success failure:(void (^)(NSError *error))failure { id remote = [self remoteForAnonymous]; From f8931e99b88246c18d12e613941929de14544bf3 Mon Sep 17 00:00:00 2001 From: kean Date: Thu, 3 Apr 2025 09:08:27 -0400 Subject: [PATCH 3/6] Rewrite restoreDisassociatedAccountIfNecessary in Swift --- .../Services/AccountService+Swift.swift | 26 +++++++++++++++++-- WordPress/Classes/Services/AccountService.h | 8 ++---- WordPress/Classes/Services/AccountService.m | 18 ------------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/WordPress/Classes/Services/AccountService+Swift.swift b/WordPress/Classes/Services/AccountService+Swift.swift index 33b6f728f6eb..72ee8d703cd9 100644 --- a/WordPress/Classes/Services/AccountService+Swift.swift +++ b/WordPress/Classes/Services/AccountService+Swift.swift @@ -4,7 +4,9 @@ import ShareExtensionCore import WebKit extension AccountService { - func setDefaultWordPressComAccount(_ account: WPAccount) { + // MARK: - Current Account + + @objc public func setDefaultWordPressComAccount(_ account: WPAccount) { wpAssert(account.authToken?.isEmpty == false, "Account should have an authToken for WP.com") guard account.isDefaultWordPressComAccount else { @@ -33,7 +35,7 @@ extension AccountService { } func removeDefaultWordPressComAccount() { - wpAssert(Thread.isMainThread, "This method should only be called from the main thread") + wpAssert(Thread.isMainThread, "Must be called from main thread") PushNotificationsManager.shared.unregisterDeviceToken() @@ -72,6 +74,26 @@ extension AccountService { StatsCache.clearCaches() } + func restoreDisassociatedAccountIfNecessary() { + wpAssert(Thread.isMainThread, "Must be called from main thread") + + let context = coreDataStack.mainContext + guard try? WPAccount.lookupDefaultWordPressComAccount(in: context) == nil { + return + } + + // Attempt to restore a default account that has somehow been disassociated. + if let accounts = try? WPAccount.lookupAllAccounts(in: context), + let account = findDefaultAccountCandidate(from: accounts) { + // Assume we have a good candidate account and make it the default account in the app. + // Note that this should be the account with the most blogs. + // Updates user defaults here vs the setter method to avoid potential side-effects from dispatched notifications. + UserPersistentStoreFactory.instance().set(account.uuid, forKey: Constants.defaultDotcomAccountUUIDDefaultsKey) + } + } + + // MARK: - App Extensions + func setupAppExtensions() { let context = coreDataStack.mainContext context.performAndWait { diff --git a/WordPress/Classes/Services/AccountService.h b/WordPress/Classes/Services/AccountService.h index 7d511162587b..299e96b743e1 100644 --- a/WordPress/Classes/Services/AccountService.h +++ b/WordPress/Classes/Services/AccountService.h @@ -94,12 +94,8 @@ extern NSNotificationName const WPAccountEmailAndDefaultBlogUpdatedNotification; */ - (void)purgeAccountIfUnused:(WPAccount *)account; -/** - Restores a disassociated default WordPress.com account if the current defaultWordPressCom account is nil - and another candidate account is found. This method bypasses the normal setter to avoid triggering unintended - side-effects from dispatching account changed notifications. - */ -- (void)restoreDisassociatedAccountIfNecessary; +// FIXME: rewrite in Swift +- (WPAccount *)findDefaultAccountCandidateFromAccounts:(NSArray *)allAccounts; @end diff --git a/WordPress/Classes/Services/AccountService.m b/WordPress/Classes/Services/AccountService.m index 14d1db73653e..2f3403dfe7ab 100644 --- a/WordPress/Classes/Services/AccountService.m +++ b/WordPress/Classes/Services/AccountService.m @@ -151,24 +151,6 @@ - (BOOL)accountHasOnlyJetpackBlogs:(WPAccount *)account return YES; } -- (void)restoreDisassociatedAccountIfNecessary -{ - NSAssert([NSThread isMainThread], @"This method should only be called from the main thread"); - - if([WPAccount lookupDefaultWordPressComAccountInContext:self.coreDataStack.mainContext] != nil) { - return; - } - - // Attempt to restore a default account that has somehow been disassociated. - WPAccount *account = [self findDefaultAccountCandidateFromAccounts:[WPAccount lookupAllAccountsInContext:self.coreDataStack.mainContext]]; - if (account) { - // Assume we have a good candidate account and make it the default account in the app. - // Note that this should be the account with the most blogs. - // Updates user defaults here vs the setter method to avoid potential side-effects from dispatched notifications. - [[UserPersistentStoreFactory userDefaultsInstance] setObject:account.uuid forKey:AccountService.defaultDotcomAccountUUIDDefaultsKey]; - } -} - - (WPAccount *)findDefaultAccountCandidateFromAccounts:(NSArray *)allAccounts { NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"blogs.@count" ascending:NO]; From a733921ff273ef7e38818e189a55d05dea240044 Mon Sep 17 00:00:00 2001 From: kean Date: Thu, 3 Apr 2025 09:09:46 -0400 Subject: [PATCH 4/6] Remove unused notifications --- WordPress/Classes/Services/AccountService+Swift.swift | 4 ++-- WordPress/Classes/Services/AccountService.h | 2 +- WordPress/Classes/Services/AccountService.m | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/WordPress/Classes/Services/AccountService+Swift.swift b/WordPress/Classes/Services/AccountService+Swift.swift index 72ee8d703cd9..1e9727744e68 100644 --- a/WordPress/Classes/Services/AccountService+Swift.swift +++ b/WordPress/Classes/Services/AccountService+Swift.swift @@ -78,13 +78,13 @@ extension AccountService { wpAssert(Thread.isMainThread, "Must be called from main thread") let context = coreDataStack.mainContext - guard try? WPAccount.lookupDefaultWordPressComAccount(in: context) == nil { + guard (try? WPAccount.lookupDefaultWordPressComAccount(in: context)) == nil else { return } // Attempt to restore a default account that has somehow been disassociated. if let accounts = try? WPAccount.lookupAllAccounts(in: context), - let account = findDefaultAccountCandidate(from: accounts) { + let account = findDefaultAccountCandidate(fromAccounts: accounts) { // Assume we have a good candidate account and make it the default account in the app. // Note that this should be the account with the most blogs. // Updates user defaults here vs the setter method to avoid potential side-effects from dispatched notifications. diff --git a/WordPress/Classes/Services/AccountService.h b/WordPress/Classes/Services/AccountService.h index 299e96b743e1..b3f780e0d19e 100644 --- a/WordPress/Classes/Services/AccountService.h +++ b/WordPress/Classes/Services/AccountService.h @@ -95,7 +95,7 @@ extern NSNotificationName const WPAccountEmailAndDefaultBlogUpdatedNotification; - (void)purgeAccountIfUnused:(WPAccount *)account; // FIXME: rewrite in Swift -- (WPAccount *)findDefaultAccountCandidateFromAccounts:(NSArray *)allAccounts; +- (WPAccount * _Nullable)findDefaultAccountCandidateFromAccounts:(NSArray *)allAccounts; @end diff --git a/WordPress/Classes/Services/AccountService.m b/WordPress/Classes/Services/AccountService.m index 2f3403dfe7ab..14a949708395 100644 --- a/WordPress/Classes/Services/AccountService.m +++ b/WordPress/Classes/Services/AccountService.m @@ -13,7 +13,6 @@ #import "WordPress-Swift.h" #endif -static NSString * const WordPressDotcomXMLRPCKey = @"https://wordpress.com/xmlrpc.php"; NSNotificationName const WPAccountDefaultWordPressComAccountChangedNotification = @"WPAccountDefaultWordPressComAccountChangedNotification"; NSString * const WPAccountEmailAndDefaultBlogUpdatedNotification = @"WPAccountEmailAndDefaultBlogUpdatedNotification"; From 846ebcdeb25268415e45f90126c5e39c2a886bf6 Mon Sep 17 00:00:00 2001 From: kean Date: Thu, 3 Apr 2025 09:25:26 -0400 Subject: [PATCH 5/6] Fix typo --- WordPress/Classes/Services/AccountService+Swift.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WordPress/Classes/Services/AccountService+Swift.swift b/WordPress/Classes/Services/AccountService+Swift.swift index 1e9727744e68..9d92f728171d 100644 --- a/WordPress/Classes/Services/AccountService+Swift.swift +++ b/WordPress/Classes/Services/AccountService+Swift.swift @@ -9,7 +9,7 @@ extension AccountService { @objc public func setDefaultWordPressComAccount(_ account: WPAccount) { wpAssert(account.authToken?.isEmpty == false, "Account should have an authToken for WP.com") - guard account.isDefaultWordPressComAccount else { + guard !account.isDefaultWordPressComAccount else { return } From 96dedd40c7e58957941516af306745847ab5819b Mon Sep 17 00:00:00 2001 From: kean Date: Thu, 3 Apr 2025 09:26:50 -0400 Subject: [PATCH 6/6] Revert restoreDisassociatedAccountIfNecessary change --- .../Services/AccountService+Swift.swift | 28 +++---------------- WordPress/Classes/Services/AccountService.h | 8 ++++-- WordPress/Classes/Services/AccountService.m | 18 ++++++++++++ 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/WordPress/Classes/Services/AccountService+Swift.swift b/WordPress/Classes/Services/AccountService+Swift.swift index 9d92f728171d..ec5fbd1fd265 100644 --- a/WordPress/Classes/Services/AccountService+Swift.swift +++ b/WordPress/Classes/Services/AccountService+Swift.swift @@ -6,6 +6,8 @@ import WebKit extension AccountService { // MARK: - Current Account + @objc public static let defaultDotcomAccountUUIDDefaultsKey = "AccountDefaultDotcomUUID" + @objc public func setDefaultWordPressComAccount(_ account: WPAccount) { wpAssert(account.authToken?.isEmpty == false, "Account should have an authToken for WP.com") @@ -13,7 +15,7 @@ extension AccountService { return } - UserPersistentStoreFactory.instance().set(account.uuid, forKey: Constants.defaultDotcomAccountUUIDDefaultsKey) + UserPersistentStoreFactory.instance().set(account.uuid, forKey: AccountService.defaultDotcomAccountUUIDDefaultsKey) let objectID = TaggedManagedObjectID(account) let notifyAccountChange = { @@ -66,7 +68,7 @@ extension AccountService { URLCache.shared.removeAllCachedResponses() // Remove defaults - UserPersistentStoreFactory.instance().removeObject(forKey: Constants.defaultDotcomAccountUUIDDefaultsKey) + UserPersistentStoreFactory.instance().removeObject(forKey: AccountService.defaultDotcomAccountUUIDDefaultsKey) WPAnalytics.refreshMetadata() NotificationCenter.default.post(name: .WPAccountDefaultWordPressComAccountChanged, object: nil) @@ -74,24 +76,6 @@ extension AccountService { StatsCache.clearCaches() } - func restoreDisassociatedAccountIfNecessary() { - wpAssert(Thread.isMainThread, "Must be called from main thread") - - let context = coreDataStack.mainContext - guard (try? WPAccount.lookupDefaultWordPressComAccount(in: context)) == nil else { - return - } - - // Attempt to restore a default account that has somehow been disassociated. - if let accounts = try? WPAccount.lookupAllAccounts(in: context), - let account = findDefaultAccountCandidate(fromAccounts: accounts) { - // Assume we have a good candidate account and make it the default account in the app. - // Note that this should be the account with the most blogs. - // Updates user defaults here vs the setter method to avoid potential side-effects from dispatched notifications. - UserPersistentStoreFactory.instance().set(account.uuid, forKey: Constants.defaultDotcomAccountUUIDDefaultsKey) - } - } - // MARK: - App Extensions func setupAppExtensions() { @@ -167,7 +151,3 @@ extension AccountService { } } - -private enum Constants { - static let defaultDotcomAccountUUIDDefaultsKey = "AccountDefaultDotcomUUID" -} diff --git a/WordPress/Classes/Services/AccountService.h b/WordPress/Classes/Services/AccountService.h index b3f780e0d19e..7d511162587b 100644 --- a/WordPress/Classes/Services/AccountService.h +++ b/WordPress/Classes/Services/AccountService.h @@ -94,8 +94,12 @@ extern NSNotificationName const WPAccountEmailAndDefaultBlogUpdatedNotification; */ - (void)purgeAccountIfUnused:(WPAccount *)account; -// FIXME: rewrite in Swift -- (WPAccount * _Nullable)findDefaultAccountCandidateFromAccounts:(NSArray *)allAccounts; +/** + Restores a disassociated default WordPress.com account if the current defaultWordPressCom account is nil + and another candidate account is found. This method bypasses the normal setter to avoid triggering unintended + side-effects from dispatching account changed notifications. + */ +- (void)restoreDisassociatedAccountIfNecessary; @end diff --git a/WordPress/Classes/Services/AccountService.m b/WordPress/Classes/Services/AccountService.m index 14a949708395..6da0a6c63036 100644 --- a/WordPress/Classes/Services/AccountService.m +++ b/WordPress/Classes/Services/AccountService.m @@ -150,6 +150,24 @@ - (BOOL)accountHasOnlyJetpackBlogs:(WPAccount *)account return YES; } +- (void)restoreDisassociatedAccountIfNecessary +{ + NSAssert([NSThread isMainThread], @"This method should only be called from the main thread"); + + if([WPAccount lookupDefaultWordPressComAccountInContext:self.coreDataStack.mainContext] != nil) { + return; + } + + // Attempt to restore a default account that has somehow been disassociated. + WPAccount *account = [self findDefaultAccountCandidateFromAccounts:[WPAccount lookupAllAccountsInContext:self.coreDataStack.mainContext]]; + if (account) { + // Assume we have a good candidate account and make it the default account in the app. + // Note that this should be the account with the most blogs. + // Updates user defaults here vs the setter method to avoid potential side-effects from dispatched notifications. + [[UserPersistentStoreFactory userDefaultsInstance] setObject:account.uuid forKey:AccountService.defaultDotcomAccountUUIDDefaultsKey]; + } +} + - (WPAccount *)findDefaultAccountCandidateFromAccounts:(NSArray *)allAccounts { NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"blogs.@count" ascending:NO];