Merge pull request #3227 from dave-atx/greader

ReaderAPI Account Changes
This commit is contained in:
Maurice Parker 2021-07-21 16:35:33 -05:00 committed by GitHub
commit 185b4cd28e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 61 additions and 147 deletions

View File

@ -473,10 +473,23 @@ final class ReaderAPIAccountDelegate: AccountDelegate {
if from is Account { if from is Account {
addWebFeed(for: account, with: feed, to: to, completion: completion) addWebFeed(for: account, with: feed, to: to, completion: completion)
} else { } else {
deleteTagging(for: account, with: feed, from: from) { result in guard
let subscriptionId = feed.externalID,
let fromTag = (from as? Folder)?.name,
let toTag = (to as? Folder)?.name
else {
completion(.failure(ReaderAPIAccountDelegateError.invalidParameter))
return
}
refreshProgress.addToNumberOfTasksAndRemaining(1)
caller.moveSubscription(subscriptionID: subscriptionId, fromTag: fromTag, toTag: toTag) { result in
self.refreshProgress.completeTask()
switch result { switch result {
case .success: case .success:
self.addWebFeed(for: account, with: feed, to: to, completion: completion) from.removeWebFeed(feed)
to.addWebFeed(feed)
completion(.success(()))
case .failure(let error): case .failure(let error):
completion(.failure(error)) completion(.failure(error))
} }
@ -1008,8 +1021,13 @@ private extension ReaderAPIAccountDelegate {
guard let streamID = entry.origin.streamId else { guard let streamID = entry.origin.streamId else {
return nil return nil
} }
// let authors = Set([ParsedAuthor(name: entry.authorName, url: entry.jsonFeed?.jsonFeedAuthor?.url, avatarURL: entry.jsonFeed?.jsonFeedAuthor?.avatarURL, emailAddress: nil)])
// let feed = account.idToFeedDictionary[entry.origin.streamId!]! // TODO clean this up var authors: Set<ParsedAuthor>? {
guard let name = entry.author else {
return nil
}
return Set([ParsedAuthor(name: name, url: nil, avatarURL: nil, emailAddress: nil)])
}
return ParsedItem(syncServiceID: entry.uniqueID(variant: variant), return ParsedItem(syncServiceID: entry.uniqueID(variant: variant),
uniqueID: entry.uniqueID(variant: variant), uniqueID: entry.uniqueID(variant: variant),
@ -1025,7 +1043,7 @@ private extension ReaderAPIAccountDelegate {
bannerImageURL: nil, bannerImageURL: nil,
datePublished: entry.parseDatePublished(), datePublished: entry.parseDatePublished(),
dateModified: nil, dateModified: nil,
authors: nil, authors: authors,
tags: nil, tags: nil,
attachments: nil) attachments: nil)
} }
@ -1132,32 +1150,4 @@ private extension ReaderAPIAccountDelegate {
} }
func deleteTagging(for account: Account, with feed: WebFeed, from container: Container?, completion: @escaping (Result<Void, Error>) -> Void) {
if let folder = container as? Folder, let feedName = feed.externalID {
caller.deleteTagging(subscriptionID: feedName, tagName: folder.name ?? "") { result in
switch result {
case .success:
DispatchQueue.main.async {
self.clearFolderRelationship(for: feed, folderExternalID: folder.externalID)
folder.removeWebFeed(feed)
account.addFeedIfNotInAnyFolder(feed)
completion(.success(()))
}
case .failure(let error):
DispatchQueue.main.async {
let wrappedError = AccountError.wrappedError(error: error, account: account)
completion(.failure(wrappedError))
}
}
}
} else {
if let account = container as? Account {
account.removeWebFeed(feed)
}
completion(.success(()))
}
}
} }

View File

@ -358,21 +358,19 @@ final class ReaderAPICaller: NSObject {
self.requestAuthorizationToken(endpoint: baseURL) { (result) in self.requestAuthorizationToken(endpoint: baseURL) { (result) in
switch result { switch result {
case .success(let token): case .success(let token):
let url = baseURL let callURL = baseURL
.appendingPathComponent(ReaderAPIEndpoints.subscriptionAdd.rawValue) .appendingPathComponent(ReaderAPIEndpoints.subscriptionAdd.rawValue)
.appendingQueryItem(URLQueryItem(name: "quickadd", value: url))
guard let callURL = url else {
completion(.failure(TransportError.noURL))
return
}
var request = URLRequest(url: callURL, credentials: self.credentials) var request = URLRequest(url: callURL, credentials: self.credentials)
self.addVariantHeaders(&request) self.addVariantHeaders(&request)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST" request.httpMethod = "POST"
let postData = "T=\(token)".data(using: String.Encoding.utf8) guard let encodedFeedURL = self.encodeForURLPath(url) else {
completion(.failure(ReaderAPIAccountDelegateError.invalidParameter))
return
}
let postData = "T=\(token)&quickadd=\(encodedFeedURL)".data(using: String.Encoding.utf8)
self.transport.send(request: request, method: HTTPMethod.post, data: postData!, resultType: ReaderAPIQuickAddResult.self, completion: { (result) in self.transport.send(request: request, method: HTTPMethod.post, data: postData!, resultType: ReaderAPIQuickAddResult.self, completion: { (result) in
switch result { switch result {
@ -387,34 +385,7 @@ final class ReaderAPICaller: NSObject {
return return
} }
if name == nil && folder == nil {
findSubscription(streamID: streamId, completion: completion) findSubscription(streamID: streamId, completion: completion)
} else {
let callURL = baseURL.appendingPathComponent(ReaderAPIEndpoints.subscriptionEdit.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"
var postString = "T=\(token)&ac=subscribe&s=\(streamId)"
if let folderName = self.encodeForURLPath(folder?.nameForDisplay) {
postString += "&a=user/-/label/\(folderName)"
}
if let name = self.encodeForURLPath(name) {
postString += "&t=\(name)"
}
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:
findSubscription(streamID: streamId, completion: completion)
case .failure:
completion(.failure(AccountError.createErrorAlreadySubscribed))
}
})
}
} }
case .failure(let error): case .failure(let error):
@ -432,42 +403,7 @@ final class ReaderAPICaller: NSObject {
} }
func renameSubscription(subscriptionID: String, newName: String, completion: @escaping (Result<Void, Error>) -> Void) { func renameSubscription(subscriptionID: String, newName: String, completion: @escaping (Result<Void, Error>) -> Void) {
guard let baseURL = apiBaseURL else { changeSubscription(subscriptionID: subscriptionID, title: newName, completion: completion)
completion(.failure(CredentialsError.incompleteCredentials))
return
}
self.requestAuthorizationToken(endpoint: baseURL) { (result) in
switch result {
case .success(let token):
var request = URLRequest(url: baseURL.appendingPathComponent(ReaderAPIEndpoints.subscriptionEdit.rawValue), credentials: self.credentials)
self.addVariantHeaders(&request)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
guard let encodedNewName = self.encodeForURLPath(newName) else {
completion(.failure(ReaderAPIAccountDelegateError.invalidParameter))
return
}
let postData = "T=\(token)&s=\(subscriptionID)&ac=edit&t=\(encodedNewName)".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):
completion(.failure(error))
break
}
})
case .failure(let error):
completion(.failure(error))
}
}
} }
func deleteSubscription(subscriptionID: String, completion: @escaping (Result<Void, Error>) -> Void) { func deleteSubscription(subscriptionID: String, completion: @escaping (Result<Void, Error>) -> Void) {
@ -504,46 +440,23 @@ final class ReaderAPICaller: NSObject {
} }
func createTagging(subscriptionID: String, tagName: String, completion: @escaping (Result<Void, Error>) -> Void) { func createTagging(subscriptionID: String, tagName: String, completion: @escaping (Result<Void, Error>) -> Void) {
changeSubscription(subscriptionID: subscriptionID, addTagName: tagName, completion: completion)
guard let baseURL = apiBaseURL else {
completion(.failure(CredentialsError.incompleteCredentials))
return
} }
self.requestAuthorizationToken(endpoint: baseURL) { (result) in func deleteTagging(subscriptionID: String, tagName: String, completion: @escaping (Result<Void, Error>) -> Void) {
switch result { changeSubscription(subscriptionID: subscriptionID, removeTagName: tagName, completion: completion)
case .success(let token): }
var request = URLRequest(url: baseURL.appendingPathComponent(ReaderAPIEndpoints.subscriptionEdit.rawValue), credentials: self.credentials)
self.addVariantHeaders(&request)
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST"
guard let tagName = self.encodeForURLPath(tagName) else { func moveSubscription(subscriptionID: String, fromTag: String, toTag: String, completion: @escaping (Result<Void, Error>) -> 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, Error>) -> Void) {
guard removeTagName != nil || addTagName != nil || title != nil else {
completion(.failure(ReaderAPIAccountDelegateError.invalidParameter)) completion(.failure(ReaderAPIAccountDelegateError.invalidParameter))
return return
} }
let postData = "T=\(token)&s=\(subscriptionID)&ac=edit&a=user/-/label/\(tagName)".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):
completion(.failure(error))
break
}
})
case .failure(let error):
completion(.failure(error))
}
}
}
func deleteTagging(subscriptionID: String, tagName: String, completion: @escaping (Result<Void, Error>) -> Void) {
guard let baseURL = apiBaseURL else { guard let baseURL = apiBaseURL else {
completion(.failure(CredentialsError.incompleteCredentials)) completion(.failure(CredentialsError.incompleteCredentials))
return return
@ -557,8 +470,17 @@ final class ReaderAPICaller: NSObject {
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpMethod = "POST" request.httpMethod = "POST"
let tagName = "user/-/label/\(tagName)" var postString = "T=\(token)&s=\(subscriptionID)&ac=edit"
let postData = "T=\(token)&s=\(subscriptionID)&ac=edit&r=\(tagName)".data(using: String.Encoding.utf8) if let fromLabel = self.encodeForURLPath(removeTagName) {
postString += "&r=user/-/label/\(fromLabel)"
}
if let toLabel = self.encodeForURLPath(addTagName) {
postString += "&a=user/-/label/\(toLabel)"
}
if let encodedTitle = self.encodeForURLPath(title) {
postString += "&t=\(encodedTitle)"
}
let postData = postString.data(using: String.Encoding.utf8)
self.transport.send(request: request, method: HTTPMethod.post, payload: postData!, completion: { (result) in self.transport.send(request: request, method: HTTPMethod.post, payload: postData!, completion: { (result) in
switch result { switch result {

View File

@ -51,6 +51,7 @@ struct ReaderAPIEntry: Codable {
let articleID: String let articleID: String
let title: String? let title: String?
let author: String?
let publishedTimestamp: Double? let publishedTimestamp: Double?
let crawledTimestamp: String? let crawledTimestamp: String?
@ -64,6 +65,7 @@ struct ReaderAPIEntry: Codable {
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {
case articleID = "id" case articleID = "id"
case title = "title" case title = "title"
case author = "author"
case summary = "summary" case summary = "summary"
case alternates = "alternate" case alternates = "alternate"
case categories = "categories" case categories = "categories"