Skip to content

Commit

Permalink
Merge pull request #4491 from wikimedia/T331902
Browse files Browse the repository at this point in the history
Clear out featured article widget cache if article data changed
  • Loading branch information
staykids authored Mar 17, 2023
2 parents 27183dc + abf44e5 commit aa7ab4f
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 22 deletions.
10 changes: 10 additions & 0 deletions WMF Framework/SharedContainerCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Foundation
@objc public class SharedContainerCacheCommonNames: NSObject {
@objc public static let pushNotificationsCache = "Push Notifications Cache"
@objc public static let talkPageCache = "Talk Page Cache"
public static let widgetCache = "Widget Cache"
}

public final class SharedContainerCache<T: Codable>: SharedContainerCacheHousekeepingProtocol {
Expand Down Expand Up @@ -81,3 +82,12 @@ public final class SharedContainerCache<T: Codable>: SharedContainerCacheHouseke
@objc public protocol SharedContainerCacheHousekeepingProtocol: AnyObject {
static func deleteStaleCachedItems(in subdirectoryPathComponent: String)
}

@objc public class SharedContainerCacheClearFeaturedArticleWrapper: NSObject {
@objc public static func clearOutFeaturedArticleWidgetCache() {
let sharedCache = SharedContainerCache<WidgetCache>(fileName: SharedContainerCacheCommonNames.widgetCache, defaultCache: { WidgetCache(settings: .default, featuredContent: nil) })
var updatedCache = sharedCache.loadCache()
updatedCache.featuredContent = nil
sharedCache.saveCache(updatedCache)
}
}
5 changes: 5 additions & 0 deletions WMF Framework/SummaryExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ extension WMFArticle {
imageWidth = NSNumber(value: 0)
imageHeight = NSNumber(value: 0)
}

if let thumbnail = summary.thumbnail {
thumbnailURLString = thumbnail.source
thumbnailURL = thumbnail.url
}

wikidataDescription = summary.articleDescription
wikidataID = summary.wikidataID
Expand Down
2 changes: 1 addition & 1 deletion WMF Framework/WMFArticle+Extensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ NS_ASSUME_NONNULL_BEGIN

- (nullable WMFArticle *)fetchOrCreateArticleWithURL:(nullable NSURL *)articleURL updatedWithSearchResult:(nullable MWKSearchResult *)searchResult;

- (nullable WMFArticle *)fetchOrCreateArticleWithURL:(nullable NSURL *)articleURL updatedWithFeedPreview:(nullable WMFFeedArticlePreview *)feedPreview pageViews:(nullable NSDictionary<NSDate *, NSNumber *> *)pageViews;
- (nullable WMFArticle *)fetchOrCreateArticleWithURL:(nullable NSURL *)articleURL updatedWithFeedPreview:(nullable WMFFeedArticlePreview *)feedPreview pageViews:(nullable NSDictionary<NSDate *, NSNumber *> *)pageViews isFeatured:(BOOL)isFeatured;

- (nullable WMFArticle *)fetchArticleWithWikidataID:(nullable NSString *)wikidataID;

Expand Down
38 changes: 24 additions & 14 deletions WMF Framework/WMFArticle+Extensions.m
Original file line number Diff line number Diff line change
Expand Up @@ -245,45 +245,55 @@ - (nullable WMFArticle *)fetchOrCreateArticleWithURL:(nullable NSURL *)articleUR
return article;
}

