diff --git a/Frameworks/Account/NewsBlur/Models/NewsBlurFolderChange.swift b/Frameworks/Account/NewsBlur/Models/NewsBlurFolderChange.swift index f894fc4b9..cc38615a7 100644 --- a/Frameworks/Account/NewsBlur/Models/NewsBlurFolderChange.swift +++ b/Frameworks/Account/NewsBlur/Models/NewsBlurFolderChange.swift @@ -10,15 +10,28 @@ import Foundation enum NewsBlurFolderChange { case add(String) + case rename(String, String) + case delete(String) } -extension NewsBlurFolderChange { +extension NewsBlurFolderChange: NewsBlurDataConvertible { var asData: Data? { var postData = URLComponents() postData.queryItems = { switch self { case .add(let name): return [URLQueryItem(name: "folder", value: name)] + case .rename(let from, let to): + return [ + URLQueryItem(name: "folder_to_rename", value: from), + URLQueryItem(name: "new_folder_name", value: to), + URLQueryItem(name: "in_folder", value: ""), // root folder + ] + case .delete(let name): + return [ + URLQueryItem(name: "folder_to_delete", value: name), + URLQueryItem(name: "in_folder", value: ""), // root folder + ] } }() diff --git a/Frameworks/Account/NewsBlur/Models/NewsBlurStoryStatusChange.swift b/Frameworks/Account/NewsBlur/Models/NewsBlurStoryStatusChange.swift index 464fe1fdb..c07fd9220 100644 --- a/Frameworks/Account/NewsBlur/Models/NewsBlurStoryStatusChange.swift +++ b/Frameworks/Account/NewsBlur/Models/NewsBlurStoryStatusChange.swift @@ -12,7 +12,7 @@ struct NewsBlurStoryStatusChange { let hashes: [String] } -extension NewsBlurStoryStatusChange { +extension NewsBlurStoryStatusChange: NewsBlurDataConvertible { var asData: Data? { var postData = URLComponents() postData.queryItems = hashes.map { URLQueryItem(name: "story_hash", value: $0) } diff --git a/Frameworks/Account/NewsBlur/NewsBlurAPICaller.swift b/Frameworks/Account/NewsBlur/NewsBlurAPICaller.swift index 4e752e804..e42f4ce0e 100644 --- a/Frameworks/Account/NewsBlur/NewsBlurAPICaller.swift +++ b/Frameworks/Account/NewsBlur/NewsBlurAPICaller.swift @@ -9,6 +9,10 @@ import Foundation import RSWeb +protocol NewsBlurDataConvertible { + var asData: Data? { get } +} + enum NewsBlurError: LocalizedError { case general(message: String) case invalidParameter @@ -178,39 +182,31 @@ final class NewsBlurAPICaller: NSObject { } func markAsUnread(hashes: [String], completion: @escaping (Result) -> Void) { - sendStoryStatus(endpoint: "reader/mark_story_hash_as_unread", hashes: hashes, completion: completion) + sendUpdates(endpoint: "reader/mark_story_hash_as_unread", payload: NewsBlurStoryStatusChange(hashes: hashes), completion: completion) } func markAsRead(hashes: [String], completion: @escaping (Result) -> Void) { - sendStoryStatus(endpoint: "reader/mark_story_hashes_as_read", hashes: hashes, completion: completion) + sendUpdates(endpoint: "reader/mark_story_hashes_as_read", payload: NewsBlurStoryStatusChange(hashes: hashes), completion: completion) } func star(hashes: [String], completion: @escaping (Result) -> Void) { - sendStoryStatus(endpoint: "reader/mark_story_hash_as_starred", hashes: hashes, completion: completion) + sendUpdates(endpoint: "reader/mark_story_hash_as_starred", payload: NewsBlurStoryStatusChange(hashes: hashes), completion: completion) } func unstar(hashes: [String], completion: @escaping (Result) -> Void) { - sendStoryStatus(endpoint: "reader/mark_story_hash_as_unstarred", hashes: hashes, completion: completion) + sendUpdates(endpoint: "reader/mark_story_hash_as_unstarred", payload: NewsBlurStoryStatusChange(hashes: hashes), completion: completion) } func addFolder(named name: String, completion: @escaping (Result) -> Void) { - let callURL = baseURL.appendingPathComponent("reader/add_folder") + sendUpdates(endpoint: "reader/add_folder", payload: NewsBlurFolderChange.add(name), completion: completion) + } - 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 - } + func renameFolder(with folder: String, to name: String, completion: @escaping (Result) -> Void) { + sendUpdates(endpoint: "reader/rename_folder", payload: NewsBlurFolderChange.rename(folder, name), completion: completion) + } - switch result { - case .success: - completion(.success(())) - case .failure(let error): - completion(.failure(error)) - } - } + func removeFolder(named name: String, completion: @escaping (Result) -> Void) { + sendUpdates(endpoint: "reader/delete_folder", payload: NewsBlurFolderChange.delete(name), completion: completion) } } @@ -244,11 +240,11 @@ extension NewsBlurAPICaller { } } - private func sendStoryStatus(endpoint: String, hashes: [String], completion: @escaping (Result) -> Void) { + private func sendUpdates(endpoint: String, payload: NewsBlurDataConvertible, completion: @escaping (Result) -> Void) { let callURL = baseURL.appendingPathComponent(endpoint) var request = URLRequest(url: callURL, credentials: credentials) - request.httpBody = NewsBlurStoryStatusChange(hashes: hashes).asData + request.httpBody = payload.asData transport.send(request: request, method: HTTPMethod.post) { result in if self.suspended { completion(.failure(TransportError.suspended)) diff --git a/Frameworks/Account/NewsBlur/NewsBlurAccountDelegate.swift b/Frameworks/Account/NewsBlur/NewsBlurAccountDelegate.swift index 7cb1bb741..c0de947af 100644 --- a/Frameworks/Account/NewsBlur/NewsBlurAccountDelegate.swift +++ b/Frameworks/Account/NewsBlur/NewsBlurAccountDelegate.swift @@ -328,11 +328,49 @@ final class NewsBlurAccountDelegate: AccountDelegate { } func renameFolder(for account: Account, with folder: Folder, to name: String, completion: @escaping (Result) -> ()) { - completion(.success(())) + guard let folderToRename = folder.name else { + completion(.failure(NewsBlurError.invalidParameter)) + return + } + + refreshProgress.addToNumberOfTasksAndRemaining(1) + + let nameBefore = folder.name + + caller.renameFolder(with: folderToRename, to: name) { result in + self.refreshProgress.completeTask() + + switch result { + case .success: + completion(.success(())) + case .failure(let error): + folder.name = nameBefore + completion(.failure(error)) + } + } + + folder.name = name } func removeFolder(for account: Account, with folder: Folder, completion: @escaping (Result) -> ()) { - completion(.success(())) + guard let folderToRemove = folder.name else { + completion(.failure(NewsBlurError.invalidParameter)) + return + } + + refreshProgress.addToNumberOfTasksAndRemaining(1) + + caller.removeFolder(named: folderToRemove) { result in + self.refreshProgress.completeTask() + + switch result { + case .success: + account.removeFolder(folder) + completion(.success(())) + case .failure(let error): + completion(.failure(error)) + } + } } func createWebFeed(for account: Account, url: String, name: String?, container: Container, completion: @escaping (Result) -> ()) {