diff --git a/Frameworks/Account/Account.xcodeproj/project.pbxproj b/Frameworks/Account/Account.xcodeproj/project.pbxproj index c26f84411..c41172a75 100644 --- a/Frameworks/Account/Account.xcodeproj/project.pbxproj +++ b/Frameworks/Account/Account.xcodeproj/project.pbxproj @@ -118,12 +118,11 @@ 9E489E8D2360652C004372EE /* FeedlyGetStreamIdsOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E489E8C2360652C004372EE /* FeedlyGetStreamIdsOperationTests.swift */; }; 9E489E912360ED30004372EE /* FeedlyOrganiseParsedItemsByFeedOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E489E902360ED30004372EE /* FeedlyOrganiseParsedItemsByFeedOperationTests.swift */; }; 9E489E93236101FC004372EE /* FeedlyUpdateAccountFeedsWithItemsOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E489E92236101FC004372EE /* FeedlyUpdateAccountFeedsWithItemsOperationTests.swift */; }; - 9E510D6E234F16A8002E6F1A /* FeedlyAddFeedRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E510D6D234F16A8002E6F1A /* FeedlyAddFeedRequest.swift */; }; 9E5ABE9A236BE6BD00B5DE9F /* feedly-1-initial in Resources */ = {isa = PBXBuildFile; fileRef = 9E5ABE99236BE6BC00B5DE9F /* feedly-1-initial */; }; 9E672394236F7CA0000BE141 /* FeedlyRefreshAccessTokenOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E672393236F7CA0000BE141 /* FeedlyRefreshAccessTokenOperation.swift */; }; 9E672396236F7E68000BE141 /* OAuthAcessTokenRefreshing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E672395236F7E68000BE141 /* OAuthAcessTokenRefreshing.swift */; }; 9E713653233AD63E00765C84 /* FeedlySetUnreadArticlesOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E713652233AD63E00765C84 /* FeedlySetUnreadArticlesOperation.swift */; }; - 9E7299D723505E9600DAEFB7 /* FeedlyAddFeedOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7299D623505E9600DAEFB7 /* FeedlyAddFeedOperation.swift */; }; + 9E7299D723505E9600DAEFB7 /* FeedlyAddFeedToCollectionOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7299D623505E9600DAEFB7 /* FeedlyAddFeedToCollectionOperation.swift */; }; 9E7299D9235062A200DAEFB7 /* FeedlyResourceProviding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E7299D8235062A200DAEFB7 /* FeedlyResourceProviding.swift */; }; 9E784EBE237E890600099B1B /* FeedlyLogoutOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E784EBD237E890600099B1B /* FeedlyLogoutOperation.swift */; }; 9E784EC0237E8BE100099B1B /* FeedlyLogoutOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E784EBF237E8BE100099B1B /* FeedlyLogoutOperationTests.swift */; }; @@ -139,12 +138,14 @@ 9E964EB823754AC400A7AF2E /* OAuthAuthorizationClient+Feedly.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E964E9E23754AC400A7AF2E /* OAuthAuthorizationClient+Feedly.swift */; }; 9E964EBA23754B4000A7AF2E /* OAuthAccountAuthorizationOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E964EB923754B4000A7AF2E /* OAuthAccountAuthorizationOperation.swift */; }; 9EA3133B231E368100268BA0 /* FeedlyAccountDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EA3133A231E368100268BA0 /* FeedlyAccountDelegate.swift */; }; + 9EA643CF2391D3560018A28C /* FeedlyAddExistingFeedOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EA643CE2391D3550018A28C /* FeedlyAddExistingFeedOperation.swift */; }; 9EAEC60C2332FE830085D7C9 /* FeedlyCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAEC60B2332FE830085D7C9 /* FeedlyCollection.swift */; }; 9EAEC60E2332FEC20085D7C9 /* FeedlyFeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAEC60D2332FEC20085D7C9 /* FeedlyFeed.swift */; }; 9EAEC624233315F60085D7C9 /* FeedlyEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAEC623233315F60085D7C9 /* FeedlyEntry.swift */; }; 9EAEC626233318400085D7C9 /* FeedlyStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAEC625233318400085D7C9 /* FeedlyStream.swift */; }; 9EAEC62823331C350085D7C9 /* FeedlyCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAEC62723331C350085D7C9 /* FeedlyCategory.swift */; }; 9EAEC62A23331EE70085D7C9 /* FeedlyOrigin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAEC62923331EE70085D7C9 /* FeedlyOrigin.swift */; }; + 9EB1D576238E6A3900A753D7 /* FeedlyAddNewFeedOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB1D575238E6A3900A753D7 /* FeedlyAddNewFeedOperation.swift */; }; 9EC228552362C17F00766EF8 /* FeedlySetStarredArticlesOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EC228542362C17F00766EF8 /* FeedlySetStarredArticlesOperationTests.swift */; }; 9EC228572362C7F900766EF8 /* FeedlyCheckpointOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EC228562362C7F900766EF8 /* FeedlyCheckpointOperationTests.swift */; }; 9EC228592362D0EA00766EF8 /* FeedlySendArticleStatusesOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EC228582362D0EA00766EF8 /* FeedlySendArticleStatusesOperationTests.swift */; }; @@ -336,12 +337,11 @@ 9E489E8C2360652C004372EE /* FeedlyGetStreamIdsOperationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyGetStreamIdsOperationTests.swift; sourceTree = ""; }; 9E489E902360ED30004372EE /* FeedlyOrganiseParsedItemsByFeedOperationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyOrganiseParsedItemsByFeedOperationTests.swift; sourceTree = ""; }; 9E489E92236101FC004372EE /* FeedlyUpdateAccountFeedsWithItemsOperationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyUpdateAccountFeedsWithItemsOperationTests.swift; sourceTree = ""; }; - 9E510D6D234F16A8002E6F1A /* FeedlyAddFeedRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyAddFeedRequest.swift; sourceTree = ""; }; 9E5ABE99236BE6BC00B5DE9F /* feedly-1-initial */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "feedly-1-initial"; sourceTree = ""; }; 9E672393236F7CA0000BE141 /* FeedlyRefreshAccessTokenOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyRefreshAccessTokenOperation.swift; sourceTree = ""; }; 9E672395236F7E68000BE141 /* OAuthAcessTokenRefreshing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OAuthAcessTokenRefreshing.swift; sourceTree = ""; }; 9E713652233AD63E00765C84 /* FeedlySetUnreadArticlesOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlySetUnreadArticlesOperation.swift; sourceTree = ""; }; - 9E7299D623505E9600DAEFB7 /* FeedlyAddFeedOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyAddFeedOperation.swift; sourceTree = ""; }; + 9E7299D623505E9600DAEFB7 /* FeedlyAddFeedToCollectionOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyAddFeedToCollectionOperation.swift; sourceTree = ""; }; 9E7299D8235062A200DAEFB7 /* FeedlyResourceProviding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyResourceProviding.swift; sourceTree = ""; }; 9E784EBD237E890600099B1B /* FeedlyLogoutOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyLogoutOperation.swift; sourceTree = ""; }; 9E784EBF237E8BE100099B1B /* FeedlyLogoutOperationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyLogoutOperationTests.swift; sourceTree = ""; }; @@ -357,12 +357,14 @@ 9E964E9E23754AC400A7AF2E /* OAuthAuthorizationClient+Feedly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OAuthAuthorizationClient+Feedly.swift"; sourceTree = ""; }; 9E964EB923754B4000A7AF2E /* OAuthAccountAuthorizationOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OAuthAccountAuthorizationOperation.swift; sourceTree = ""; }; 9EA3133A231E368100268BA0 /* FeedlyAccountDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedlyAccountDelegate.swift; sourceTree = ""; }; + 9EA643CE2391D3550018A28C /* FeedlyAddExistingFeedOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedlyAddExistingFeedOperation.swift; sourceTree = ""; }; 9EAEC60B2332FE830085D7C9 /* FeedlyCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyCollection.swift; sourceTree = ""; }; 9EAEC60D2332FEC20085D7C9 /* FeedlyFeed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyFeed.swift; sourceTree = ""; }; 9EAEC623233315F60085D7C9 /* FeedlyEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyEntry.swift; sourceTree = ""; }; 9EAEC625233318400085D7C9 /* FeedlyStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyStream.swift; sourceTree = ""; }; 9EAEC62723331C350085D7C9 /* FeedlyCategory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyCategory.swift; sourceTree = ""; }; 9EAEC62923331EE70085D7C9 /* FeedlyOrigin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyOrigin.swift; sourceTree = ""; }; + 9EB1D575238E6A3900A753D7 /* FeedlyAddNewFeedOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyAddNewFeedOperation.swift; sourceTree = ""; }; 9EC228542362C17F00766EF8 /* FeedlySetStarredArticlesOperationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlySetStarredArticlesOperationTests.swift; sourceTree = ""; }; 9EC228562362C7F900766EF8 /* FeedlyCheckpointOperationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyCheckpointOperationTests.swift; sourceTree = ""; }; 9EC228582362D0EA00766EF8 /* FeedlySendArticleStatusesOperationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlySendArticleStatusesOperationTests.swift; sourceTree = ""; }; @@ -680,7 +682,6 @@ 9E964EB923754B4000A7AF2E /* OAuthAccountAuthorizationOperation.swift */, 9E672395236F7E68000BE141 /* OAuthAcessTokenRefreshing.swift */, 9EC688E9232B973C00A8D0A2 /* FeedlyAPICaller.swift */, - 9E510D6D234F16A8002E6F1A /* FeedlyAddFeedRequest.swift */, 9E7299D8235062A200DAEFB7 /* FeedlyResourceProviding.swift */, 9EEAE06F235D003400E3FEE4 /* Services */, 9EBC31B32338AC2E002A567B /* Models */, @@ -694,7 +695,9 @@ children = ( 9E1D1554233431A600F4944C /* FeedlyOperation.swift */, 9EF35F79234E830E003AE2AE /* FeedlyCompoundOperation.swift */, - 9E7299D623505E9600DAEFB7 /* FeedlyAddFeedOperation.swift */, + 9E7299D623505E9600DAEFB7 /* FeedlyAddFeedToCollectionOperation.swift */, + 9EB1D575238E6A3900A753D7 /* FeedlyAddNewFeedOperation.swift */, + 9EA643CE2391D3550018A28C /* FeedlyAddExistingFeedOperation.swift */, 9E1D154E233371DD00F4944C /* FeedlyGetCollectionsOperation.swift */, 9E1D15502334282100F4944C /* FeedlyMirrorCollectionsAsFoldersOperation.swift */, 9E12B01F2334696A00ADE5A0 /* FeedlyCreateFeedsForCollectionFoldersOperation.swift */, @@ -1005,9 +1008,10 @@ 9E1773D7234575AB0056A5A8 /* FeedlyTag.swift in Sources */, 3B826DAB2385C81C00FC1ADB /* FeedWranglerConfig.swift in Sources */, 515E4EB62324FF8C0057B0E7 /* URLRequest+RSWeb.swift in Sources */, + 9EB1D576238E6A3900A753D7 /* FeedlyAddNewFeedOperation.swift in Sources */, 3B826DA82385C81C00FC1ADB /* FeedWranglerFeedItem.swift in Sources */, 9E672396236F7E68000BE141 /* OAuthAcessTokenRefreshing.swift in Sources */, - 9E7299D723505E9600DAEFB7 /* FeedlyAddFeedOperation.swift in Sources */, + 9E7299D723505E9600DAEFB7 /* FeedlyAddFeedToCollectionOperation.swift in Sources */, 9EEAE075235D01C400E3FEE4 /* FeedlyMarkArticlesService.swift in Sources */, 9EF1B10323584B4C000A486A /* FeedlySyncStreamContentsOperation.swift in Sources */, 5154367B228EEB28005E1CDF /* FeedbinImportResult.swift in Sources */, @@ -1019,9 +1023,9 @@ 3BC23AB92385ECB100371CBA /* FeedWranglerSubscriptionResult.swift in Sources */, 5144EA49227B497600D19003 /* FeedbinAPICaller.swift in Sources */, 84B99C9F1FAE8D3200ECDEDB /* ContainerPath.swift in Sources */, - 9E510D6E234F16A8002E6F1A /* FeedlyAddFeedRequest.swift in Sources */, 51BC8FCC237EC055004F8B56 /* Feed.swift in Sources */, 846E77501F6EF9C400A165E2 /* LocalAccountRefresher.swift in Sources */, + 9EA643CF2391D3560018A28C /* FeedlyAddExistingFeedOperation.swift in Sources */, 55203300229D5D5A009559E0 /* ReaderAPICaller.swift in Sources */, 9E1D154F233371DD00F4944C /* FeedlyGetCollectionsOperation.swift in Sources */, 9EAEC626233318400085D7C9 /* FeedlyStream.swift in Sources */, diff --git a/Frameworks/Account/Feedly/FeedlyAccountDelegate.swift b/Frameworks/Account/Feedly/FeedlyAccountDelegate.swift index bc4495d2e..9a8ce30c3 100644 --- a/Frameworks/Account/Feedly/FeedlyAccountDelegate.swift +++ b/Frameworks/Account/Feedly/FeedlyAccountDelegate.swift @@ -288,22 +288,34 @@ final class FeedlyAccountDelegate: AccountDelegate { } } } - - var createFeedRequest: FeedlyAddFeedRequest? - + func createWebFeed(for account: Account, url: String, name: String?, container: Container, completion: @escaping (Result) -> Void) { - - let progress = refreshProgress - progress.addToNumberOfTasksAndRemaining(1) - let request = FeedlyAddFeedRequest(account: account, caller: caller, container: container, log: log) - - self.createFeedRequest = request - - request.addNewFeed(at: url, name: name) { [weak self] result in - progress.completeTask() - self?.createFeedRequest = nil - completion(result) + do { + guard let credentials = credentials else { + throw FeedlyAccountDelegateError.notLoggedIn + } + + let resource = FeedlyFeedResourceId(url: url) + let addNewFeed = try FeedlyAddNewFeedOperation(account: account, + credentials: credentials, + resource: resource, + feedName: name, + caller: caller, + container: container, + progress: refreshProgress, + log: log) + + addNewFeed.addCompletionHandler = { result in + completion(result) + } + + operationQueue.addOperation(addNewFeed) + + } catch { + DispatchQueue.main.async { + completion(.failure(error)) + } } } @@ -334,26 +346,31 @@ final class FeedlyAccountDelegate: AccountDelegate { feed.editedName = name } - var addFeedRequest: FeedlyAddFeedRequest? - func addWebFeed(for account: Account, with feed: WebFeed, to container: Container, completion: @escaping (Result) -> Void) { - - let progress = refreshProgress - progress.addToNumberOfTasksAndRemaining(1) - let request = FeedlyAddFeedRequest(account: account, caller: caller, container: container, log: log) - - self.addFeedRequest = request - - request.add(existing: feed) { [weak self] result in - progress.completeTask() + do { + guard let credentials = credentials else { + throw FeedlyAccountDelegateError.notLoggedIn + } - self?.addFeedRequest = nil + let resource = FeedlyFeedResourceId(id: feed.webFeedID) + let addExistingFeed = try FeedlyAddExistingFeedOperation(account: account, + credentials: credentials, + resource: resource, + caller: caller, + container: container, + progress: refreshProgress, + log: log) - switch result { - case .success: - completion(.success(())) - case .failure(let error): + + addExistingFeed.addCompletionHandler = { result in + completion(result) + } + + operationQueue.addOperation(addExistingFeed) + + } catch { + DispatchQueue.main.async { completion(.failure(error)) } } diff --git a/Frameworks/Account/Feedly/FeedlyAddFeedRequest.swift b/Frameworks/Account/Feedly/FeedlyAddFeedRequest.swift deleted file mode 100644 index b359183e9..000000000 --- a/Frameworks/Account/Feedly/FeedlyAddFeedRequest.swift +++ /dev/null @@ -1,130 +0,0 @@ -// -// FeedlyCreateFeedRequest.swift -// Account -// -// Created by Kiel Gillard on 10/10/19. -// Copyright © 2019 Ranchero Software, LLC. All rights reserved. -// - -import Foundation -import os.log - -final class FeedlyAddFeedRequest { - let account: Account - let caller: FeedlyAPICaller - let container: Container - let log: OSLog - - init(account: Account, caller: FeedlyAPICaller, container: Container, log: OSLog) { - self.account = account - self.caller = caller - self.container = container - self.log = log - } - - private class Delegate: FeedlyOperationDelegate { - let resourceProvider: FeedlyResourceProviding - - init(resourceProvider: FeedlyResourceProviding) { - self.resourceProvider = resourceProvider - } - - var completionHandler: ((Result) -> ())? - var error: Error? - - func feedlyOperation(_ operation: FeedlyOperation, didFailWith error: Error) { - self.error = error - } - } - - func addNewFeed(at url: String, name: String? = nil, completion: @escaping (Result) -> Void) { - let resource = FeedlyFeedResourceId(url: url) - self.start(resource: resource, name: name, refreshes: true, completion: completion) - } - - func add(existing feed: WebFeed, name: String? = nil, completion: @escaping (Result) -> Void) { - let resource = FeedlyFeedResourceId(id: feed.webFeedID) - self.start(resource: resource, name: name, refreshes: false, completion: completion) - } - - private func start(resource: FeedlyFeedResourceId, name: String?, refreshes: Bool, completion: @escaping (Result) -> Void) { - - let (folder, collectionId): (Folder, String) - do { - let validator = FeedlyFeedContainerValidator(container: container, userId: caller.credentials?.username) - (folder, collectionId) = try validator.getValidContainer() - } catch { - return DispatchQueue.main.async { - completion(.failure(error)) - } - } - - let delegate = Delegate(resourceProvider: resource) - delegate.completionHandler = completion - - let createFeed = FeedlyCompoundOperation() { - let addRequest = FeedlyAddFeedOperation(account: account, folder: folder, feedResource: resource, feedName: name, collectionId: collectionId, caller: caller) - - let createFeeds = FeedlyCreateFeedsForCollectionFoldersOperation(account: account, feedsAndFoldersProvider: addRequest, log: log) - createFeeds.addDependency(addRequest) - - let getStream: FeedlyGetStreamContentsOperation? = { - if refreshes { - let op = FeedlyGetStreamContentsOperation(account: account, resourceProvider: addRequest, service: caller, newerThan: nil, log: log) - op.addDependency(createFeeds) - return op - } - return nil - }() - - let organiseByFeed: FeedlyOrganiseParsedItemsByFeedOperation? = { - if let getStream = getStream { - let op = FeedlyOrganiseParsedItemsByFeedOperation(account: account, parsedItemProvider: getStream, log: log) - op.addDependency(getStream) - return op - } - return nil - }() - - let updateAccount: FeedlyUpdateAccountFeedsWithItemsOperation? = { - if let organiseByFeed = organiseByFeed { - let op = FeedlyUpdateAccountFeedsWithItemsOperation(account: account, organisedItemsProvider: organiseByFeed, log: log) - op.addDependency(organiseByFeed) - return op - } - return nil - }() - - let operations = [addRequest, createFeeds, getStream, organiseByFeed, updateAccount].compactMap { $0 } - - for operation in operations { - assert(operation.isReady == (operation === addRequest), "Only the add request operation should be ready.") - operation.delegate = delegate - } - - return operations - } - - let callback = BlockOperation() { - guard let handler = delegate.completionHandler else { - return - } - - defer { delegate.completionHandler = nil } - - if let error = delegate.error { - handler(.failure(error)) - - } else if let feed = folder.existingWebFeed(withWebFeedID: resource.id) { - handler(.success(feed)) - - } else { - handler(.failure(AccountError.createErrorNotFound)) - } - } - - callback.addDependency(createFeed) - - OperationQueue.main.addOperations([createFeed, callback], waitUntilFinished: false) - } -} diff --git a/Frameworks/Account/Feedly/Operations/FeedlyAddExistingFeedOperation.swift b/Frameworks/Account/Feedly/Operations/FeedlyAddExistingFeedOperation.swift new file mode 100644 index 000000000..a3b6e3739 --- /dev/null +++ b/Frameworks/Account/Feedly/Operations/FeedlyAddExistingFeedOperation.swift @@ -0,0 +1,77 @@ +// +// FeedlyAddExistingFeedOperation.swift +// Account +// +// Created by Kiel Gillard on 27/11/19. +// Copyright © 2019 Ranchero Software, LLC. All rights reserved. +// + +import Foundation +import os.log +import RSWeb + +class FeedlyAddExistingFeedOperation: FeedlyOperation, FeedlyOperationDelegate, FeedlyCheckpointOperationDelegate { + private let operationQueue: OperationQueue + + var addCompletionHandler: ((Result) -> ())? + + init(account: Account, credentials: Credentials, resource: FeedlyFeedResourceId, caller: FeedlyAPICaller, container: Container, progress: DownloadProgress, log: OSLog) throws { + + let validator = FeedlyFeedContainerValidator(container: container, userId: credentials.username) + let (folder, collectionId) = try validator.getValidContainer() + + self.operationQueue = OperationQueue() + self.operationQueue.isSuspended = true + + super.init() + + self.downloadProgress = progress + + let addRequest = FeedlyAddFeedToCollectionOperation(account: account, folder: folder, feedResource: resource, feedName: nil, collectionId: collectionId, caller: caller) + addRequest.delegate = self + addRequest.downloadProgress = progress + self.operationQueue.addOperation(addRequest) + + let createFeeds = FeedlyCreateFeedsForCollectionFoldersOperation(account: account, feedsAndFoldersProvider: addRequest, log: log) + createFeeds.downloadProgress = progress + createFeeds.addDependency(addRequest) + self.operationQueue.addOperation(createFeeds) + + let finishOperation = FeedlyCheckpointOperation() + finishOperation.checkpointDelegate = self + finishOperation.downloadProgress = progress + finishOperation.addDependency(createFeeds) + self.operationQueue.addOperation(finishOperation) + } + + override func cancel() { + operationQueue.cancelAllOperations() + super.cancel() + didFinish() + } + + override func main() { + guard !isCancelled else { + return + } + operationQueue.isSuspended = false + } + + func feedlyOperation(_ operation: FeedlyOperation, didFailWith error: Error) { + addCompletionHandler?(.failure(error)) + addCompletionHandler = nil + + cancel() + } + + func feedlyCheckpointOperationDidReachCheckpoint(_ operation: FeedlyCheckpointOperation) { + guard !isCancelled else { + return + } + + addCompletionHandler?(.success(())) + addCompletionHandler = nil + + didFinish() + } +} diff --git a/Frameworks/Account/Feedly/Operations/FeedlyAddFeedOperation.swift b/Frameworks/Account/Feedly/Operations/FeedlyAddFeedToCollectionOperation.swift similarity index 83% rename from Frameworks/Account/Feedly/Operations/FeedlyAddFeedOperation.swift rename to Frameworks/Account/Feedly/Operations/FeedlyAddFeedToCollectionOperation.swift index 71f35f345..1ac8f6c81 100644 --- a/Frameworks/Account/Feedly/Operations/FeedlyAddFeedOperation.swift +++ b/Frameworks/Account/Feedly/Operations/FeedlyAddFeedToCollectionOperation.swift @@ -1,5 +1,5 @@ // -// FeedlyAddFeedOperation.swift +// FeedlyAddFeedToCollectionOperation.swift // Account // // Created by Kiel Gillard on 11/10/19. @@ -8,7 +8,7 @@ import Foundation -final class FeedlyAddFeedOperation: FeedlyOperation, FeedlyFeedsAndFoldersProviding, FeedlyResourceProviding { +final class FeedlyAddFeedToCollectionOperation: FeedlyOperation, FeedlyFeedsAndFoldersProviding, FeedlyResourceProviding { let feedName: String? let collectionId: String let caller: FeedlyAPICaller @@ -37,8 +37,12 @@ final class FeedlyAddFeedOperation: FeedlyOperation, FeedlyFeedsAndFoldersProvid } caller.addFeed(with: feedResource, title: feedName, toCollectionWith: collectionId) { [weak self] result in - guard let self = self else { return } - guard !self.isCancelled else { return self.didFinish() } + guard let self = self else { + return + } + guard !self.isCancelled else { + return self.didFinish() + } self.didCompleteRequest(result) } } diff --git a/Frameworks/Account/Feedly/Operations/FeedlyAddNewFeedOperation.swift b/Frameworks/Account/Feedly/Operations/FeedlyAddNewFeedOperation.swift new file mode 100644 index 000000000..bd15ede20 --- /dev/null +++ b/Frameworks/Account/Feedly/Operations/FeedlyAddNewFeedOperation.swift @@ -0,0 +1,103 @@ +// +// FeedlyAddNewFeedOperation.swift +// Account +// +// Created by Kiel Gillard on 27/11/19. +// Copyright © 2019 Ranchero Software, LLC. All rights reserved. +// + +import Foundation +import os.log +import RSWeb + +class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, FeedlyCheckpointOperationDelegate { + private let operationQueue: OperationQueue + private let folder: Folder + private let feedResourceId: FeedlyFeedResourceId + + var addCompletionHandler: ((Result) -> ())? + + init(account: Account, credentials: Credentials, resource: FeedlyFeedResourceId, feedName: String?, caller: FeedlyAPICaller, container: Container, progress: DownloadProgress, log: OSLog) throws { + + let validator = FeedlyFeedContainerValidator(container: container, userId: credentials.username) + let (folder, collectionId) = try validator.getValidContainer() + + self.folder = folder + self.feedResourceId = resource + self.operationQueue = OperationQueue() + self.operationQueue.isSuspended = true + + super.init() + + self.downloadProgress = progress + + let addRequest = FeedlyAddFeedToCollectionOperation(account: account, folder: folder, feedResource: resource, feedName: feedName, collectionId: collectionId, caller: caller) + addRequest.delegate = self + addRequest.downloadProgress = progress + self.operationQueue.addOperation(addRequest) + + let createFeeds = FeedlyCreateFeedsForCollectionFoldersOperation(account: account, feedsAndFoldersProvider: addRequest, log: log) + createFeeds.addDependency(addRequest) + createFeeds.downloadProgress = progress + self.operationQueue.addOperation(createFeeds) + + let syncUnread = FeedlySyncUnreadStatusesOperation(account: account, credentials: credentials, service: caller, newerThan: nil, log: log) + syncUnread.addDependency(addRequest) + syncUnread.downloadProgress = progress + self.operationQueue.addOperation(syncUnread) + + let syncFeed = FeedlySyncStreamContentsOperation(account: account, resource: resource, service: caller, newerThan: nil, log: log) + syncFeed.addDependency(syncUnread) + syncFeed.downloadProgress = progress + self.operationQueue.addOperation(syncFeed) + + let finishOperation = FeedlyCheckpointOperation() + finishOperation.checkpointDelegate = self + finishOperation.downloadProgress = progress + finishOperation.addDependency(syncFeed) + self.operationQueue.addOperation(finishOperation) + } + + override func cancel() { + operationQueue.cancelAllOperations() + super.cancel() + didFinish() + } + + override func main() { + guard !isCancelled else { + return + } + operationQueue.isSuspended = false + } + + func feedlyOperation(_ operation: FeedlyOperation, didFailWith error: Error) { + addCompletionHandler?(.failure(error)) + addCompletionHandler = nil + + cancel() + } + + func feedlyCheckpointOperationDidReachCheckpoint(_ operation: FeedlyCheckpointOperation) { + guard !isCancelled else { + return + } + + defer { + didFinish() + } + + guard let handler = addCompletionHandler else { + return + } + + if let feed = folder.existingWebFeed(withWebFeedID: feedResourceId.id) { + handler(.success(feed)) + + } else { + handler(.failure(AccountError.createErrorNotFound)) + } + + addCompletionHandler = nil + } +}