Skip to content

getSubCategoryList and getParentCategoryList migrated to retrofit #3055

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 33 additions & 5 deletions app/src/main/java/fr/free/nrw/commons/category/CategoryClient.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package fr.free.nrw.commons.category;


import androidx.annotation.NonNull;

import org.wikipedia.dataclient.mwapi.MwQueryPage;
import org.wikipedia.dataclient.mwapi.MwQueryResponse;
import org.wikipedia.dataclient.mwapi.MwQueryResult;

import java.util.List;

Expand Down Expand Up @@ -74,6 +77,29 @@ public Observable<String> searchCategoriesForPrefix(String prefix, int itemLimit
}


/**
* The method takes categoryName as input and returns a List of Subcategories
* It uses the generator query API to get the subcategories in a category, 500 at a time.
*
* @param categoryName Category name as defined on commons
* @return Observable emitting the categories returned. If our search yielded "Category:Test", "Test" is emitted.
*/
public Observable<String> getSubCategoryList(String categoryName) {
return responseToCategoryName(CategoryInterface.getSubCategoryList(categoryName));
}

/**
* The method takes categoryName as input and returns a List of parent categories
* It uses the generator query API to get the parent categories of a category, 500 at a time.
*
* @param categoryName Category name as defined on commons
* @return
*/
@NonNull
public Observable<String> getParentCategoryList(String categoryName) {
return responseToCategoryName(CategoryInterface.getParentCategoryList(categoryName));
}

/**
* Internal function to reduce code reuse. Extracts the categories returned from MwQueryResponse.
*
Expand All @@ -83,12 +109,14 @@ public Observable<String> searchCategoriesForPrefix(String prefix, int itemLimit
private Observable<String> responseToCategoryName(Observable<MwQueryResponse> responseObservable) {
return responseObservable
.flatMap(mwQueryResponse -> {
List<MwQueryPage> pages = mwQueryResponse.query().pages();
if (pages != null)
return Observable.fromIterable(pages);
else
MwQueryResult query;
List<MwQueryPage> pages;
if ((query = mwQueryResponse.query()) == null ||
(pages = query.pages()) == null) {
Timber.d("No categories returned.");
return Observable.empty();
return Observable.empty();
} else
return Observable.fromIterable(pages);
})
.map(MwQueryPage::title)
.doOnEach(s -> Timber.d("Category returned: %s", s))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ public interface CategoryInterface {

/**
* Searches for categories with the specified name.
* Replaces ApacheHttpClientMediaWikiApi#allCategories
*
* @param filter The string to be searched
* @param itemLimit How many results are returned
Expand All @@ -24,8 +23,25 @@ public interface CategoryInterface {
Observable<MwQueryResponse> searchCategories(@Query("gsrsearch") String filter,
@Query("gsrlimit") int itemLimit, @Query("gsroffset") int offset);

/**
* Searches for categories starting with the specified prefix.
*
* @param prefix The string to be searched
* @param itemLimit How many results are returned
* @return
*/
@GET("w/api.php?action=query&format=json&formatversion=2"
+ "&generator=allcategories")
Observable<MwQueryResponse> searchCategoriesForPrefix(@Query("gacprefix") String prefix,
@Query("gaclimit") int itemLimit, @Query("gacoffset") int offset);

@GET("w/api.php?action=query&format=json&formatversion=2"
+ "&generator=categorymembers&gcmtype=subcat"
+ "&prop=info&gcmlimit=500")
Observable<MwQueryResponse> getSubCategoryList(@Query("gcmtitle") String categoryName);

@GET("w/api.php?action=query&format=json&formatversion=2"
+ "&generator=categories&prop=info&gcllimit=500")
Observable<MwQueryResponse> getParentCategoryList(@Query("titles") String categoryName);

}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public class SubCategoryListFragment extends CommonsDaggerSupportFragment {
TextView categoriesNotFoundView;

private String categoryName = null;
@Inject MediaWikiApi mwApi;
@Inject CategoryClient categoryClient;

private RVRendererAdapter<String> categoriesAdapter;
private boolean isParentCategory = true;
Expand Down Expand Up @@ -86,7 +86,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle sav
}

