Implement revised retention policy for feed-based accounts. Keep all articles currently in the feed and all articles in the last 30 days.
This commit is contained in:
parent
f00df4a8e9
commit
c55d8c540e
|
@ -1248,32 +1248,41 @@ private extension Account {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendNotificationAbout(_ newAndUpdatedArticles: NewAndUpdatedArticles) {
|
func sendNotificationAbout(_ articleChanges: ArticleChanges) {
|
||||||
var webFeeds = Set<WebFeed>()
|
var webFeeds = Set<WebFeed>()
|
||||||
|
|
||||||
if let newArticles = newAndUpdatedArticles.newArticles {
|
if let newArticles = articleChanges.newArticles {
|
||||||
webFeeds.formUnion(Set(newArticles.compactMap { $0.webFeed }))
|
webFeeds.formUnion(Set(newArticles.compactMap { $0.webFeed }))
|
||||||
}
|
}
|
||||||
if let updatedArticles = newAndUpdatedArticles.updatedArticles {
|
if let updatedArticles = articleChanges.updatedArticles {
|
||||||
webFeeds.formUnion(Set(updatedArticles.compactMap { $0.webFeed }))
|
webFeeds.formUnion(Set(updatedArticles.compactMap { $0.webFeed }))
|
||||||
}
|
}
|
||||||
|
|
||||||
var shouldSendNotification = false
|
var shouldSendNotification = false
|
||||||
|
var shouldUpdateUnreadCounts = false
|
||||||
var userInfo = [String: Any]()
|
var userInfo = [String: Any]()
|
||||||
|
|
||||||
if let newArticles = newAndUpdatedArticles.newArticles, !newArticles.isEmpty {
|
if let newArticles = articleChanges.newArticles, !newArticles.isEmpty {
|
||||||
shouldSendNotification = true
|
shouldSendNotification = true
|
||||||
|
shouldUpdateUnreadCounts = true
|
||||||
userInfo[UserInfoKey.newArticles] = newArticles
|
userInfo[UserInfoKey.newArticles] = newArticles
|
||||||
|
}
|
||||||
|
|
||||||
|
if let updatedArticles = articleChanges.updatedArticles, !updatedArticles.isEmpty {
|
||||||
|
shouldSendNotification = true
|
||||||
|
userInfo[UserInfoKey.updatedArticles] = updatedArticles
|
||||||
|
}
|
||||||
|
|
||||||
|
if let deletedArticles = articleChanges.deletedArticles, !deletedArticles.isEmpty {
|
||||||
|
shouldUpdateUnreadCounts = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if shouldUpdateUnreadCounts {
|
||||||
self.updateUnreadCounts(for: webFeeds) {
|
self.updateUnreadCounts(for: webFeeds) {
|
||||||
NotificationCenter.default.post(name: .DownloadArticlesDidUpdateUnreadCounts, object: self, userInfo: nil)
|
NotificationCenter.default.post(name: .DownloadArticlesDidUpdateUnreadCounts, object: self, userInfo: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let updatedArticles = newAndUpdatedArticles.updatedArticles, !updatedArticles.isEmpty {
|
|
||||||
shouldSendNotification = true
|
|
||||||
userInfo[UserInfoKey.updatedArticles] = updatedArticles
|
|
||||||
}
|
|
||||||
|
|
||||||
if shouldSendNotification {
|
if shouldSendNotification {
|
||||||
userInfo[UserInfoKey.webFeeds] = webFeeds
|
userInfo[UserInfoKey.webFeeds] = webFeeds
|
||||||
NotificationCenter.default.post(name: .AccountDidDownloadArticles, object: self, userInfo: userInfo)
|
NotificationCenter.default.post(name: .AccountDidDownloadArticles, object: self, userInfo: userInfo)
|
||||||
|
|
|
@ -24,12 +24,13 @@ public typealias UnreadCountDictionaryCompletionBlock = (UnreadCountDictionaryCo
|
||||||
public typealias SingleUnreadCountResult = Result<Int, DatabaseError>
|
public typealias SingleUnreadCountResult = Result<Int, DatabaseError>
|
||||||
public typealias SingleUnreadCountCompletionBlock = (SingleUnreadCountResult) -> Void
|
public typealias SingleUnreadCountCompletionBlock = (SingleUnreadCountResult) -> Void
|
||||||
|
|
||||||
public struct NewAndUpdatedArticles {
|
public struct ArticleChanges {
|
||||||
public let newArticles: Set<Article>?
|
public let newArticles: Set<Article>?
|
||||||
public let updatedArticles: Set<Article>?
|
public let updatedArticles: Set<Article>?
|
||||||
|
public let deletedArticles: Set<Article>?
|
||||||
}
|
}
|
||||||
|
|
||||||
public typealias UpdateArticlesResult = Result<NewAndUpdatedArticles, DatabaseError>
|
public typealias UpdateArticlesResult = Result<ArticleChanges, DatabaseError>
|
||||||
public typealias UpdateArticlesCompletionBlock = (UpdateArticlesResult) -> Void
|
public typealias UpdateArticlesCompletionBlock = (UpdateArticlesResult) -> Void
|
||||||
|
|
||||||
public typealias ArticleSetResult = Result<Set<Article>, DatabaseError>
|
public typealias ArticleSetResult = Result<Set<Article>, DatabaseError>
|
||||||
|
|
|
@ -175,7 +175,7 @@ final class ArticlesTable: DatabaseTable {
|
||||||
func update(_ parsedItems: Set<ParsedItem>, _ webFeedID: String, _ completion: @escaping UpdateArticlesCompletionBlock) {
|
func update(_ parsedItems: Set<ParsedItem>, _ webFeedID: String, _ completion: @escaping UpdateArticlesCompletionBlock) {
|
||||||
precondition(retentionStyle == .feedBased)
|
precondition(retentionStyle == .feedBased)
|
||||||
if parsedItems.isEmpty {
|
if parsedItems.isEmpty {
|
||||||
callUpdateArticlesCompletionBlock(nil, nil, completion)
|
callUpdateArticlesCompletionBlock(nil, nil, nil, completion)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ final class ArticlesTable: DatabaseTable {
|
||||||
|
|
||||||
let incomingArticles = Article.articlesWithParsedItems(parsedItems, webFeedID, self.accountID, statusesDictionary) //2
|
let incomingArticles = Article.articlesWithParsedItems(parsedItems, webFeedID, self.accountID, statusesDictionary) //2
|
||||||
if incomingArticles.isEmpty {
|
if incomingArticles.isEmpty {
|
||||||
self.callUpdateArticlesCompletionBlock(nil, nil, completion)
|
self.callUpdateArticlesCompletionBlock(nil, nil, nil, completion)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,13 +209,19 @@ final class ArticlesTable: DatabaseTable {
|
||||||
let newArticles = self.findAndSaveNewArticles(incomingArticles, fetchedArticlesDictionary, database) //5
|
let newArticles = self.findAndSaveNewArticles(incomingArticles, fetchedArticlesDictionary, database) //5
|
||||||
let updatedArticles = self.findAndSaveUpdatedArticles(incomingArticles, fetchedArticlesDictionary, database) //6
|
let updatedArticles = self.findAndSaveUpdatedArticles(incomingArticles, fetchedArticlesDictionary, database) //6
|
||||||
|
|
||||||
self.callUpdateArticlesCompletionBlock(newArticles, updatedArticles, completion) //7
|
// Articles to delete are 1) no longer in feed and 2) older than 30 days.
|
||||||
|
let cutoffDate = Date().bySubtracting(days: 30)
|
||||||
|
let articlesToDelete = fetchedArticles.filter { (article) -> Bool in
|
||||||
|
return article.status.dateArrived < cutoffDate && !articleIDs.contains(article.articleID)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.callUpdateArticlesCompletionBlock(newArticles, updatedArticles, articlesToDelete, completion) //7
|
||||||
|
|
||||||
self.addArticlesToCache(newArticles)
|
self.addArticlesToCache(newArticles)
|
||||||
self.addArticlesToCache(updatedArticles)
|
self.addArticlesToCache(updatedArticles)
|
||||||
|
|
||||||
// 8. Delete articles no longer in feed.
|
// 8. Delete articles no longer in feed.
|
||||||
let articleIDsToDelete = fetchedArticles.articleIDs().filter { !(articleIDs.contains($0)) }
|
let articleIDsToDelete = articlesToDelete.articleIDs()
|
||||||
if !articleIDsToDelete.isEmpty {
|
if !articleIDsToDelete.isEmpty {
|
||||||
self.removeArticles(articleIDsToDelete, database)
|
self.removeArticles(articleIDsToDelete, database)
|
||||||
self.removeArticleIDsFromCache(articleIDsToDelete)
|
self.removeArticleIDsFromCache(articleIDsToDelete)
|
||||||
|
@ -244,7 +250,7 @@ final class ArticlesTable: DatabaseTable {
|
||||||
func update(_ webFeedIDsAndItems: [String: Set<ParsedItem>], _ read: Bool, _ completion: @escaping UpdateArticlesCompletionBlock) {
|
func update(_ webFeedIDsAndItems: [String: Set<ParsedItem>], _ read: Bool, _ completion: @escaping UpdateArticlesCompletionBlock) {
|
||||||
precondition(retentionStyle == .syncSystem)
|
precondition(retentionStyle == .syncSystem)
|
||||||
if webFeedIDsAndItems.isEmpty {
|
if webFeedIDsAndItems.isEmpty {
|
||||||
callUpdateArticlesCompletionBlock(nil, nil, completion)
|
callUpdateArticlesCompletionBlock(nil, nil, nil, completion)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,13 +276,13 @@ final class ArticlesTable: DatabaseTable {
|
||||||
|
|
||||||
let allIncomingArticles = Article.articlesWithWebFeedIDsAndItems(webFeedIDsAndItems, self.accountID, statusesDictionary) //2
|
let allIncomingArticles = Article.articlesWithWebFeedIDsAndItems(webFeedIDsAndItems, self.accountID, statusesDictionary) //2
|
||||||
if allIncomingArticles.isEmpty {
|
if allIncomingArticles.isEmpty {
|
||||||
self.callUpdateArticlesCompletionBlock(nil, nil, completion)
|
self.callUpdateArticlesCompletionBlock(nil, nil, nil, completion)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let incomingArticles = self.filterIncomingArticles(allIncomingArticles) //3
|
let incomingArticles = self.filterIncomingArticles(allIncomingArticles) //3
|
||||||
if incomingArticles.isEmpty {
|
if incomingArticles.isEmpty {
|
||||||
self.callUpdateArticlesCompletionBlock(nil, nil, completion)
|
self.callUpdateArticlesCompletionBlock(nil, nil, nil, completion)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,7 +293,7 @@ final class ArticlesTable: DatabaseTable {
|
||||||
let newArticles = self.findAndSaveNewArticles(incomingArticles, fetchedArticlesDictionary, database) //5
|
let newArticles = self.findAndSaveNewArticles(incomingArticles, fetchedArticlesDictionary, database) //5
|
||||||
let updatedArticles = self.findAndSaveUpdatedArticles(incomingArticles, fetchedArticlesDictionary, database) //6
|
let updatedArticles = self.findAndSaveUpdatedArticles(incomingArticles, fetchedArticlesDictionary, database) //6
|
||||||
|
|
||||||
self.callUpdateArticlesCompletionBlock(newArticles, updatedArticles, completion) //7
|
self.callUpdateArticlesCompletionBlock(newArticles, updatedArticles, nil, completion) //7
|
||||||
|
|
||||||
self.addArticlesToCache(newArticles)
|
self.addArticlesToCache(newArticles)
|
||||||
self.addArticlesToCache(updatedArticles)
|
self.addArticlesToCache(updatedArticles)
|
||||||
|
@ -849,10 +855,10 @@ private extension ArticlesTable {
|
||||||
|
|
||||||
// MARK: - Saving Parsed Items
|
// MARK: - Saving Parsed Items
|
||||||
|
|
||||||
func callUpdateArticlesCompletionBlock(_ newArticles: Set<Article>?, _ updatedArticles: Set<Article>?, _ completion: @escaping UpdateArticlesCompletionBlock) {
|
func callUpdateArticlesCompletionBlock(_ newArticles: Set<Article>?, _ updatedArticles: Set<Article>?, _ deletedArticles: Set<Article>?, _ completion: @escaping UpdateArticlesCompletionBlock) {
|
||||||
let newAndUpdatedArticles = NewAndUpdatedArticles(newArticles: newArticles, updatedArticles: updatedArticles)
|
let articleChanges = ArticleChanges(newArticles: newArticles, updatedArticles: updatedArticles, deletedArticles: deletedArticles)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
completion(.success(newAndUpdatedArticles))
|
completion(.success(articleChanges))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue