Merge pull request #1375 from kielgillard/master

Fix syncing of unread articles with Feedly when…
This commit is contained in:
Maurice Parker 2019-11-29 17:40:19 -06:00 committed by GitHub
commit 8097fc488b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 247 additions and 172 deletions

View File

@ -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 = "<group>"; };
9E489E902360ED30004372EE /* FeedlyOrganiseParsedItemsByFeedOperationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyOrganiseParsedItemsByFeedOperationTests.swift; sourceTree = "<group>"; };
9E489E92236101FC004372EE /* FeedlyUpdateAccountFeedsWithItemsOperationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyUpdateAccountFeedsWithItemsOperationTests.swift; sourceTree = "<group>"; };
9E510D6D234F16A8002E6F1A /* FeedlyAddFeedRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyAddFeedRequest.swift; sourceTree = "<group>"; };
9E5ABE99236BE6BC00B5DE9F /* feedly-1-initial */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "feedly-1-initial"; sourceTree = "<group>"; };
9E672393236F7CA0000BE141 /* FeedlyRefreshAccessTokenOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyRefreshAccessTokenOperation.swift; sourceTree = "<group>"; };
9E672395236F7E68000BE141 /* OAuthAcessTokenRefreshing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OAuthAcessTokenRefreshing.swift; sourceTree = "<group>"; };
9E713652233AD63E00765C84 /* FeedlySetUnreadArticlesOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlySetUnreadArticlesOperation.swift; sourceTree = "<group>"; };
9E7299D623505E9600DAEFB7 /* FeedlyAddFeedOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyAddFeedOperation.swift; sourceTree = "<group>"; };
9E7299D623505E9600DAEFB7 /* FeedlyAddFeedToCollectionOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyAddFeedToCollectionOperation.swift; sourceTree = "<group>"; };
9E7299D8235062A200DAEFB7 /* FeedlyResourceProviding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyResourceProviding.swift; sourceTree = "<group>"; };
9E784EBD237E890600099B1B /* FeedlyLogoutOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyLogoutOperation.swift; sourceTree = "<group>"; };
9E784EBF237E8BE100099B1B /* FeedlyLogoutOperationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyLogoutOperationTests.swift; sourceTree = "<group>"; };
@ -357,12 +357,14 @@
9E964E9E23754AC400A7AF2E /* OAuthAuthorizationClient+Feedly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OAuthAuthorizationClient+Feedly.swift"; sourceTree = "<group>"; };
9E964EB923754B4000A7AF2E /* OAuthAccountAuthorizationOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OAuthAccountAuthorizationOperation.swift; sourceTree = "<group>"; };
9EA3133A231E368100268BA0 /* FeedlyAccountDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedlyAccountDelegate.swift; sourceTree = "<group>"; };
9EA643CE2391D3550018A28C /* FeedlyAddExistingFeedOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedlyAddExistingFeedOperation.swift; sourceTree = "<group>"; };
9EAEC60B2332FE830085D7C9 /* FeedlyCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyCollection.swift; sourceTree = "<group>"; };
9EAEC60D2332FEC20085D7C9 /* FeedlyFeed.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyFeed.swift; sourceTree = "<group>"; };
9EAEC623233315F60085D7C9 /* FeedlyEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyEntry.swift; sourceTree = "<group>"; };
9EAEC625233318400085D7C9 /* FeedlyStream.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyStream.swift; sourceTree = "<group>"; };
9EAEC62723331C350085D7C9 /* FeedlyCategory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyCategory.swift; sourceTree = "<group>"; };
9EAEC62923331EE70085D7C9 /* FeedlyOrigin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyOrigin.swift; sourceTree = "<group>"; };
9EB1D575238E6A3900A753D7 /* FeedlyAddNewFeedOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyAddNewFeedOperation.swift; sourceTree = "<group>"; };
9EC228542362C17F00766EF8 /* FeedlySetStarredArticlesOperationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlySetStarredArticlesOperationTests.swift; sourceTree = "<group>"; };
9EC228562362C7F900766EF8 /* FeedlyCheckpointOperationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlyCheckpointOperationTests.swift; sourceTree = "<group>"; };
9EC228582362D0EA00766EF8 /* FeedlySendArticleStatusesOperationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedlySendArticleStatusesOperationTests.swift; sourceTree = "<group>"; };
@ -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 */,

View File

@ -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<WebFeed, Error>) -> 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, Error>) -> 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))
}
}

View File

@ -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<WebFeed, Error>) -> ())?
var error: Error?
func feedlyOperation(_ operation: FeedlyOperation, didFailWith error: Error) {
self.error = error
}
}
func addNewFeed(at url: String, name: String? = nil, completion: @escaping (Result<WebFeed, Error>) -> 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<WebFeed, Error>) -> 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<WebFeed, Error>) -> 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)
}
}

View File

@ -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<Void, Error>) -> ())?
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()
}
}

View File

@ -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)
}
}

View File

@ -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<WebFeed, Error>) -> ())?
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
}
}