/**
* Checks for internet connection and then initializes the recycler view with 25 categories of the searched query
* Checks for internet connection and then initializes the recycler view with all(max 500) categories of the searched query
* Clearing categoryAdapter every time new keyword is searched so that user can see only new results
*/
public void initSubCategoryList() {
Expand All @@ -96,17 +96,19 @@ public void initSubCategoryList() {
return;
}
progressBar.setVisibility(View.VISIBLE);
if (!isParentCategory){
compositeDisposable.add(Observable.fromCallable(() -> mwApi.getSubCategoryList(categoryName))
if (isParentCategory) {
compositeDisposable.add(categoryClient.getParentCategoryList("Category:"+categoryName)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.timeout(TIMEOUT_SECONDS, TimeUnit.SECONDS)
.collect(ArrayList<String>::new, ArrayList::add)
.subscribe(this::handleSuccess, this::handleError));
}else {
compositeDisposable.add(Observable.fromCallable(() -> mwApi.getParentCategoryList(categoryName))
} else {
compositeDisposable.add(categoryClient.getSubCategoryList("Category:"+categoryName)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.timeout(TIMEOUT_SECONDS, TimeUnit.SECONDS)
.collect(ArrayList<String>::new, ArrayList::add)
.subscribe(this::handleSuccess, this::handleError));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public HttpLoggingInterceptor provideHttpLoggingInterceptor() {
public MediaWikiApi provideMediaWikiApi(Context context,
@Named("default_preferences") JsonKvStore defaultKvStore,
Gson gson) {
return new ApacheHttpClientMediaWikiApi(context, BuildConfig.WIKIMEDIA_API_HOST, BuildConfig.WIKIDATA_API_HOST, defaultKvStore, gson);
return new ApacheHttpClientMediaWikiApi(context, BuildConfig.WIKIMEDIA_API_HOST, BuildConfig.WIKIDATA_API_HOST, defaultKvStore);
}

@Provides
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,19 @@
import java.io.InputStream;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.Callable;

import fr.free.nrw.commons.BuildConfig;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.auth.AccountUtil;
import fr.free.nrw.commons.category.CategoryImageUtils;
import fr.free.nrw.commons.category.QueryContinue;
import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.notification.Notification;
import fr.free.nrw.commons.notification.NotificationUtils;
import fr.free.nrw.commons.utils.ViewUtil;
import io.reactivex.Observable;
import io.reactivex.Single;
import timber.log.Timber;

Expand All @@ -58,15 +54,13 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
private CustomMwApi wikidataApi;
private Context context;
private JsonKvStore defaultKvStore;
private Gson gson;

private final String ERROR_CODE_BAD_TOKEN = "badtoken";

public ApacheHttpClientMediaWikiApi(Context context,
String apiURL,
String wikidatApiURL,
JsonKvStore defaultKvStore,
Gson gson) {
JsonKvStore defaultKvStore) {
this.context = context;
BasicHttpParams params = new BasicHttpParams();
SchemeRegistry schemeRegistry = new SchemeRegistry();
Expand All @@ -82,7 +76,6 @@ public ApacheHttpClientMediaWikiApi(Context context,
api = new CustomMwApi(apiURL, httpClient);
wikidataApi = new CustomMwApi(wikidatApiURL, httpClient);
this.defaultKvStore = defaultKvStore;
this.gson = gson;
}

/**
Expand Down Expand Up @@ -491,114 +484,6 @@ public boolean markNotificationAsRead(Notification notification) throws IOExcept
return result.equals("success");
}

/**
* The method takes categoryName as input and returns a List of Subcategories
* It uses the generator query API to get the subcategories in a category, 500 at a time.
* Uses the query continue values for fetching paginated responses
*
* @param categoryName Category name as defined on commons
* @return
*/
@Override
@NonNull
public List<String> getSubCategoryList(String categoryName) {
CustomApiResult apiResult = null;
try {
CustomMwApi.RequestBuilder requestBuilder = api.action("query")
.param("generator", "categorymembers")
.param("format", "xml")
.param("gcmtype", "subcat")
.param("gcmtitle", categoryName)
.param("prop", "info")
.param("gcmlimit", "500")
.param("iiprop", "url|extmetadata");

apiResult = requestBuilder.get();
} catch (IOException e) {
Timber.e(e, "Failed to obtain searchCategories");
}

if (apiResult == null) {
return new ArrayList<>();
}

CustomApiResult categoryImagesNode = apiResult.getNode("/api/query/pages");
if (categoryImagesNode == null
|| categoryImagesNode.getDocument() == null
|| categoryImagesNode.getDocument().getChildNodes() == null
|| categoryImagesNode.getDocument().getChildNodes().getLength() == 0) {
return new ArrayList<>();
}

NodeList childNodes = categoryImagesNode.getDocument().getChildNodes();
return CategoryImageUtils.getSubCategoryList(childNodes);
}

/**
* The method takes categoryName as input and returns a List of parent categories
* It uses the generator query API to get the parent categories of a category, 500 at a time.
*
* @param categoryName Category name as defined on commons
* @return
*/
@Override
@NonNull
public List<String> getParentCategoryList(String categoryName) {
CustomApiResult apiResult = null;
try {
CustomMwApi.RequestBuilder requestBuilder = api.action("query")
.param("generator", "categories")
.param("format", "xml")
.param("titles", categoryName)
.param("prop", "info")
.param("cllimit", "500")
.param("iiprop", "url|extmetadata");

apiResult = requestBuilder.get();
} catch (IOException e) {
Timber.e(e, "Failed to obtain parent Categories");
}

if (apiResult == null) {
return new ArrayList<>();
}

CustomApiResult categoryImagesNode = apiResult.getNode("/api/query/pages");
if (categoryImagesNode == null
|| categoryImagesNode.getDocument() == null
|| categoryImagesNode.getDocument().getChildNodes() == null
|| categoryImagesNode.getDocument().getChildNodes().getLength() == 0) {
return new ArrayList<>();
}

NodeList childNodes = categoryImagesNode.getDocument().getChildNodes();
return CategoryImageUtils.getSubCategoryList(childNodes);
}


/**
* For APIs that return paginated responses, MediaWiki APIs uses the QueryContinue to facilitate fetching of subsequent pages
* https://www.mediawiki.org/wiki/API:Raw_query_continue
* After fetching images a page of image for a particular category, shared defaultKvStore are updated with the latest QueryContinue Values
*
* @param keyword
* @param queryContinue
*/
private void setQueryContinueValues(String keyword, QueryContinue queryContinue) {
defaultKvStore.putString(keyword, gson.toJson(queryContinue));
}

/**
* Before making a paginated API call, this method is called to get the latest query continue values to be used
*
* @param keyword
* @return
*/
@Nullable
private QueryContinue getQueryContinueValues(String keyword) {
String queryContinueString = defaultKvStore.getString(keyword, null);
return gson.fromJson(queryContinueString, QueryContinue.class);
}

@Override
@NonNull
Expand Down
4 changes: 0 additions & 4 deletions app/src/main/java/fr/free/nrw/commons/mwapi/MediaWikiApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,6 @@ public interface MediaWikiApi {

String getCentralAuthToken() throws IOException;

List<String> getSubCategoryList(String categoryName);

List<String> getParentCategoryList(String categoryName);

@NonNull
Single<UploadStash> uploadFile(String filename, InputStream file,
long dataLength, Uri fileUri, Uri contentProviderUri,
Expand Down
Loading