Skip to content

Commit

Permalink
Merge pull request #2676 from wikimedia/bug/wikidata_api_en
Browse files Browse the repository at this point in the history
Show wikidata editor for non-local descriptions
  • Loading branch information
joewalsh committed Oct 12, 2018
2 parents d56362e + 211fed9 commit 600c5f5
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 63 deletions.
14 changes: 14 additions & 0 deletions WMF Framework/MWKArticle+Description.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Foundation

@objc public enum ArticleDescriptionSource: Int {
case none
case central
case local
}

extension MWKArticle {
public var descriptionSource: ArticleDescriptionSource {
let value = descriptionSourceNumber?.intValue ?? 0
return ArticleDescriptionSource(rawValue: value) ?? .none
}
}
4 changes: 4 additions & 0 deletions Wikipedia.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@
7A3AD05B20ADB1DF00C92E04 /* WMFCurrentlyLoggedInUserFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0ED173A1E497AE7008B70AD /* WMFCurrentlyLoggedInUserFetcher.swift */; };
7A3AD05C20ADB1F500C92E04 /* WMFKeychainCredentials.swift in Sources */ = {isa = PBXBuildFile; fileRef = B066F0D11E4F00B100A199F8 /* WMFKeychainCredentials.swift */; };
7A45AB8020AB2A4C006A92F5 /* Dictionary+Equality.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A45AB7F20AB2A4C006A92F5 /* Dictionary+Equality.swift */; };
7A4941E0216FE96400038D0F /* MWKArticle+Description.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A4941DF216FE96400038D0F /* MWKArticle+Description.swift */; };
7A49A20121231510005C574C /* CollectionViewFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A49A20021231510005C574C /* CollectionViewFooter.swift */; };
7A49A20221231510005C574C /* CollectionViewFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A49A20021231510005C574C /* CollectionViewFooter.swift */; };
7A49A20321231510005C574C /* CollectionViewFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A49A20021231510005C574C /* CollectionViewFooter.swift */; };
Expand Down Expand Up @@ -3272,6 +3273,7 @@
7A35CB861FD82B6300AAF3B7 /* ReadingListDetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadingListDetailViewController.swift; sourceTree = "<group>"; };
7A3AD05620ADAFEF00C92E04 /* WMFCaptcha.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WMFCaptcha.swift; path = "../../WMF Framework/WMFCaptcha.swift"; sourceTree = "<group>"; };
7A45AB7F20AB2A4C006A92F5 /* Dictionary+Equality.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Dictionary+Equality.swift"; sourceTree = "<group>"; };
7A4941DF216FE96400038D0F /* MWKArticle+Description.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MWKArticle+Description.swift"; sourceTree = "<group>"; };
7A49A20021231510005C574C /* CollectionViewFooter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewFooter.swift; sourceTree = "<group>"; };
7A4ABA8520AA8966007AA405 /* UserHistoryFunnel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserHistoryFunnel.swift; sourceTree = "<group>"; };
7A4B333B2136EDED00C6C820 /* UnderlineButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnderlineButton.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -5363,6 +5365,7 @@
children = (
B0E807B91C0CF04A0065EBC0 /* MWKArticle.h */,
B0E807BA1C0CF04A0065EBC0 /* MWKArticle.m */,
7A4941DF216FE96400038D0F /* MWKArticle+Description.swift */,
B0E807CD1C0CF04A0065EBC0 /* MWKSectionList.h */,
B0E807CE1C0CF04A0065EBC0 /* MWKSectionList.m */,
B0E807CF1C0CF04A0065EBC0 /* MWKSectionMetaData.h */,
Expand Down Expand Up @@ -10706,6 +10709,7 @@
D82C3A99213451100073EEAC /* DeviceInfo.swift in Sources */,
D80ACD291EA0DD0000DC3F20 /* FLAnimatedImage+SafeForSwift.m in Sources */,
D8FA18F21E1BDA35009675C3 /* UIImageView+WMFImageFetchingInternal.m in Sources */,
7A4941E0216FE96400038D0F /* MWKArticle+Description.swift in Sources */,
0E728D251DAEE2B50074EB4B /* WMFFeedContentFetcher.m in Sources */,
0E728D401DAEEC380074EB4B /* WMFRelatedSearchFetcher.m in Sources */,
D84C35F11F323CCA00895FA1 /* CollectionViewCell.swift in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion Wikipedia/Code/DescriptionEditViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ class DescriptionEditViewController: WMFScrollViewController, Themeable, UITextV
return
}

dataStore.wikidataDescriptionEditingController.publish(newWikidataDescription: descriptionToSave, for: articleURL) {error in
dataStore.wikidataDescriptionEditingController.publish(newWikidataDescription: descriptionToSave, from: article.descriptionSource, for: articleURL) {error in
let presentingVC = self.presentingViewController
DispatchQueue.main.async {
guard let error = error else {
Expand Down
1 change: 1 addition & 0 deletions Wikipedia/Code/MWKArticle.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ static const NSInteger kMWKArticleSectionNone = -1;
@property (readonly, strong, nonatomic, nullable) MWKUser *lastmodifiedby; // required
@property (readonly, assign, nonatomic) int articleId; // required; -> 'id'
@property (readonly, strong, nonatomic, nullable) NSNumber *revisionId;
@property (readonly, strong, nonatomic, nullable) NSNumber *descriptionSourceNumber;

@property (copy, nonatomic, nullable) NSString *acceptLanguageRequestHeader;

Expand Down
16 changes: 15 additions & 1 deletion Wikipedia/Code/MWKArticle.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ @interface MWKArticle ()
@property (readwrite, assign, nonatomic) BOOL editable; // required
@property (readwrite, assign, nonatomic, getter=isMain) BOOL main;
@property (readwrite, strong, nonatomic) NSNumber *revisionId;
@property (readwrite, strong, nonatomic) NSNumber *descriptionSourceNumber; // optional

@property (readwrite, nonatomic) NSInteger ns; //optional, defaults to 0

Expand Down Expand Up @@ -97,7 +98,7 @@ - (BOOL)isEqual:(id)object {
}

- (BOOL)isEqualToArticle:(MWKArticle *)other {
return WMF_EQUAL(self.url, isEqual:, other.url) && WMF_EQUAL(self.lastmodified, isEqualToDate:, other.lastmodified) && WMF_IS_EQUAL(self.lastmodifiedby, other.lastmodifiedby) && WMF_EQUAL(self.displaytitle, isEqualToString:, other.displaytitle) && WMF_EQUAL(self.protection, isEqual:, other.protection) && WMF_EQUAL(self.thumbnailURL, isEqualToString:, other.thumbnailURL) && WMF_EQUAL(self.imageURL, isEqualToString:, other.imageURL) && WMF_EQUAL(self.revisionId, isEqualToNumber:, other.revisionId) && self.articleId == other.articleId && self.languagecount == other.languagecount && self.isMain == other.isMain && self.sections.count == other.sections.count;
return WMF_EQUAL(self.url, isEqual:, other.url) && WMF_EQUAL(self.lastmodified, isEqualToDate:, other.lastmodified) && WMF_IS_EQUAL(self.lastmodifiedby, other.lastmodifiedby) && WMF_EQUAL(self.displaytitle, isEqualToString:, other.displaytitle) && WMF_EQUAL(self.protection, isEqual:, other.protection) && WMF_EQUAL(self.thumbnailURL, isEqualToString:, other.thumbnailURL) && WMF_EQUAL(self.imageURL, isEqualToString:, other.imageURL) && WMF_EQUAL(self.revisionId, isEqualToNumber:, other.revisionId) && self.articleId == other.articleId && self.languagecount == other.languagecount && self.isMain == other.isMain && self.sections.count == other.sections.count && WMF_EQUAL(self.descriptionSourceNumber, isEqualToNumber:, other.descriptionSourceNumber);
}

- (BOOL)isDeeplyEqualToArticle:(MWKArticle *)article {
Expand Down Expand Up @@ -162,6 +163,7 @@ - (void)importMobileViewJSON:(NSDictionary *)dict {
self.lastmodifiedby = [self requiredUser:@"lastmodifiedby" dict:dict];
self.articleId = [[self requiredNumber:@"id" dict:dict] intValue];
self.languagecount = [[self requiredNumber:@"languagecount" dict:dict] intValue];
self.descriptionSourceNumber = [self descriptionSourceNumberFromStringValue:[self optionalString:@"descriptionsource" dict:dict]];

self.ns = [[self optionalNumber:@"ns" dict:dict] integerValue];

Expand Down Expand Up @@ -236,6 +238,18 @@ - (void)importMobileViewJSON:(NSDictionary *)dict {
[self importMediaJSON:self.media];
}

- (NSNumber *)descriptionSourceNumberFromStringValue:(NSString *)stringValue {
ArticleDescriptionSource source;
if ([stringValue isEqualToString:@"central"]) {
source = ArticleDescriptionSourceCentral;
} else if ([stringValue isEqualToString:@"local"]) {
source = ArticleDescriptionSourceLocal;
} else {
source = ArticleDescriptionSourceNone;
}
return [NSNumber numberWithInteger:source];
}

+ (NSInteger)articleImageWidth {
static dispatch_once_t onceToken;
static NSInteger articleImageWidth;
Expand Down
32 changes: 15 additions & 17 deletions Wikipedia/Code/MWKDataStore.m
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ - (instancetype)initWithContainerURL:(NSURL *)containerURL {
self.feedContentController.siteURLs = [[MWKLanguageLinkController sharedInstance] preferredSiteURLs];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarningWithNotification:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
self.articleLocationController = [ArticleLocationController new];
self.wikidataDescriptionEditingController = [[WikidataDescriptionEditingController alloc] initWith:self.viewContext];
self.wikidataDescriptionEditingController = [[WikidataDescriptionEditingController alloc] init];
}
return self;
}
Expand Down Expand Up @@ -220,8 +220,8 @@ - (void)setupCoreDataStackWithContainerURL:(NSURL *)containerURL {

NSURL *coreDataDBURL = [containerURL URLByAppendingPathComponent:coreDataDBName isDirectory:NO];
NSPersistentStoreCoordinator *persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
NSDictionary *options = @{ NSMigratePersistentStoresAutomaticallyOption: @YES,
NSInferMappingModelAutomaticallyOption: @YES };
NSDictionary *options = @{NSMigratePersistentStoresAutomaticallyOption: @YES,
NSInferMappingModelAutomaticallyOption: @YES};
NSError *persistentStoreError = nil;
if (nil == [persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:coreDataDBURL options:options error:&persistentStoreError]) {
// TODO: Metrics
Expand Down Expand Up @@ -520,26 +520,26 @@ - (BOOL)migrateToReadingListsInManagedObjectContext:(NSManagedObjectContext *)mo
defaultReadingList.canonicalName = [ReadingList defaultListCanonicalName];
defaultReadingList.isDefault = YES;
}

for (ReadingListEntry *entry in defaultReadingList.entries) {
entry.isUpdatedLocally = YES;
}

if ([moc hasChanges] && ![moc save:migrationError]) {
return NO;
}

NSFetchRequest<WMFArticle *> *request = [WMFArticle fetchRequest];
request.fetchLimit = 500;
request.predicate = [NSPredicate predicateWithFormat:@"savedDate != NULL && readingLists.@count == 0", defaultReadingList];

NSArray<WMFArticle *> *results = [moc executeFetchRequest:request error:migrationError];
if (!results) {
return NO;
}

NSError *addError = nil;

while (results.count > 0) {
for (WMFArticle *article in results) {
[self.readingListsController addArticleToDefaultReadingList:article error:&addError];
Expand Down Expand Up @@ -598,7 +598,7 @@ - (void)performUpdatesFromLibraryVersion:(NSUInteger)currentLibraryVersion inMan
return;
}
}

if (currentLibraryVersion < 6) {
if (![self migrateMainPageContentGroupInManagedObjectContext:moc error:&migrationError]) {
DDLogError(@"Error during migration: %@", migrationError);
Expand Down Expand Up @@ -1111,7 +1111,7 @@ - (BOOL)saveArticle:(MWKArticle *)article error:(NSError **)outError {
}

if (article.url.wmf_isNonStandardURL) {
return YES; // OK to fail without error
return YES; // OK to fail without error
}
[self addArticleToMemoryCache:article];
NSString *path = [self pathForArticle:article];
Expand Down Expand Up @@ -1568,9 +1568,10 @@ - (void)clearMemoryCache {
- (void)clearCachesForUnsavedArticles {
[[WMFImageController sharedInstance] deleteTemporaryCache];
[[WMFImageController sharedInstance] removeLegacyCache];
[self removeUnreferencedArticlesFromDiskCacheWithFailure:^(NSError *_Nonnull error) {
DDLogError(@"Error removing unreferenced articles: %@", error);
}
[self
removeUnreferencedArticlesFromDiskCacheWithFailure:^(NSError *_Nonnull error) {
DDLogError(@"Error removing unreferenced articles: %@", error);
}
success:^{
DDLogDebug(@"Successfully removed unreferenced articles");
}];
Expand All @@ -1589,7 +1590,6 @@ - (void)updateLocalConfigurationFromRemoteConfigurationWithCompletion:(nullable
NSError *invalidRequestParametersError = [NSError wmf_errorWithType:WMFErrorTypeInvalidRequestParameters userInfo:nil];
WMFTaskGroup *taskGroup = [[WMFTaskGroup alloc] init];


// Site info
NSURL *siteInfoURL = [NSURL URLWithString:@"https://meta.wikimedia.org/w/api.php?action=query&format=json&meta=siteinfo"];
NSURLRequest *siteInfoRequest = [NSURLRequest requestWithURL:siteInfoURL];
Expand Down Expand Up @@ -1648,8 +1648,6 @@ - (void)updateLocalConfigurationFromRemoteConfiguration:(NSDictionary *)remoteCo
NSNumber *disableReadingListSyncNumber = remoteConfigurationDictionary[@"disableReadingListSync"];
BOOL shouldDisableReadingListSync = [disableReadingListSyncNumber boolValue];
self.readingListsController.isSyncRemotelyEnabled = !shouldDisableReadingListSync;

[self.wikidataDescriptionEditingController setBlacklistedLanguages:remoteConfigurationDictionary[@"descriptionEditLangBlacklist"]];
}

- (void)updateReadingListsLimits:(NSDictionary *)readingListsConfig {
Expand Down
51 changes: 7 additions & 44 deletions Wikipedia/Code/WikidataDescriptionEditingController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,53 +34,20 @@ extension WikidataAPIResult {
enum WikidataPublishingError: LocalizedError {
case invalidArticleURL
case apiResultNotParsedCorrectly
case blacklistedLanguage
case notEditable
case unknown
}

@objc public final class WikidataDescriptionEditingController: NSObject {
weak var viewContext: NSManagedObjectContext?

@objc public init(with viewContext: NSManagedObjectContext) {
self.viewContext = viewContext
}

private let BlacklistedLanguagesKey = "WMFWikidataDescriptionEditingBlacklistedLanguagesKey"
private var blacklistedLanguages: NSSet {
assert(Thread.isMainThread)
let fallback = NSSet(set: ["en"])
guard
let viewContext = viewContext,
let keyValue = viewContext.wmf_keyValue(forKey: BlacklistedLanguagesKey),
let value = keyValue.value as? NSSet else {
return fallback
}
return value
}

@objc public func setBlacklistedLanguages(_ blacklistedLanguagesFromRemoteConfig: Array<String>) {
assert(Thread.isMainThread)
assert(viewContext != nil)
let blacklistedLanguages = NSSet(array: blacklistedLanguagesFromRemoteConfig)
viewContext?.wmf_setValue(blacklistedLanguages, forKey: BlacklistedLanguagesKey)
}

public func isBlacklisted(_ languageCode: String) -> Bool {
guard blacklistedLanguages.count > 0 else {
return false
}
return blacklistedLanguages.contains(languageCode)
}

@objc(publishNewWikidataDescription:forArticleURL:completion:)
public func publish(newWikidataDescription: String, for articleURL: URL, completion: @escaping (Error?) -> Void) {
public func publish(newWikidataDescription: String, from source: ArticleDescriptionSource, for articleURL: URL, completion: @escaping (Error?) -> Void) {
guard let title = articleURL.wmf_title,
let language = articleURL.wmf_language,
let wiki = articleURL.wmf_wiki else {
completion(WikidataPublishingError.invalidArticleURL)
return
}
publish(newWikidataDescription: newWikidataDescription, forPageWithTitle: title, language: language, wiki: wiki, completion: completion)
publish(newWikidataDescription: newWikidataDescription, from: source, forPageWithTitle: title, language: language, wiki: wiki, completion: completion)
}

/// Publish new wikidata description.
Expand All @@ -91,10 +58,9 @@ enum WikidataPublishingError: LocalizedError {
/// - language: language code of the page's wiki, e.g., "en".
/// - wiki: wiki of the page to be updated, e.g., "enwiki"
/// - completion: completion block called when operation is completed.
private func publish(newWikidataDescription: String, forPageWithTitle title: String, language: String, wiki: String, completion: @escaping (Error?) -> Void) {
guard !isBlacklisted(language) else {
//DDLog("Attempting to publish a wikidata description in a blacklisted language; aborting")
completion(WikidataPublishingError.blacklistedLanguage)
private func publish(newWikidataDescription: String, from source: ArticleDescriptionSource, forPageWithTitle title: String, language: String, wiki: String, completion: @escaping (Error?) -> Void) {
guard source != .local else {
completion(WikidataPublishingError.notEditable)
return
}
let requestWithCSRFCompletion: (WikidataAPIResult?, URLResponse?, Error?) -> Void = { result, response, error in
Expand All @@ -114,9 +80,6 @@ enum WikidataPublishingError: LocalizedError {

public extension MWKArticle {
@objc var isWikidataDescriptionEditable: Bool {
guard let dataStore = dataStore, let language = self.url.wmf_language else {
return false
}
return !dataStore.wikidataDescriptionEditingController.isBlacklisted(language)
return descriptionSource != .local
}
}

0 comments on commit 600c5f5

Please sign in to comment.