- (nullable WMFArticle *)fetchOrCreateArticleWithURL:(nullable NSURL *)articleURL updatedWithFeedPreview:(nullable WMFFeedArticlePreview *)feedPreview pageViews:(nullable NSDictionary<NSDate *, NSNumber *> *)pageViews {
- (nullable WMFArticle *)fetchOrCreateArticleWithURL:(nullable NSURL *)articleURL updatedWithFeedPreview:(nullable WMFFeedArticlePreview *)feedPreview pageViews:(nullable NSDictionary<NSDate *, NSNumber *> *)pageViews isFeatured:(BOOL)isFeatured {
NSParameterAssert(articleURL);
if (!articleURL) {
return nil;
}

WMFArticle *preview = [self fetchOrCreateArticleWithURL:articleURL];
WMFArticle *article = [self fetchOrCreateArticleWithURL:articleURL];

if (isFeatured) {
WMFFeedArticlePreview *oldFeedPreview = [article feedArticlePreview];
if (![oldFeedPreview isEqual:feedPreview]) {
[SharedContainerCacheClearFeaturedArticleWrapper clearOutFeaturedArticleWidgetCache];
}
}

if ([feedPreview.displayTitleHTML length] > 0) {
preview.displayTitleHTML = feedPreview.displayTitleHTML;
article.displayTitleHTML = feedPreview.displayTitleHTML;
} else if ([feedPreview.displayTitle length] > 0) {
preview.displayTitleHTML = feedPreview.displayTitle;
article.displayTitleHTML = feedPreview.displayTitle;
}

if ([feedPreview.wikidataDescription length] > 0) {
preview.wikidataDescription = feedPreview.wikidataDescription;
article.wikidataDescription = feedPreview.wikidataDescription;
}
if ([feedPreview.snippet length] > 0) {
preview.snippet = feedPreview.snippet;
article.snippet = feedPreview.snippet;
}
if (feedPreview.thumbnailURL != nil) {
preview.thumbnailURL = feedPreview.thumbnailURL;

article.thumbnailURL = feedPreview.thumbnailURL;
}
if (pageViews != nil) {
if (preview.pageViews == nil) {
preview.pageViews = pageViews;
if (article.pageViews == nil) {
article.pageViews = pageViews;
} else {
preview.pageViews = [preview.pageViews mtl_dictionaryByAddingEntriesFromDictionary:pageViews];
article.pageViews = [article.pageViews mtl_dictionaryByAddingEntriesFromDictionary:pageViews];
}
}
if (feedPreview.imageURLString != nil) {
preview.imageURLString = feedPreview.imageURLString;
article.imageURLString = feedPreview.imageURLString;
}
if (feedPreview.imageWidth != nil) {
preview.imageWidth = feedPreview.imageWidth;
article.imageWidth = feedPreview.imageWidth;
}
if (feedPreview.imageHeight != nil) {
preview.imageHeight = feedPreview.imageHeight;
article.imageHeight = feedPreview.imageHeight;
}
return preview;

return article;
}

@end
Expand Down
20 changes: 20 additions & 0 deletions WMF Framework/WMFArticle+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,24 @@ extension WMFArticle {
savedDate = newValue ? Date() : nil
}
}

@objc public func feedArticlePreview() -> WMFFeedArticlePreview? {

var dictionary: [AnyHashable: Any] = [
"displayTitle": displayTitle as Any,
"displayTitleHTML": displayTitleHTML,
"thumbnailURL": thumbnailURL as Any,
"imageURLString": imageURLString as Any,
"wikidataDescription": wikidataDescription as Any,
"snippet": snippet as Any,
"imageWidth": imageWidth as Any,
"imageHeight": imageHeight as Any
]

if let articleURLString = key?.decomposedStringWithCanonicalMapping {
dictionary["articleURL"] = URL(string: articleURLString)
}

return try? WMFFeedArticlePreview(dictionary: dictionary)
}
}
17 changes: 16 additions & 1 deletion WMF Framework/Widget/WidgetController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public final class WidgetController: NSObject {
// MARK: Properties

@objc public static let shared = WidgetController()
private let sharedCache = SharedContainerCache<WidgetCache>(fileName: "Widget Cache", defaultCache: { WidgetCache(settings: .default, featuredContent: nil) })
private let sharedCache = SharedContainerCache<WidgetCache>(fileName: SharedContainerCacheCommonNames.widgetCache, defaultCache: { WidgetCache(settings: .default, featuredContent: nil) })

// MARK: Public

Expand All @@ -40,6 +40,21 @@ public final class WidgetController: NSObject {
WidgetCenter.shared.reloadAllTimelines()
}

public func reloadFeaturedArticleWidgetIfNecessary() {
guard !Bundle.main.isAppExtension else {
return
}

let dataStore = MWKDataStore.shared()
let appLanguage = dataStore.languageLinkController.appLanguage
if let siteURL = appLanguage?.siteURL, let languageCode = appLanguage?.languageCode {
let updatedWidgetSettings = WidgetSettings(siteURL: siteURL, languageCode: languageCode, languageVariantCode: appLanguage?.languageVariantCode)
updateCacheWith(settings: updatedWidgetSettings)
}

WidgetCenter.shared.reloadTimelines(ofKind: SupportedWidget.featuredArticle.rawValue)
}

/// For requesting background time from widgets
/// - Parameter userCompletion: the completion block to call with the result
/// - Parameter task: block that takes the `MWKDataStore` to use for updates and the completion block to call when done as parameters
Expand Down
24 changes: 24 additions & 0 deletions Wikipedia/Code/ArticleViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -418,8 +418,14 @@ class ArticleViewController: ViewController, HintPresenting {
return
}

var oldFeedPreview: WMFFeedArticlePreview?
if isWidgetCachedFeaturedArticle {
oldFeedPreview = article.feedArticlePreview()
}

articleLoadWaitGroup?.enter()
let cachePolicy: URLRequest.CachePolicy? = oldState == .reloading ? .reloadRevalidatingCacheData : nil

self.dataStore.articleSummaryController.updateOrCreateArticleSummaryForArticle(withKey: key, cachePolicy: cachePolicy) { (article, error) in
defer {
self.articleLoadWaitGroup?.leave()
Expand All @@ -429,6 +435,14 @@ class ArticleViewController: ViewController, HintPresenting {
return
}
self.article = article

if let oldFeedPreview,
let newFeedPreview = article.feedArticlePreview(),
oldFeedPreview != newFeedPreview {
SharedContainerCacheClearFeaturedArticleWrapper.clearOutFeaturedArticleWidgetCache()
WidgetController.shared.reloadFeaturedArticleWidgetIfNecessary()
}

// Handle redirects
guard let newKey = article.inMemoryKey, newKey != key, let newURL = article.url else {
return
Expand Down Expand Up @@ -1024,6 +1038,16 @@ private extension ArticleViewController {
setToolbarHidden(false, animated: false)
}

var isWidgetCachedFeaturedArticle: Bool {
let sharedCache = SharedContainerCache<WidgetCache>(fileName: SharedContainerCacheCommonNames.widgetCache, defaultCache: { WidgetCache(settings: .default, featuredContent: nil) })
guard let widgetFeaturedArticleURLString = sharedCache.loadCache().featuredContent?.featuredArticle?.contentURL.desktop.page,
let widgetFeaturedArticleURL = URL(string: widgetFeaturedArticleURLString) else {
return false
}

return widgetFeaturedArticleURL == articleURL
}

}

extension ArticleViewController {
Expand Down
4 changes: 2 additions & 2 deletions Wikipedia/Code/HelpViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,11 @@ private extension HelpViewController {
urlsToRemove.append(temporaryAppContainerURL.appendingPathComponent("Event Logging"))
urlsToRemove.append(temporaryAppContainerURL.appendingPathComponent("Event Platform"))
urlsToRemove.append(temporaryAppContainerURL.appendingPathComponent("Library"))
urlsToRemove.append(temporaryAppContainerURL.appendingPathComponent("Push Notifications Cache").appendingPathExtension("json"))
urlsToRemove.append(temporaryAppContainerURL.appendingPathComponent(SharedContainerCacheCommonNames.pushNotificationsCache).appendingPathExtension("json"))
urlsToRemove.append(temporaryAppContainerURL.appendingPathComponent("RemoteNotifications").appendingPathExtension("sqlite"))
urlsToRemove.append(temporaryAppContainerURL.appendingPathComponent("RemoteNotifications").appendingPathExtension("sqlite-shm"))
urlsToRemove.append(temporaryAppContainerURL.appendingPathComponent("RemoteNotifications").appendingPathExtension("sqlite-wal"))
urlsToRemove.append(temporaryAppContainerURL.appendingPathComponent("Widget Cache").appendingPathExtension("json"))
urlsToRemove.append(temporaryAppContainerURL.appendingPathComponent(SharedContainerCacheCommonNames.widgetCache).appendingPathExtension("json"))
for url in urlsToRemove {
do {
try fileManager.removeItem(at: url)
Expand Down
6 changes: 3 additions & 3 deletions Wikipedia/Code/WMFFeedContentSource.m
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ - (void)saveGroupForFeaturedPreview:(WMFFeedArticlePreview *)preview date:(NSDat
return;
}

[moc fetchOrCreateArticleWithURL:featuredURL updatedWithFeedPreview:preview pageViews:nil];
[moc fetchOrCreateArticleWithURL:featuredURL updatedWithFeedPreview:preview pageViews:nil isFeatured:YES];

if (featured == nil) {
[moc createGroupOfKind:WMFContentGroupKindFeaturedArticle forDate:date withSiteURL:self.siteURL associatedContent:@[featuredURL]];
Expand All @@ -206,7 +206,7 @@ - (void)saveGroupForTopRead:(WMFFeedTopReadResponse *)topRead pageViews:(NSDicti

[topRead.articlePreviews enumerateObjectsUsingBlock:^(WMFFeedTopReadArticlePreview *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
NSURL *url = [obj articleURL];
[moc fetchOrCreateArticleWithURL:url updatedWithFeedPreview:obj pageViews:pageViews[url]];
[moc fetchOrCreateArticleWithURL:url updatedWithFeedPreview:obj pageViews:pageViews[url] isFeatured: NO];
}];

WMFContentGroup *group = [self topReadForDate:date inManagedObjectContext:moc];
Expand Down Expand Up @@ -289,7 +289,7 @@ - (void)saveGroupForNews:(NSArray<WMFFeedNewsStory *> *)news pageViews:(NSDictio
[story.articlePreviews enumerateObjectsUsingBlock:^(WMFFeedArticlePreview *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
NSURL *url = [obj articleURL];
NSDictionary<NSDate *, NSNumber *> *pageViewsForURL = pageViews[url];
[moc fetchOrCreateArticleWithURL:url updatedWithFeedPreview:obj pageViews:pageViewsForURL];
[moc fetchOrCreateArticleWithURL:url updatedWithFeedPreview:obj pageViews:pageViewsForURL isFeatured: NO];
}];

NSString *featuredArticleTitleBasedOnSemanticLookup = [WMFFeedNewsStory semanticFeaturedArticleTitleFromStoryHTML:story.storyHTML siteURL:self.siteURL];
Expand Down
2 changes: 1 addition & 1 deletion Wikipedia/Code/WMFOnThisDayContentSource.m
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ - (void)loadContentForDate:(NSDate *)date inManagedObjectContext:(NSManagedObjec
[moc performBlock:^{
[onThisDayEvents enumerateObjectsUsingBlock:^(WMFFeedOnThisDayEvent *_Nonnull event, NSUInteger idx, BOOL *_Nonnull stop) {
[event.articlePreviews enumerateObjectsUsingBlock:^(WMFFeedArticlePreview *_Nonnull articlePreview, NSUInteger idx, BOOL *_Nonnull stop) {
[moc fetchOrCreateArticleWithURL:[articlePreview articleURL] updatedWithFeedPreview:articlePreview pageViews:nil];
[moc fetchOrCreateArticleWithURL:[articlePreview articleURL] updatedWithFeedPreview:articlePreview pageViews:nil isFeatured:NO];
}];
event.score = [event calculateScore];
event.index = @(idx);
Expand Down

0 comments on commit aa7ab4f

Please sign in to comment.