diff --git a/Frameworks/Account/Account.xcodeproj/project.pbxproj b/Frameworks/Account/Account.xcodeproj/project.pbxproj index cdfe3e4c6..7f96e2abd 100644 --- a/Frameworks/Account/Account.xcodeproj/project.pbxproj +++ b/Frameworks/Account/Account.xcodeproj/project.pbxproj @@ -12,6 +12,7 @@ 179DB28CF49F73A945EBF5DB /* NewsBlurLoginResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 179DB088236E3236010462E8 /* NewsBlurLoginResponse.swift */; }; 179DB49A960F8B78C4924458 /* NewsBlurGenericCodingKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = 179DB66D933E976C29159DEE /* NewsBlurGenericCodingKeys.swift */; }; 179DB96B984E67DC101E470D /* NewsBlurAccountDelegate+Private.swift in Sources */ = {isa = PBXBuildFile; fileRef = 179DB55DC2CAD332D4376416 /* NewsBlurAccountDelegate+Private.swift */; }; + 179DBD4ECC1C9712DF51DB8C /* NewsBlurFolderChange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 179DBDDC00B68411AA28941F /* NewsBlurFolderChange.swift */; }; 179DBED55C9B4D6A413486C1 /* NewsBlurStoryHash.swift in Sources */ = {isa = PBXBuildFile; fileRef = 179DB818180A51098A9816B2 /* NewsBlurStoryHash.swift */; }; 179DBF4DE2562D4C532F6008 /* NewsBlurFeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 179DB1B909672E0E807B5E8C /* NewsBlurFeed.swift */; }; 3B3A33E7238D3D6800314204 /* Secrets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B3A33E6238D3D6800314204 /* Secrets.swift */; }; @@ -236,6 +237,7 @@ 179DB66D933E976C29159DEE /* NewsBlurGenericCodingKeys.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsBlurGenericCodingKeys.swift; sourceTree = ""; }; 179DB7399814F6FB3247825C /* NewsBlurStory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsBlurStory.swift; sourceTree = ""; }; 179DB818180A51098A9816B2 /* NewsBlurStoryHash.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsBlurStoryHash.swift; sourceTree = ""; }; + 179DBDDC00B68411AA28941F /* NewsBlurFolderChange.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewsBlurFolderChange.swift; sourceTree = ""; }; 3B3A33E6238D3D6800314204 /* Secrets.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Secrets.swift; path = ../../Shared/Secrets.swift; sourceTree = ""; }; 3B826D9E2385C81C00FC1ADB /* FeedWranglerAuthorizationResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedWranglerAuthorizationResult.swift; sourceTree = ""; }; 3B826D9F2385C81C00FC1ADB /* FeedWranglerFeedItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedWranglerFeedItem.swift; sourceTree = ""; }; @@ -462,6 +464,7 @@ 179DB66D933E976C29159DEE /* NewsBlurGenericCodingKeys.swift */, 179DB818180A51098A9816B2 /* NewsBlurStoryHash.swift */, 179DB5B421C5433B45C5F13E /* NewsBlurStoryStatusChange.swift */, + 179DBDDC00B68411AA28941F /* NewsBlurFolderChange.swift */, ); path = Models; sourceTree = ""; @@ -1159,6 +1162,7 @@ 179DBED55C9B4D6A413486C1 /* NewsBlurStoryHash.swift in Sources */, 179DB0B17A6C51B95ABC1741 /* NewsBlurStoryStatusChange.swift in Sources */, 179DB96B984E67DC101E470D /* NewsBlurAccountDelegate+Private.swift in Sources */, + 179DBD4ECC1C9712DF51DB8C /* NewsBlurFolderChange.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Frameworks/Account/NewsBlur/Models/NewsBlurFolderChange.swift b/Frameworks/Account/NewsBlur/Models/NewsBlurFolderChange.swift new file mode 100644 index 000000000..f894fc4b9 --- /dev/null +++ b/Frameworks/Account/NewsBlur/Models/NewsBlurFolderChange.swift @@ -0,0 +1,27 @@ +// +// NewsBlurFolderChange.swift +// Account +// +// Created by Anh Quang Do on 2020-03-14. +// Copyright (c) 2020 Ranchero Software, LLC. All rights reserved. +// + +import Foundation + +enum NewsBlurFolderChange { + case add(String) +} + +extension NewsBlurFolderChange { + var asData: Data? { + var postData = URLComponents() + postData.queryItems = { + switch self { + case .add(let name): + return [URLQueryItem(name: "folder", value: name)] + } + }() + + return postData.percentEncodedQuery?.data(using: .utf8) + } +} diff --git a/Frameworks/Account/NewsBlur/NewsBlurAPICaller.swift b/Frameworks/Account/NewsBlur/NewsBlurAPICaller.swift index 2d8d43cc9..4e752e804 100644 --- a/Frameworks/Account/NewsBlur/NewsBlurAPICaller.swift +++ b/Frameworks/Account/NewsBlur/NewsBlurAPICaller.swift @@ -11,12 +11,15 @@ import RSWeb enum NewsBlurError: LocalizedError { case general(message: String) + case invalidParameter case unknown var errorDescription: String? { switch self { case .general(let message): return message + case .invalidParameter: + return "There was an invalid parameter passed" case .unknown: return "An unknown error occurred" } @@ -65,13 +68,13 @@ final class NewsBlurAPICaller: NSObject { if let message = error?.first { completion(.failure(NewsBlurError.general(message: message))) } else { - completion(.failure(NewsBlurError.general(message: "Failed to log in"))) + completion(.failure(NewsBlurError.unknown)) } return } guard let username = self.credentials?.username else { - completion(.failure(NewsBlurError.general(message: "Failed to log in"))) + completion(.failure(NewsBlurError.unknown)) return } @@ -189,6 +192,26 @@ final class NewsBlurAPICaller: NSObject { func unstar(hashes: [String], completion: @escaping (Result) -> Void) { sendStoryStatus(endpoint: "reader/mark_story_hash_as_unstarred", hashes: hashes, completion: completion) } + + func addFolder(named name: String, completion: @escaping (Result) -> Void) { + let callURL = baseURL.appendingPathComponent("reader/add_folder") + + var request = URLRequest(url: callURL, credentials: credentials) + request.httpBody = NewsBlurFolderChange.add(name).asData + transport.send(request: request, method: HTTPMethod.post) { result in + if self.suspended { + completion(.failure(TransportError.suspended)) + return + } + + switch result { + case .success: + completion(.success(())) + case .failure(let error): + completion(.failure(error)) + } + } + } } extension NewsBlurAPICaller { diff --git a/Frameworks/Account/NewsBlur/NewsBlurAccountDelegate.swift b/Frameworks/Account/NewsBlur/NewsBlurAccountDelegate.swift index 3e957e965..7cb1bb741 100644 --- a/Frameworks/Account/NewsBlur/NewsBlurAccountDelegate.swift +++ b/Frameworks/Account/NewsBlur/NewsBlurAccountDelegate.swift @@ -309,6 +309,22 @@ final class NewsBlurAccountDelegate: AccountDelegate { } func addFolder(for account: Account, name: String, completion: @escaping (Result) -> ()) { + self.refreshProgress.addToNumberOfTasksAndRemaining(1) + + caller.addFolder(named: name) { result in + self.refreshProgress.completeTask() + + switch result { + case .success(): + if let folder = account.ensureFolder(with: name) { + completion(.success(folder)) + } else { + completion(.failure(NewsBlurError.invalidParameter)) + } + case .failure(let error): + completion(.failure(error)) + } + } } func renameFolder(for account: Account, with folder: Folder, to name: String, completion: @escaping (Result) -> ()) {