From 361ecd20e3bfa9017fc7ca878e7305369b91c6d5 Mon Sep 17 00:00:00 2001 From: Brent Simmons Date: Wed, 22 Jan 2025 21:49:54 -0800 Subject: [PATCH] Fix lint issues. --- .../Account/ReaderAPI/ReaderAPICaller.swift | 225 ++++++++---------- 1 file changed, 105 insertions(+), 120 deletions(-) diff --git a/Modules/Account/Sources/Account/ReaderAPI/ReaderAPICaller.swift b/Modules/Account/Sources/Account/ReaderAPI/ReaderAPICaller.swift index 45ac4fb44..b569bce42 100644 --- a/Modules/Account/Sources/Account/ReaderAPI/ReaderAPICaller.swift +++ b/Modules/Account/Sources/Account/ReaderAPI/ReaderAPICaller.swift @@ -16,23 +16,23 @@ enum CreateReaderAPISubscriptionResult { } final class ReaderAPICaller: NSObject { - + enum ItemIDType { case unread case starred case allForAccount case allForFeed } - + private enum ReaderState: String { case read = "user/-/state/com.google/read" case starred = "user/-/state/com.google/starred" } - + private enum ReaderStreams: String { case readingList = "user/-/state/com.google/reading-list" } - + private enum ReaderAPIEndpoints: String { case login = "/accounts/ClientLogin" case token = "/reader/api/0/token" @@ -46,12 +46,12 @@ final class ReaderAPICaller: NSObject { case itemIds = "/reader/api/0/stream/items/ids" case editTag = "/reader/api/0/edit-tag" } - + private var transport: Transport! private let uriComponentAllowed: CharacterSet private var accessToken: String? - + weak var accountMetadata: AccountMetadata? var variant: ReaderAPIVariant = .generic @@ -62,7 +62,7 @@ final class ReaderAPICaller: NSObject { return apiBaseURL?.host } } - + private var apiBaseURL: URL? { get { switch variant { @@ -76,27 +76,27 @@ final class ReaderAPICaller: NSObject { } } } - + init(transport: Transport) { self.transport = transport - + var urlHostAllowed = CharacterSet.urlHostAllowed urlHostAllowed.remove("+") urlHostAllowed.remove("&") uriComponentAllowed = urlHostAllowed super.init() } - + func cancelAll() { transport.cancelAll() } - + func validateCredentials(endpoint: URL, completion: @escaping (Result) -> Void) { guard let credentials = credentials else { completion(.failure(CredentialsError.incompleteCredentials)) return } - + var request = URLRequest(url: endpoint.appendingPathComponent(ReaderAPIEndpoints.login.rawValue), credentials: credentials) addVariantHeaders(&request) @@ -107,29 +107,29 @@ final class ReaderAPICaller: NSObject { completion(.failure(TransportError.noData)) break } - + // Convert the return data to UTF8 and then parse out the Auth token guard let rawData = String(data: resultData, encoding: .utf8) else { completion(.failure(TransportError.noData)) break } - + var authData: [String: String] = [:] rawData.split(separator: "\n").forEach({ (line: Substring) in - let items = line.split(separator: "=").map{String($0)} + let items = line.split(separator: "=").map {String($0)} if items.count == 2 { authData[items[0]] = items[1] } }) - + guard let authString = authData["Auth"] else { completion(.failure(CredentialsError.incompleteCredentials)) break } - + // Save Auth Token for later use self.credentials = Credentials(type: .readerAPIKey, username: credentials.username, secret: authString) - + completion(.success(self.credentials)) case .failure(let error): if let transportError = error as? TransportError, case .httpError(let code) = transportError, code == 404 { @@ -139,25 +139,25 @@ final class ReaderAPICaller: NSObject { } } } - + } - + func requestAuthorizationToken(endpoint: URL, completion: @escaping (Result) -> Void) { // If we have a token already, use it if let accessToken = accessToken { completion(.success(accessToken)) return } - + // Otherwise request one. guard let credentials = credentials else { completion(.failure(CredentialsError.incompleteCredentials)) return } - + var request = URLRequest(url: endpoint.appendingPathComponent(ReaderAPIEndpoints.token.rawValue), credentials: credentials) addVariantHeaders(&request) - + transport.send(request: request) { result in switch result { case .success(let (_, data)): @@ -165,13 +165,13 @@ final class ReaderAPICaller: NSObject { completion(.failure(TransportError.noData)) break } - + // Convert the return data to UTF8 and then parse out the Auth token guard let accessToken = String(data: resultData, encoding: .utf8) else { completion(.failure(TransportError.noData)) break } - + self.accessToken = accessToken completion(.success(accessToken)) case .failure(let error): @@ -179,22 +179,21 @@ final class ReaderAPICaller: NSObject { } } } - - + func retrieveTags(completion: @escaping (Result<[ReaderAPITag]?, Error>) -> Void) { guard let baseURL = apiBaseURL else { completion(.failure(CredentialsError.incompleteCredentials)) return } - + var url = baseURL .appendingPathComponent(ReaderAPIEndpoints.tagList.rawValue) .appendingQueryItem(URLQueryItem(name: "output", value: "json")) - + if variant == .inoreader { url = url?.appendingQueryItem(URLQueryItem(name: "types", value: "1")) } - + guard let callURL = url else { completion(.failure(TransportError.noURL)) return @@ -211,7 +210,7 @@ final class ReaderAPICaller: NSObject { completion(.failure(error)) } } - + } func renameTag(oldName: String, newName: String, completion: @escaping (Result) -> Void) { @@ -219,7 +218,7 @@ final class ReaderAPICaller: NSObject { completion(.failure(CredentialsError.incompleteCredentials)) return } - + self.requestAuthorizationToken(endpoint: baseURL) { (result) in switch result { case .success(let token): @@ -227,45 +226,42 @@ final class ReaderAPICaller: NSObject { self.addVariantHeaders(&request) request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.httpMethod = "POST" - + guard let encodedOldName = self.encodeForURLPath(oldName), let encodedNewName = self.encodeForURLPath(newName) else { completion(.failure(ReaderAPIAccountDelegateError.invalidParameter)) return } - + let oldTagName = "user/-/label/\(encodedOldName)" let newTagName = "user/-/label/\(encodedNewName)" let postData = "T=\(token)&s=\(oldTagName)&dest=\(newTagName)".data(using: String.Encoding.utf8) - + self.transport.send(request: request, method: HTTPMethod.post, payload: postData!, completion: { (result) in switch result { case .success: completion(.success(())) - break - case .failure(let error): + case .failure(let error): completion(.failure(error)) - break } }) - - + case .failure(let error): completion(.failure(error)) } } } - + func deleteTag(folder: Folder, completion: @escaping (Result) -> Void) { guard let baseURL = apiBaseURL else { completion(.failure(CredentialsError.incompleteCredentials)) return } - + guard let folderExternalID = folder.externalID else { completion(.failure(ReaderAPIAccountDelegateError.invalidParameter)) return } - + self.requestAuthorizationToken(endpoint: baseURL) { (result) in switch result { case .success(let token): @@ -273,42 +269,39 @@ final class ReaderAPICaller: NSObject { self.addVariantHeaders(&request) request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.httpMethod = "POST" - + let postData = "T=\(token)&s=\(folderExternalID)".data(using: String.Encoding.utf8) - + self.transport.send(request: request, method: HTTPMethod.post, payload: postData!, completion: { (result) in switch result { case .success: completion(.success(())) - break - case .failure(let error): + case .failure(let error): completion(.failure(error)) - break } }) - - + case .failure(let error): completion(.failure(error)) } } } - + func retrieveSubscriptions(completion: @escaping (Result<[ReaderAPISubscription]?, Error>) -> Void) { guard let baseURL = apiBaseURL else { completion(.failure(CredentialsError.incompleteCredentials)) return } - + let url = baseURL .appendingPathComponent(ReaderAPIEndpoints.subscriptionList.rawValue) .appendingQueryItem(URLQueryItem(name: "output", value: "json")) - + guard let callURL = url else { completion(.failure(TransportError.noURL)) return } - + var request = URLRequest(url: callURL, credentials: credentials) addVariantHeaders(&request) @@ -321,13 +314,13 @@ final class ReaderAPICaller: NSObject { } } } - + func createSubscription(url: String, name: String?, folder: Folder?, completion: @escaping (Result) -> Void) { guard let baseURL = apiBaseURL else { completion(.failure(CredentialsError.incompleteCredentials)) return } - + func findSubscription(streamID: String, completion: @escaping (Result) -> Void) { // There is no call to get a single subscription entry, so we get them all, // look up the one we just subscribed to and return that @@ -353,19 +346,18 @@ final class ReaderAPICaller: NSObject { } }) } - self.requestAuthorizationToken(endpoint: baseURL) { (result) in switch result { case .success(let token): let callURL = baseURL .appendingPathComponent(ReaderAPIEndpoints.subscriptionAdd.rawValue) - + var request = URLRequest(url: callURL, credentials: self.credentials) self.addVariantHeaders(&request) request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.httpMethod = "POST" - + guard let encodedFeedURL = self.encodeForURLPath(url) else { completion(.failure(ReaderAPIAccountDelegateError.invalidParameter)) return @@ -387,7 +379,7 @@ final class ReaderAPICaller: NSObject { findSubscription(streamID: streamId, completion: completion) } - + case .failure(let error): completion(.failure(error)) } @@ -397,21 +389,21 @@ final class ReaderAPICaller: NSObject { case .failure(let error): completion(.failure(error)) } - + } } - + func renameSubscription(subscriptionID: String, newName: String, completion: @escaping (Result) -> Void) { changeSubscription(subscriptionID: subscriptionID, title: newName, completion: completion) } - + func deleteSubscription(subscriptionID: String, completion: @escaping (Result) -> Void) { guard let baseURL = apiBaseURL else { completion(.failure(CredentialsError.incompleteCredentials)) return } - + self.requestAuthorizationToken(endpoint: baseURL) { (result) in switch result { case .success(let token): @@ -419,49 +411,47 @@ final class ReaderAPICaller: NSObject { self.addVariantHeaders(&request) request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.httpMethod = "POST" - + let postData = "T=\(token)&s=\(subscriptionID)&ac=unsubscribe".data(using: String.Encoding.utf8) - + self.transport.send(request: request, method: HTTPMethod.post, payload: postData!, completion: { (result) in switch result { case .success: completion(.success(())) - break - case .failure(let error): + case .failure(let error): completion(.failure(error)) - break } }) - + case .failure(let error): completion(.failure(error)) } } } - + func createTagging(subscriptionID: String, tagName: String, completion: @escaping (Result) -> Void) { changeSubscription(subscriptionID: subscriptionID, addTagName: tagName, completion: completion) } - + func deleteTagging(subscriptionID: String, tagName: String, completion: @escaping (Result) -> Void) { changeSubscription(subscriptionID: subscriptionID, removeTagName: tagName, completion: completion) } - + func moveSubscription(subscriptionID: String, fromTag: String, toTag: String, completion: @escaping (Result) -> Void) { changeSubscription(subscriptionID: subscriptionID, removeTagName: fromTag, addTagName: toTag, completion: completion) } - + private func changeSubscription(subscriptionID: String, removeTagName: String? = nil, addTagName: String? = nil, title: String? = nil, completion: @escaping (Result) -> Void) { guard removeTagName != nil || addTagName != nil || title != nil else { completion(.failure(ReaderAPIAccountDelegateError.invalidParameter)) return } - + guard let baseURL = apiBaseURL else { completion(.failure(CredentialsError.incompleteCredentials)) return } - + self.requestAuthorizationToken(endpoint: baseURL) { (result) in switch result { case .success(let token): @@ -469,7 +459,7 @@ final class ReaderAPICaller: NSObject { self.addVariantHeaders(&request) request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.httpMethod = "POST" - + var postString = "T=\(token)&s=\(subscriptionID)&ac=edit" if let fromLabel = self.encodeForURLPath(removeTagName) { postString += "&r=user/-/label/\(fromLabel)" @@ -481,36 +471,34 @@ final class ReaderAPICaller: NSObject { postString += "&t=\(encodedTitle)" } let postData = postString.data(using: String.Encoding.utf8) - + self.transport.send(request: request, method: HTTPMethod.post, payload: postData!, completion: { (result) in switch result { case .success: completion(.success(())) - break - case .failure(let error): + case .failure(let error): completion(.failure(error)) - break } }) - + case .failure(let error): completion(.failure(error)) } } } - + func retrieveEntries(articleIDs: [String], completion: @escaping (Result<([ReaderAPIEntry]?), Error>) -> Void) { - + guard !articleIDs.isEmpty else { completion(.success(([ReaderAPIEntry]()))) return } - + guard let baseURL = apiBaseURL else { completion(.failure(CredentialsError.incompleteCredentials)) return } - + self.requestAuthorizationToken(endpoint: baseURL) { (result) in switch result { case .success(let token): @@ -518,7 +506,7 @@ final class ReaderAPICaller: NSObject { self.addVariantHeaders(&request) request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.httpMethod = "POST" - + // Get ids from above into hex representation of value let idsToFetch = articleIDs.map({ articleID -> String in if self.variant == .theOldReader { @@ -528,10 +516,10 @@ final class ReaderAPICaller: NSObject { let idHexString = String(idValue, radix: 16, uppercase: false) return "i=tag:google.com,2005:reader/item/\(idHexString)" } - }).joined(separator:"&") - + }).joined(separator: "&") + let postData = "T=\(token)&output=json&\(idsToFetch)".data(using: String.Encoding.utf8) - + self.transport.send(request: request, method: HTTPMethod.post, data: postData!, resultType: ReaderAPIEntryWrapper.self, completion: { (result) in switch result { case .success(let (_, entryWrapper)): @@ -539,32 +527,31 @@ final class ReaderAPICaller: NSObject { completion(.failure(ReaderAPIAccountDelegateError.invalidResponse)) return } - + completion(.success((entryWrapper.entries))) case .failure(let error): completion(.failure(error)) } }) - - + case .failure(let error): completion(.failure(error)) } } } - + func retrieveItemIDs(type: ItemIDType, feedID: String? = nil, completion: @escaping ((Result<[String], Error>) -> Void)) { guard let baseURL = apiBaseURL else { completion(.failure(CredentialsError.incompleteCredentials)) return } - + var queryItems = [ URLQueryItem(name: "n", value: "1000"), URLQueryItem(name: "output", value: "json") ] - + switch type { case .allForAccount: let since: Date = { @@ -574,7 +561,7 @@ final class ReaderAPICaller: NSObject { return Calendar.current.date(byAdding: .month, value: -3, to: Date()) ?? Date() } }() - + let sinceTimeInterval = since.timeIntervalSince1970 queryItems.append(URLQueryItem(name: "ot", value: String(Int(sinceTimeInterval)))) queryItems.append(URLQueryItem(name: "s", value: ReaderStreams.readingList.rawValue)) @@ -592,16 +579,16 @@ final class ReaderAPICaller: NSObject { case .starred: queryItems.append(URLQueryItem(name: "s", value: ReaderState.starred.rawValue)) } - + let url = baseURL .appendingPathComponent(ReaderAPIEndpoints.itemIds.rawValue) .appendingQueryItems(queryItems) - + guard let callURL = url else { completion(.failure(TransportError.noURL)) return } - + var request: URLRequest = URLRequest(url: callURL, credentials: credentials) addVariantHeaders(&request) @@ -630,21 +617,21 @@ final class ReaderAPICaller: NSObject { completion(.success(itemIDs)) return } - + guard var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) else { completion(.failure(ReaderAPIAccountDelegateError.invalidParameter)) return } - + var queryItems = urlComponents.queryItems!.filter({ $0.name != "c" }) queryItems.append(URLQueryItem(name: "c", value: continuation)) urlComponents.queryItems = queryItems - + guard let callURL = urlComponents.url else { completion(.failure(TransportError.noURL)) return } - + var request: URLRequest = URLRequest(url: callURL, credentials: credentials) addVariantHeaders(&request) @@ -663,34 +650,34 @@ final class ReaderAPICaller: NSObject { } } } - + func createUnreadEntries(entries: [String], completion: @escaping (Result) -> Void) { updateStateToEntries(entries: entries, state: .read, add: false, completion: completion) } - + func deleteUnreadEntries(entries: [String], completion: @escaping (Result) -> Void) { updateStateToEntries(entries: entries, state: .read, add: true, completion: completion) } - + func createStarredEntries(entries: [String], completion: @escaping (Result) -> Void) { updateStateToEntries(entries: entries, state: .starred, add: true, completion: completion) } - + func deleteStarredEntries(entries: [String], completion: @escaping (Result) -> Void) { updateStateToEntries(entries: entries, state: .starred, add: false, completion: completion) } - + } // MARK: Private private extension ReaderAPICaller { - + func encodeForURLPath(_ pathComponent: String?) -> String? { guard let pathComponent = pathComponent else { return nil } return pathComponent.addingPercentEncoding(withAllowedCharacters: uriComponentAllowed) } - + func addVariantHeaders(_ request: inout URLRequest) { if variant == .inoreader { request.addValue(SecretKey.inoreaderAppID, forHTTPHeaderField: "AppId") @@ -703,7 +690,7 @@ private extension ReaderAPICaller { completion(.failure(CredentialsError.incompleteCredentials)) return } - + self.requestAuthorizationToken(endpoint: baseURL) { (result) in switch result { case .success(let token): @@ -712,7 +699,7 @@ private extension ReaderAPICaller { self.addVariantHeaders(&request) request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.httpMethod = "POST" - + // Get ids from above into hex representation of value let idsToFetch = entries.compactMap({ idValue -> String? in if self.variant == .theOldReader { @@ -722,12 +709,12 @@ private extension ReaderAPICaller { let idHexString = String(format: "%.16llx", intValue) return "i=tag:google.com,2005:reader/item/\(idHexString)" } - }).joined(separator:"&") - + }).joined(separator: "&") + let actionIndicator = add ? "a" : "r" - + let postData = "T=\(token)&\(idsToFetch)&\(actionIndicator)=\(state.rawValue)".data(using: String.Encoding.utf8) - + self.transport.send(request: request, method: HTTPMethod.post, payload: postData!, completion: { (result) in switch result { case .success: @@ -736,13 +723,11 @@ private extension ReaderAPICaller { completion(.failure(error)) } }) - - + case .failure(let error): completion(.failure(error)) } } } - }