diff --git a/Frameworks/Account/CloudKit/CloudKitArticlesZone.swift b/Frameworks/Account/CloudKit/CloudKitArticlesZone.swift index 350807d7b..6efe26fd0 100644 --- a/Frameworks/Account/CloudKit/CloudKitArticlesZone.swift +++ b/Frameworks/Account/CloudKit/CloudKitArticlesZone.swift @@ -41,19 +41,7 @@ final class CloudKitArticlesZone: CloudKitZone { static let imageURL = "imageURL" static let datePublished = "datePublished" static let dateModified = "dateModified" - static let authors = "authors" - } - } - - struct CloudKitAuthor { - static let recordType = "Author" - struct Fields { - static let article = "article" - static let authorID = "authorID" - static let name = "name" - static let url = "url" - static let avatarURL = "avatarURL" - static let emailAddress = "emailAddress" + static let parsedAuthors = "parsedAuthors" } } @@ -84,47 +72,6 @@ final class CloudKitArticlesZone: CloudKitZone { } } - func fetchArticle(articleID: String, completion: @escaping ((Result<(String, ParsedItem), Error>) -> Void)) { - - let statusRecordID = CKRecord.ID(recordName: articleID, zoneID: Self.zoneID) - let statusRecordRef = CKRecord.Reference(recordID: statusRecordID, action: .deleteSelf) - let predicate = NSPredicate(format: "articleStatus = %@", statusRecordRef) - let ckQuery = CKQuery(recordType: CloudKitArticle.recordType, predicate: predicate) - - query(ckQuery) { result in - - switch result { - case .success(let articleRecords): - if articleRecords.count == 1 { - let articleRecord = articleRecords[0] - - let articleRef = CKRecord.Reference(record: articleRecord, action: .deleteSelf) - let predicate = NSPredicate(format: "article = %@", articleRef) - let ckQuery = CKQuery(recordType: CloudKitAuthor.recordType, predicate: predicate) - - self.query(ckQuery) { result in - switch result { - case .success(let authorRecords): - if let webFeedID = articleRecord[CloudKitArticle.Fields.webFeedID] as? String, let parsedItem = self.makeParsedItem(articleRecord, authorRecords) { - completion(.success((webFeedID, parsedItem))) - } else { - completion(.failure(CloudKitZoneError.unknown)) - } - case .failure(let error): - completion(.failure(error)) - } - } - - } else { - completion(.failure(CloudKitZoneError.unknown)) - } - case .failure(let error): - completion(.failure(error)) - } - } - - } - } private extension CloudKitArticlesZone { @@ -210,58 +157,26 @@ private extension CloudKitArticlesZone { articleRecord[CloudKitArticle.Fields.datePublished] = article.datePublished articleRecord[CloudKitArticle.Fields.dateModified] = article.dateModified - records.append(articleRecord) + let encoder = JSONEncoder() + var parsedAuthors = [String]() if let authors = article.authors { for author in authors { - let authorRecord = CKRecord(recordType: CloudKitAuthor.recordType, recordID: generateRecordID()) - authorRecord[CloudKitAuthor.Fields.article] = CKRecord.Reference(record: articleRecord, action: .deleteSelf) - authorRecord[CloudKitAuthor.Fields.authorID] = author.authorID - authorRecord[CloudKitAuthor.Fields.name] = author.name - authorRecord[CloudKitAuthor.Fields.url] = author.url - authorRecord[CloudKitAuthor.Fields.avatarURL] = author.avatarURL - authorRecord[CloudKitAuthor.Fields.emailAddress] = author.emailAddress - records.append(authorRecord) + let parsedAuthor = ParsedAuthor(name: author.name, + url: author.url, + avatarURL: author.avatarURL, + emailAddress: author.emailAddress) + if let data = try? encoder.encode(parsedAuthor), let encodedParsedAuthor = String(data: data, encoding: .utf8) { + parsedAuthors.append(encodedParsedAuthor) + } } } + articleRecord[CloudKitArticle.Fields.parsedAuthors] = parsedAuthors + + records.append(articleRecord) return records } - - func makeParsedItem(_ articleRecord: CKRecord, _ authorRecords: [CKRecord]) -> ParsedItem? { - var parsedAuthors = Set() - - for authorRecord in authorRecords { - let parsedAuthor = ParsedAuthor(name: authorRecord[CloudKitAuthor.Fields.name] as? String, - url: authorRecord[CloudKitAuthor.Fields.url] as? String, - avatarURL: authorRecord[CloudKitAuthor.Fields.avatarURL] as? String, - emailAddress: authorRecord[CloudKitAuthor.Fields.emailAddress] as? String) - parsedAuthors.insert(parsedAuthor) - } - - guard let uniqueID = articleRecord[CloudKitArticle.Fields.uniqueID] as? String, - let feedURL = articleRecord[CloudKitArticle.Fields.webFeedID] as? String else { - return nil - } - - let parsedItem = ParsedItem(syncServiceID: nil, - uniqueID: uniqueID, - feedURL: feedURL, - url: articleRecord[CloudKitArticle.Fields.url] as? String, - externalURL: articleRecord[CloudKitArticle.Fields.externalURL] as? String, - title: articleRecord[CloudKitArticle.Fields.title] as? String, - contentHTML: articleRecord[CloudKitArticle.Fields.contentHTML] as? String, - contentText: articleRecord[CloudKitArticle.Fields.contentText] as? String, - summary: articleRecord[CloudKitArticle.Fields.summary] as? String, - imageURL: articleRecord[CloudKitArticle.Fields.imageURL] as? String, - bannerImageURL: articleRecord[CloudKitArticle.Fields.imageURL] as? String, - datePublished: articleRecord[CloudKitArticle.Fields.datePublished] as? Date, - dateModified: articleRecord[CloudKitArticle.Fields.dateModified] as? Date, - authors: parsedAuthors, - tags: nil, - attachments: nil) - - return parsedItem - } + } diff --git a/Frameworks/Account/CloudKit/CloudKitArticlesZoneDelegate.swift b/Frameworks/Account/CloudKit/CloudKitArticlesZoneDelegate.swift index 528916b62..8cab47869 100644 --- a/Frameworks/Account/CloudKit/CloudKitArticlesZoneDelegate.swift +++ b/Frameworks/Account/CloudKit/CloudKitArticlesZoneDelegate.swift @@ -8,6 +8,7 @@ import Foundation import os.log +import RSParser import CloudKit import SyncDatabase @@ -26,7 +27,7 @@ class CloudKitArticlesZoneDelegate: CloudKitZoneDelegate { } func cloudKitDidChange(record: CKRecord) { - // Process everything in the batch method + } func cloudKitDidDelete(recordKey: CloudKitRecordKey) { @@ -65,12 +66,14 @@ class CloudKitArticlesZoneDelegate: CloudKitZoneDelegate { private extension CloudKitArticlesZoneDelegate { func process(records: [CKRecord], pendingReadStatusArticleIDs: Set, pendingStarredStatusArticleIDs: Set, completion: @escaping (Result) -> Void) { - - let receivedUnreadArticleIDs = Set(records.filter( { $0[CloudKitArticlesZone.CloudKitArticleStatus.Fields.read] == "0" }).map({ $0.externalID })) - let receivedReadArticleIDs = Set(records.filter( { $0[CloudKitArticlesZone.CloudKitArticleStatus.Fields.read] == "1" }).map({ $0.externalID })) - let receivedUnstarredArticleIDs = Set(records.filter( { $0[CloudKitArticlesZone.CloudKitArticleStatus.Fields.starred] == "0" }).map({ $0.externalID })) - let receivedStarredArticleIDs = Set(records.filter( { $0[CloudKitArticlesZone.CloudKitArticleStatus.Fields.starred] == "1" }).map({ $0.externalID })) + let receivedUnreadArticleIDs = Set(records.filter({ $0[CloudKitArticlesZone.CloudKitArticleStatus.Fields.read] == "0" }).map({ $0.externalID })) + let receivedReadArticleIDs = Set(records.filter({ $0[CloudKitArticlesZone.CloudKitArticleStatus.Fields.read] == "1" }).map({ $0.externalID })) + let receivedUnstarredArticleIDs = Set(records.filter({ $0[CloudKitArticlesZone.CloudKitArticleStatus.Fields.starred] == "0" }).map({ $0.externalID })) + let receivedStarredArticleIDs = Set(records.filter({ $0[CloudKitArticlesZone.CloudKitArticleStatus.Fields.starred] == "1" }).map({ $0.externalID })) + + let receivedStarredArticles = records.filter({ $0.recordType == CloudKitArticlesZone.CloudKitArticle.recordType }) + let updateableUnreadArticleIDs = receivedUnreadArticleIDs.subtracting(pendingReadStatusArticleIDs) let updateableReadArticleIDs = receivedReadArticleIDs.subtracting(pendingReadStatusArticleIDs) let updateableUnstarredArticleIDs = receivedUnstarredArticleIDs.subtracting(pendingStarredStatusArticleIDs) @@ -98,23 +101,15 @@ private extension CloudKitArticlesZoneDelegate { group.leave() } - for updateableStarredArticleID in updateableStarredArticleIDs { - - group.enter() - articlesZone?.fetchArticle(articleID: updateableStarredArticleID) { result in - switch result { - case .success(let (webFeedID, parsedItem)): - self.account?.update(webFeedID, with: Set([parsedItem])) { databaseError in - group.leave() - if let databaseError = databaseError { - os_log(.error, log: self.log, "Error occurred while storing starred items: %@", databaseError.localizedDescription) - } - } - case .failure(let error): + for receivedStarredArticle in receivedStarredArticles { + if let parsedItem = makeParsedItem(receivedStarredArticle), let statusRef = receivedStarredArticle[CloudKitArticlesZone.CloudKitArticle.Fields.articleStatus] as? CKRecord.Reference { + group.enter() + self.account?.update(statusRef.recordID.externalID, with: Set([parsedItem])) { databaseError in group.leave() - os_log(.error, log: self.log, "Error occurred while retrieving starred items: %@", error.localizedDescription) + if let databaseError = databaseError { + os_log(.error, log: self.log, "Error occurred while storing starred items: %@", databaseError.localizedDescription) + } } - } } @@ -123,5 +118,44 @@ private extension CloudKitArticlesZoneDelegate { } } + + + func makeParsedItem(_ articleRecord: CKRecord) -> ParsedItem? { + var parsedAuthors = Set() + + let decoder = JSONDecoder() + + if let encodedParsedAuthors = articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.parsedAuthors] as? [String] { + for encodedParsedAuthor in encodedParsedAuthors { + if let data = encodedParsedAuthor.data(using: .utf8), let parsedAuthor = try? decoder.decode(ParsedAuthor.self, from: data) { + parsedAuthors.insert(parsedAuthor) + } + } + } + + guard let uniqueID = articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.uniqueID] as? String, + let feedURL = articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.webFeedID] as? String else { + return nil + } + + let parsedItem = ParsedItem(syncServiceID: nil, + uniqueID: uniqueID, + feedURL: feedURL, + url: articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.url] as? String, + externalURL: articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.externalURL] as? String, + title: articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.title] as? String, + contentHTML: articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.contentHTML] as? String, + contentText: articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.contentText] as? String, + summary: articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.summary] as? String, + imageURL: articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.imageURL] as? String, + bannerImageURL: articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.imageURL] as? String, + datePublished: articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.datePublished] as? Date, + dateModified: articleRecord[CloudKitArticlesZone.CloudKitArticle.Fields.dateModified] as? Date, + authors: parsedAuthors, + tags: nil, + attachments: nil) + + return parsedItem + } } diff --git a/submodules/RSParser b/submodules/RSParser index 47ba87875..a977d8e84 160000 --- a/submodules/RSParser +++ b/submodules/RSParser @@ -1 +1 @@ -Subproject commit 47ba87875fbd026dccc2c4d4382a98cb4a1f1fbc +Subproject commit a977d8e84af8645fc8268ac843e8a79b3644b133