diff --git a/WordPress/Classes/Services/AccountService+Swift.swift b/WordPress/Classes/Services/AccountService+Swift.swift index f0a0dba44eb8..ec5fbd1fd265 100644 --- a/WordPress/Classes/Services/AccountService+Swift.swift +++ b/WordPress/Classes/Services/AccountService+Swift.swift @@ -1,8 +1,83 @@ import Foundation import WordPressShared import ShareExtensionCore +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") + + guard !account.isDefaultWordPressComAccount else { + return + } + + UserPersistentStoreFactory.instance().set(account.uuid, forKey: AccountService.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, "Must be called from 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() + } + + // 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 e924f05794ca..7d511162587b 100644 --- a/WordPress/Classes/Services/AccountService.h +++ b/WordPress/Classes/Services/AccountService.h @@ -22,23 +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; - -/** - 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 +32,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..6da0a6c63036 100644 --- a/WordPress/Classes/Services/AccountService.m +++ b/WordPress/Classes/Services/AccountService.m @@ -13,10 +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"; @@ -31,89 +27,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: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); - } -} - -/** - 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 +41,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 +164,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]; } }