mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 21:03:54 +01:00
Convert API clients to kotlin (#5567)
* Convert UserClient to kotlin * Added tests for WikiBaseClient * Removed superfluous dao tests in review helper and got the proper ReviewDaoTest running in the unit test suite * Improved tests for ReviewHelper * Convert the ReviewHelper to kotlin * Convert the WikiBaseClient to kotlin * Convert the WikidataClient to kotlin
This commit is contained in:
parent
c43405267a
commit
728712c4e1
15 changed files with 496 additions and 526 deletions
|
|
@ -1,74 +0,0 @@
|
||||||
package fr.free.nrw.commons;
|
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.equalTo;
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import androidx.room.Room;
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|
||||||
import fr.free.nrw.commons.db.AppDatabase;
|
|
||||||
import fr.free.nrw.commons.review.ReviewDao;
|
|
||||||
import fr.free.nrw.commons.review.ReviewEntity;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
public class ReviewDaoTest {
|
|
||||||
|
|
||||||
private ReviewDao reviewDao;
|
|
||||||
private AppDatabase database;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set up the application database
|
|
||||||
*/
|
|
||||||
@Before
|
|
||||||
public void createDb() {
|
|
||||||
Context context = ApplicationProvider.getApplicationContext();
|
|
||||||
database = Room.inMemoryDatabaseBuilder(
|
|
||||||
context, AppDatabase.class)
|
|
||||||
.allowMainThreadQueries()
|
|
||||||
.build();
|
|
||||||
reviewDao = database.ReviewDao();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the database
|
|
||||||
*/
|
|
||||||
@After
|
|
||||||
public void closeDb() {
|
|
||||||
database.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test insertion
|
|
||||||
* Also checks isReviewedAlready():
|
|
||||||
* Case 1: When image has been reviewed/skipped by the user
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void insert() {
|
|
||||||
// Insert data
|
|
||||||
String imageId = "1234";
|
|
||||||
ReviewEntity reviewEntity = new ReviewEntity(imageId);
|
|
||||||
reviewDao.insert(reviewEntity);
|
|
||||||
|
|
||||||
// Check insertion
|
|
||||||
// Covers the case where the image exists in the database
|
|
||||||
// And isReviewedAlready() returns true
|
|
||||||
Boolean isInserted = reviewDao.isReviewedAlready(imageId);
|
|
||||||
assertThat(isInserted, equalTo(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test review status of the image
|
|
||||||
* Case 2: When image has not been reviewed/skipped
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void isReviewedAlready(){
|
|
||||||
String imageId = "5856";
|
|
||||||
Boolean isInserted = reviewDao.isReviewedAlready(imageId);
|
|
||||||
assertThat(isInserted, equalTo(false));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
package fr.free.nrw.commons.mwapi;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.wikidata.mwapi.MwQueryResponse;
|
|
||||||
import fr.free.nrw.commons.wikidata.mwapi.MwQueryResult;
|
|
||||||
import fr.free.nrw.commons.wikidata.mwapi.UserInfo;
|
|
||||||
import fr.free.nrw.commons.utils.DateUtil;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import io.reactivex.Observable;
|
|
||||||
import io.reactivex.Single;
|
|
||||||
|
|
||||||
public class UserClient {
|
|
||||||
private final UserInterface userInterface;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public UserClient(UserInterface userInterface) {
|
|
||||||
this.userInterface = userInterface;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks to see if a user is currently blocked from Commons
|
|
||||||
*
|
|
||||||
* @return whether or not the user is blocked from Commons
|
|
||||||
*/
|
|
||||||
public Single<Boolean> isUserBlockedFromCommons() {
|
|
||||||
return userInterface.getUserBlockInfo()
|
|
||||||
.map(MwQueryResponse::query)
|
|
||||||
.map(MwQueryResult::userInfo)
|
|
||||||
.map(UserInfo::blockexpiry)
|
|
||||||
.map(blockExpiry -> {
|
|
||||||
if (blockExpiry.isEmpty())
|
|
||||||
return false;
|
|
||||||
else if ("infinite".equals(blockExpiry))
|
|
||||||
return true;
|
|
||||||
else {
|
|
||||||
Date endDate = DateUtil.iso8601DateParse(blockExpiry);
|
|
||||||
Date current = new Date();
|
|
||||||
return endDate.after(current);
|
|
||||||
}
|
|
||||||
}).single(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
36
app/src/main/java/fr/free/nrw/commons/mwapi/UserClient.kt
Normal file
36
app/src/main/java/fr/free/nrw/commons/mwapi/UserClient.kt
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
package fr.free.nrw.commons.mwapi
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.utils.DateUtil
|
||||||
|
import fr.free.nrw.commons.wikidata.mwapi.MwQueryResponse
|
||||||
|
import fr.free.nrw.commons.wikidata.mwapi.MwQueryResult
|
||||||
|
import fr.free.nrw.commons.wikidata.mwapi.UserInfo
|
||||||
|
import io.reactivex.Single
|
||||||
|
import java.text.ParseException
|
||||||
|
import java.util.Date
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class UserClient @Inject constructor(private val userInterface: UserInterface) {
|
||||||
|
/**
|
||||||
|
* Checks to see if a user is currently blocked from Commons
|
||||||
|
*
|
||||||
|
* @return whether or not the user is blocked from Commons
|
||||||
|
*/
|
||||||
|
fun isUserBlockedFromCommons(): Single<Boolean> =
|
||||||
|
userInterface.getUserBlockInfo()
|
||||||
|
.map(::processBlockExpiry)
|
||||||
|
.single(false)
|
||||||
|
|
||||||
|
@Throws(ParseException::class)
|
||||||
|
private fun processBlockExpiry(response: MwQueryResponse): Boolean {
|
||||||
|
val blockExpiry = response.query()?.userInfo()?.blockexpiry()
|
||||||
|
return when {
|
||||||
|
blockExpiry.isNullOrEmpty() -> false
|
||||||
|
"infinite" == blockExpiry -> true
|
||||||
|
else -> {
|
||||||
|
val endDate = DateUtil.iso8601DateParse(blockExpiry)
|
||||||
|
val current = Date()
|
||||||
|
endDate.after(current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,166 +0,0 @@
|
||||||
package fr.free.nrw.commons.review;
|
|
||||||
|
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
|
||||||
import fr.free.nrw.commons.Media;
|
|
||||||
import fr.free.nrw.commons.media.MediaClient;
|
|
||||||
import io.reactivex.Completable;
|
|
||||||
import io.reactivex.Observable;
|
|
||||||
import io.reactivex.Single;
|
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
|
||||||
import io.reactivex.schedulers.Schedulers;
|
|
||||||
import java.util.Collections;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import fr.free.nrw.commons.wikidata.mwapi.MwQueryPage;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
public class ReviewHelper {
|
|
||||||
|
|
||||||
private static final String[] imageExtensions = new String[]{".jpg", ".jpeg", ".png"};
|
|
||||||
|
|
||||||
private final MediaClient mediaClient;
|
|
||||||
private final ReviewInterface reviewInterface;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
ReviewDao dao;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public ReviewHelper(MediaClient mediaClient, ReviewInterface reviewInterface) {
|
|
||||||
this.mediaClient = mediaClient;
|
|
||||||
this.reviewInterface = reviewInterface;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches recent changes from MediaWiki API
|
|
||||||
* Calls the API to get the latest 50 changes
|
|
||||||
* When more results are available, the query gets continued beyond this range
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private Observable<MwQueryPage> getRecentChanges() {
|
|
||||||
return reviewInterface.getRecentChanges()
|
|
||||||
.map(mwQueryResponse -> mwQueryResponse.query().pages())
|
|
||||||
.map(recentChanges -> {
|
|
||||||
Collections.shuffle(recentChanges);
|
|
||||||
return recentChanges;
|
|
||||||
})
|
|
||||||
.flatMapIterable(changes -> changes)
|
|
||||||
.filter(recentChange -> isChangeReviewable(recentChange));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a random file change for review.
|
|
||||||
* - Picks a random file from those changes
|
|
||||||
* - Checks if the file is nominated for deletion
|
|
||||||
* - Retries upto 5 times for getting a file which is not nominated for deletion
|
|
||||||
*
|
|
||||||
* @return Random file change
|
|
||||||
*/
|
|
||||||
public Single<Media> getRandomMedia() {
|
|
||||||
return getRecentChanges()
|
|
||||||
.flatMapSingle(change -> getRandomMediaFromRecentChange(change))
|
|
||||||
.filter(media -> !StringUtils.isBlank(media.getFilename())
|
|
||||||
&& !getReviewStatus(media.getPageId()) // Check if the image has already been shown to the user
|
|
||||||
)
|
|
||||||
.firstOrError();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a proper Media object if the file is not already nominated for deletion
|
|
||||||
* Else it returns an empty Media object
|
|
||||||
*
|
|
||||||
* @param recentChange
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private Single<Media> getRandomMediaFromRecentChange(MwQueryPage recentChange) {
|
|
||||||
return Single.just(recentChange)
|
|
||||||
.flatMap(change -> mediaClient.checkPageExistsUsingTitle("Commons:Deletion_requests/" + change.title()))
|
|
||||||
.flatMap(isDeleted -> {
|
|
||||||
if (isDeleted) {
|
|
||||||
return Single.error(new Exception(recentChange.title() + " is deleted"));
|
|
||||||
}
|
|
||||||
return mediaClient.getMedia(recentChange.title());
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the image exists in the reviewed images entity
|
|
||||||
*
|
|
||||||
* @param image
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@VisibleForTesting
|
|
||||||
Boolean getReviewStatus(String image){
|
|
||||||
if(dao == null){
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return Observable.fromCallable(()-> dao.isReviewedAlready(image))
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread()).blockingSingle();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the first revision of the file from filename
|
|
||||||
*
|
|
||||||
* @param filename
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public Observable<MwQueryPage.Revision> getFirstRevisionOfFile(String filename) {
|
|
||||||
return reviewInterface.getFirstRevisionOfFile(filename)
|
|
||||||
.map(response -> response.query().firstPage().revisions().get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks Whether Given File is used in any Wiki page or not
|
|
||||||
* by calling api for given file
|
|
||||||
*
|
|
||||||
* @param filename
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
Observable<Boolean> checkFileUsage(final String filename) {
|
|
||||||
return reviewInterface.getGlobalUsageInfo(filename)
|
|
||||||
.map(mwQueryResponse -> mwQueryResponse.query().firstPage()
|
|
||||||
.checkWhetherFileIsUsedInWikis());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the change is reviewable or not.
|
|
||||||
* - checks the type and revisionId of the change
|
|
||||||
* - checks supported image extensions
|
|
||||||
*
|
|
||||||
* @param recentChange
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private boolean isChangeReviewable(MwQueryPage recentChange) {
|
|
||||||
for (String extension : imageExtensions) {
|
|
||||||
if (recentChange.title().endsWith(extension)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds reviewed/skipped images to the database
|
|
||||||
*
|
|
||||||
* @param imageId
|
|
||||||
*/
|
|
||||||
public void addViewedImagesToDB(String imageId) {
|
|
||||||
Completable.fromAction(() -> dao.insert(new ReviewEntity(imageId)))
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe(() -> {
|
|
||||||
// Inserted successfully
|
|
||||||
Timber.i("Image inserted successfully.");
|
|
||||||
},
|
|
||||||
throwable -> {
|
|
||||||
Timber.e("Image not inserted into the reviewed images database");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
138
app/src/main/java/fr/free/nrw/commons/review/ReviewHelper.kt
Normal file
138
app/src/main/java/fr/free/nrw/commons/review/ReviewHelper.kt
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
package fr.free.nrw.commons.review
|
||||||
|
|
||||||
|
import androidx.annotation.VisibleForTesting
|
||||||
|
import fr.free.nrw.commons.Media
|
||||||
|
import fr.free.nrw.commons.media.MediaClient
|
||||||
|
import fr.free.nrw.commons.wikidata.mwapi.MwQueryPage
|
||||||
|
import fr.free.nrw.commons.wikidata.mwapi.MwQueryPage.Revision
|
||||||
|
import fr.free.nrw.commons.wikidata.mwapi.MwQueryResponse
|
||||||
|
import io.reactivex.Completable
|
||||||
|
import io.reactivex.Observable
|
||||||
|
import io.reactivex.Single
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.schedulers.Schedulers
|
||||||
|
import org.apache.commons.lang3.StringUtils
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.util.Collections
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class ReviewHelper @Inject constructor(
|
||||||
|
private val mediaClient: MediaClient,
|
||||||
|
private val reviewInterface: ReviewInterface
|
||||||
|
) {
|
||||||
|
@JvmField @Inject var dao: ReviewDao? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetches recent changes from MediaWiki API
|
||||||
|
* Calls the API to get the latest 50 changes
|
||||||
|
* When more results are available, the query gets continued beyond this range
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private fun getRecentChanges() = reviewInterface.getRecentChanges()
|
||||||
|
.map { it.query()?.pages() }
|
||||||
|
.map(MutableList<MwQueryPage>::shuffled)
|
||||||
|
.flatMapIterable { changes: List<MwQueryPage>? -> changes }
|
||||||
|
.filter { isChangeReviewable(it) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a random file change for review. Checks if the image has already been shown to the user
|
||||||
|
* - Picks a random file from those changes
|
||||||
|
* - Checks if the file is nominated for deletion
|
||||||
|
* - Retries upto 5 times for getting a file which is not nominated for deletion
|
||||||
|
*
|
||||||
|
* @return Random file change
|
||||||
|
*/
|
||||||
|
fun getRandomMedia(): Single<Media> = getRecentChanges()
|
||||||
|
.flatMapSingle(::getRandomMediaFromRecentChange)
|
||||||
|
.filter { !it.filename.isNullOrBlank() && !getReviewStatus(it.pageId) }
|
||||||
|
.firstOrError()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a proper Media object if the file is not already nominated for deletion
|
||||||
|
* Else it returns an empty Media object
|
||||||
|
*
|
||||||
|
* @param recentChange
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private fun getRandomMediaFromRecentChange(recentChange: MwQueryPage) =
|
||||||
|
Single.just(recentChange)
|
||||||
|
.flatMap { mediaClient.checkPageExistsUsingTitle("Commons:Deletion_requests/${it.title()}") }
|
||||||
|
.flatMap {
|
||||||
|
if (it) {
|
||||||
|
Single.error(Exception("${recentChange.title()} is deleted"))
|
||||||
|
} else {
|
||||||
|
mediaClient.getMedia(recentChange.title())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the image exists in the reviewed images entity
|
||||||
|
*
|
||||||
|
* @param image
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
fun getReviewStatus(image: String?): Boolean =
|
||||||
|
dao?.isReviewedAlready(image) ?: false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the first revision of the file from filename
|
||||||
|
*
|
||||||
|
* @param filename
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
fun getFirstRevisionOfFile(filename: String?): Observable<Revision> =
|
||||||
|
reviewInterface.getFirstRevisionOfFile(filename)
|
||||||
|
.map { it.query()?.firstPage()?.revisions()?.get(0) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks Whether Given File is used in any Wiki page or not
|
||||||
|
* by calling api for given file
|
||||||
|
*
|
||||||
|
* @param filename
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
fun checkFileUsage(filename: String?): Observable<Boolean> =
|
||||||
|
reviewInterface.getGlobalUsageInfo(filename)
|
||||||
|
.map { it.query()?.firstPage()?.checkWhetherFileIsUsedInWikis() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the change is reviewable or not.
|
||||||
|
* - checks the type and revisionId of the change
|
||||||
|
* - checks supported image extensions
|
||||||
|
*
|
||||||
|
* @param recentChange
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private fun isChangeReviewable(recentChange: MwQueryPage): Boolean {
|
||||||
|
for (extension in imageExtensions) {
|
||||||
|
if (recentChange.title().endsWith(extension)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds reviewed/skipped images to the database
|
||||||
|
*
|
||||||
|
* @param imageId
|
||||||
|
*/
|
||||||
|
fun addViewedImagesToDB(imageId: String?) {
|
||||||
|
Completable.fromAction { dao!!.insert(ReviewEntity(imageId)) }
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(
|
||||||
|
{
|
||||||
|
// Inserted successfully
|
||||||
|
Timber.i("Image inserted successfully.")
|
||||||
|
}
|
||||||
|
) { throwable: Throwable? -> Timber.e("Image not inserted into the reviewed images database") }
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val imageExtensions = arrayOf(".jpg", ".jpeg", ".png")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,76 +0,0 @@
|
||||||
package fr.free.nrw.commons.wikidata;
|
|
||||||
|
|
||||||
import static fr.free.nrw.commons.di.NetworkingModule.NAMED_COMMONS_CSRF;
|
|
||||||
import static fr.free.nrw.commons.media.MediaClientKt.PAGE_ID_PREFIX;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.upload.UploadResult;
|
|
||||||
import fr.free.nrw.commons.upload.WikiBaseInterface;
|
|
||||||
import io.reactivex.Observable;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Named;
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
import fr.free.nrw.commons.auth.csrf.CsrfTokenClient;
|
|
||||||
import fr.free.nrw.commons.wikidata.mwapi.MwPostResponse;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wikibase Client for calling WikiBase APIs
|
|
||||||
*/
|
|
||||||
@Singleton
|
|
||||||
public class WikiBaseClient {
|
|
||||||
|
|
||||||
private final WikiBaseInterface wikiBaseInterface;
|
|
||||||
private final CsrfTokenClient csrfTokenClient;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public WikiBaseClient(WikiBaseInterface wikiBaseInterface,
|
|
||||||
@Named(NAMED_COMMONS_CSRF) CsrfTokenClient csrfTokenClient) {
|
|
||||||
this.wikiBaseInterface = wikiBaseInterface;
|
|
||||||
this.csrfTokenClient = csrfTokenClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Observable<Boolean> postEditEntity(String fileEntityId, String data) {
|
|
||||||
return csrfToken()
|
|
||||||
.switchMap(editToken -> wikiBaseInterface.postEditEntity(fileEntityId, editToken, data)
|
|
||||||
.map(response -> (response.getSuccessVal() == 1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the server call for posting new depicts
|
|
||||||
*
|
|
||||||
* @param filename name of the file
|
|
||||||
* @param data data of the depicts to be uploaded
|
|
||||||
* @return Observable<Boolean>
|
|
||||||
*/
|
|
||||||
public Observable<Boolean> postEditEntityByFilename(final String filename, final String data) {
|
|
||||||
return csrfToken()
|
|
||||||
.switchMap(editToken -> wikiBaseInterface.postEditEntityByFilename(filename,
|
|
||||||
editToken, data)
|
|
||||||
.map(response -> (response.getSuccessVal() == 1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Observable<Long> getFileEntityId(UploadResult uploadResult) {
|
|
||||||
return wikiBaseInterface.getFileEntityId(uploadResult.createCanonicalFileName())
|
|
||||||
.map(response -> (long) (response.query().pages().get(0).pageId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Observable<MwPostResponse> addLabelstoWikidata(long fileEntityId,
|
|
||||||
String languageCode, String captionValue) {
|
|
||||||
return csrfToken()
|
|
||||||
.switchMap(editToken -> wikiBaseInterface
|
|
||||||
.addLabelstoWikidata(PAGE_ID_PREFIX + fileEntityId, editToken, languageCode,
|
|
||||||
captionValue));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private Observable<String> csrfToken() {
|
|
||||||
return Observable.fromCallable(() -> {
|
|
||||||
try {
|
|
||||||
return csrfTokenClient.getTokenBlocking();
|
|
||||||
} catch (Throwable throwable) {
|
|
||||||
Timber.e(throwable);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,69 @@
|
||||||
|
package fr.free.nrw.commons.wikidata
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.auth.csrf.CsrfTokenClient
|
||||||
|
import fr.free.nrw.commons.di.NetworkingModule
|
||||||
|
import fr.free.nrw.commons.media.PAGE_ID_PREFIX
|
||||||
|
import fr.free.nrw.commons.upload.UploadResult
|
||||||
|
import fr.free.nrw.commons.upload.WikiBaseInterface
|
||||||
|
import fr.free.nrw.commons.wikidata.mwapi.MwPostResponse
|
||||||
|
import fr.free.nrw.commons.wikidata.mwapi.MwQueryResponse
|
||||||
|
import io.reactivex.Observable
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Named
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wikibase Client for calling WikiBase APIs
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
class WikiBaseClient @Inject constructor(
|
||||||
|
private val wikiBaseInterface: WikiBaseInterface,
|
||||||
|
@param:Named(NetworkingModule.NAMED_COMMONS_CSRF) private val csrfTokenClient: CsrfTokenClient
|
||||||
|
) {
|
||||||
|
fun postEditEntity(fileEntityId: String?, data: String?): Observable<Boolean> {
|
||||||
|
return csrfToken().switchMap { editToken ->
|
||||||
|
wikiBaseInterface.postEditEntity(fileEntityId!!, editToken, data!!)
|
||||||
|
.map { response: MwPostResponse -> response.successVal == 1 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes the server call for posting new depicts
|
||||||
|
*
|
||||||
|
* @param filename name of the file
|
||||||
|
* @param data data of the depicts to be uploaded
|
||||||
|
* @return Observable<Boolean>
|
||||||
|
</Boolean> */
|
||||||
|
fun postEditEntityByFilename(filename: String?, data: String?): Observable<Boolean> {
|
||||||
|
return csrfToken().switchMap { editToken ->
|
||||||
|
wikiBaseInterface.postEditEntityByFilename(filename!!, editToken, data!!)
|
||||||
|
.map { response: MwPostResponse -> response.successVal == 1 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getFileEntityId(uploadResult: UploadResult): Observable<Long> {
|
||||||
|
return wikiBaseInterface.getFileEntityId(uploadResult.createCanonicalFileName())
|
||||||
|
.map { response: MwQueryResponse -> response.query()!!.pages()!![0].pageId().toLong() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addLabelstoWikidata(fileEntityId: Long, languageCode: String?, captionValue: String?): Observable<MwPostResponse> {
|
||||||
|
return csrfToken().switchMap { editToken ->
|
||||||
|
wikiBaseInterface.addLabelstoWikidata(
|
||||||
|
PAGE_ID_PREFIX + fileEntityId,
|
||||||
|
editToken,
|
||||||
|
languageCode,
|
||||||
|
captionValue
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun csrfToken(): Observable<String> = Observable.fromCallable {
|
||||||
|
try {
|
||||||
|
csrfTokenClient.getTokenBlocking()
|
||||||
|
} catch (throwable: Throwable) {
|
||||||
|
Timber.e(throwable)
|
||||||
|
""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
package fr.free.nrw.commons.wikidata;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
import javax.inject.Singleton;
|
|
||||||
|
|
||||||
import fr.free.nrw.commons.wikidata.model.AddEditTagResponse;
|
|
||||||
import io.reactivex.Observable;
|
|
||||||
import io.reactivex.ObservableSource;
|
|
||||||
import fr.free.nrw.commons.wikidata.model.Statement_partial;
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
public class WikidataClient {
|
|
||||||
|
|
||||||
|
|
||||||
private final WikidataInterface wikidataInterface;
|
|
||||||
private final Gson gson;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public WikidataClient(WikidataInterface wikidataInterface, final Gson gson) {
|
|
||||||
this.wikidataInterface = wikidataInterface;
|
|
||||||
this.gson = gson;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create wikidata claim to add P18 value
|
|
||||||
*
|
|
||||||
* @return revisionID of the edit
|
|
||||||
*/
|
|
||||||
Observable<Long> setClaim(Statement_partial claim, String tags) {
|
|
||||||
return getCsrfToken()
|
|
||||||
.flatMap(
|
|
||||||
csrfToken -> wikidataInterface.postSetClaim(gson.toJson(claim), tags, csrfToken))
|
|
||||||
.map(mwPostResponse -> mwPostResponse.getPageinfo().getLastrevid());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get csrf token for wikidata edit
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
private Observable<String> getCsrfToken() {
|
|
||||||
return wikidataInterface.getCsrfToken()
|
|
||||||
.map(mwQueryResponse -> mwQueryResponse.query().csrfToken());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
package fr.free.nrw.commons.wikidata
|
||||||
|
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import fr.free.nrw.commons.wikidata.model.Statement_partial
|
||||||
|
import fr.free.nrw.commons.wikidata.model.WbCreateClaimResponse
|
||||||
|
import fr.free.nrw.commons.wikidata.mwapi.MwQueryResponse
|
||||||
|
import io.reactivex.Observable
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class WikidataClient @Inject constructor(
|
||||||
|
private val wikidataInterface: WikidataInterface,
|
||||||
|
private val gson: Gson
|
||||||
|
) {
|
||||||
|
/**
|
||||||
|
* Create wikidata claim to add P18 value
|
||||||
|
*
|
||||||
|
* @return revisionID of the edit
|
||||||
|
*/
|
||||||
|
fun setClaim(claim: Statement_partial?, tags: String?): Observable<Long> {
|
||||||
|
return csrfToken().flatMap { csrfToken: String? ->
|
||||||
|
wikidataInterface.postSetClaim(gson.toJson(claim), tags!!, csrfToken!!)
|
||||||
|
}.map { mwPostResponse: WbCreateClaimResponse -> mwPostResponse.pageinfo.lastrevid }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get csrf token for wikidata edit
|
||||||
|
*/
|
||||||
|
private fun csrfToken(): Observable<String?> =
|
||||||
|
wikidataInterface.getCsrfToken().map { it.query()?.csrfToken() }
|
||||||
|
}
|
||||||
|
|
@ -36,7 +36,7 @@ class UserClientTest{
|
||||||
Mockito.`when`(userInterface!!.getUserBlockInfo())
|
Mockito.`when`(userInterface!!.getUserBlockInfo())
|
||||||
.thenReturn(Observable.just(mockResponse))
|
.thenReturn(Observable.just(mockResponse))
|
||||||
|
|
||||||
val isBanned = userClient!!.isUserBlockedFromCommons.blockingGet()
|
val isBanned = userClient!!.isUserBlockedFromCommons().blockingGet()
|
||||||
assertTrue(isBanned)
|
assertTrue(isBanned)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,7 +54,7 @@ class UserClientTest{
|
||||||
Mockito.`when`(userInterface!!.getUserBlockInfo())
|
Mockito.`when`(userInterface!!.getUserBlockInfo())
|
||||||
.thenReturn(Observable.just(mockResponse))
|
.thenReturn(Observable.just(mockResponse))
|
||||||
|
|
||||||
val isBanned = userClient!!.isUserBlockedFromCommons.blockingGet()
|
val isBanned = userClient!!.isUserBlockedFromCommons().blockingGet()
|
||||||
assertTrue(isBanned)
|
assertTrue(isBanned)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,7 +69,7 @@ class UserClientTest{
|
||||||
Mockito.`when`(userInterface!!.getUserBlockInfo())
|
Mockito.`when`(userInterface!!.getUserBlockInfo())
|
||||||
.thenReturn(Observable.just(mockResponse))
|
.thenReturn(Observable.just(mockResponse))
|
||||||
|
|
||||||
val isBanned = userClient!!.isUserBlockedFromCommons.blockingGet()
|
val isBanned = userClient!!.isUserBlockedFromCommons().blockingGet()
|
||||||
assertFalse(isBanned)
|
assertFalse(isBanned)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -111,10 +111,10 @@ class ReviewActivityTest {
|
||||||
val media = mock(Media::class.java)
|
val media = mock(Media::class.java)
|
||||||
|
|
||||||
doReturn(mapOf<String, Boolean>("test" to false)).`when`(media).categoriesHiddenStatus
|
doReturn(mapOf<String, Boolean>("test" to false)).`when`(media).categoriesHiddenStatus
|
||||||
doReturn(Single.just(media)).`when`(reviewHelper)?.randomMedia
|
doReturn(Single.just(media)).`when`(reviewHelper)?.getRandomMedia()
|
||||||
Assert.assertNotNull(reviewHelper?.randomMedia)
|
Assert.assertNotNull(reviewHelper?.getRandomMedia())
|
||||||
reviewHelper
|
reviewHelper
|
||||||
?.randomMedia
|
?.getRandomMedia()
|
||||||
?.test()
|
?.test()
|
||||||
?.assertValue(media);
|
?.assertValue(media);
|
||||||
activity.swipeToNext()
|
activity.swipeToNext()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
package fr.free.nrw.commons.review
|
||||||
|
|
||||||
|
import androidx.room.Room.inMemoryDatabaseBuilder
|
||||||
|
import androidx.test.core.app.ApplicationProvider
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import fr.free.nrw.commons.TestCommonsApplication
|
||||||
|
import fr.free.nrw.commons.db.AppDatabase
|
||||||
|
import org.hamcrest.CoreMatchers
|
||||||
|
import org.hamcrest.MatcherAssert
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.robolectric.annotation.Config
|
||||||
|
import org.robolectric.annotation.LooperMode
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
@Config(sdk = [21], application = TestCommonsApplication::class)
|
||||||
|
@LooperMode(LooperMode.Mode.PAUSED)
|
||||||
|
class ReviewDaoTest {
|
||||||
|
private lateinit var reviewDao: ReviewDao
|
||||||
|
private lateinit var database: AppDatabase
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set up the application database
|
||||||
|
*/
|
||||||
|
@Before
|
||||||
|
fun createDb() {
|
||||||
|
database = inMemoryDatabaseBuilder(
|
||||||
|
context = ApplicationProvider.getApplicationContext(),
|
||||||
|
klass = AppDatabase::class.java
|
||||||
|
).allowMainThreadQueries().build()
|
||||||
|
reviewDao = database.ReviewDao()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the database
|
||||||
|
*/
|
||||||
|
@After
|
||||||
|
fun closeDb() {
|
||||||
|
database.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test insertion
|
||||||
|
* Also checks isReviewedAlready():
|
||||||
|
* Case 1: When image has been reviewed/skipped by the user
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun insert() {
|
||||||
|
// Insert data
|
||||||
|
val imageId = "1234"
|
||||||
|
val reviewEntity = ReviewEntity(imageId)
|
||||||
|
reviewDao.insert(reviewEntity)
|
||||||
|
|
||||||
|
// Check insertion
|
||||||
|
// Covers the case where the image exists in the database
|
||||||
|
// And isReviewedAlready() returns true
|
||||||
|
val isInserted = reviewDao.isReviewedAlready(imageId)
|
||||||
|
MatcherAssert.assertThat(isInserted, CoreMatchers.equalTo(true))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isReviewedAlready() {
|
||||||
|
/**
|
||||||
|
* Test review status of the image
|
||||||
|
* Case 2: When image has not been reviewed/skipped
|
||||||
|
*/
|
||||||
|
val imageId = "5856"
|
||||||
|
val isInserted = reviewDao.isReviewedAlready(imageId)
|
||||||
|
MatcherAssert.assertThat(isInserted, CoreMatchers.equalTo(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,40 +1,32 @@
|
||||||
package fr.free.nrw.commons.review
|
package fr.free.nrw.commons.review
|
||||||
|
|
||||||
import com.nhaarman.mockitokotlin2.mock
|
|
||||||
import com.nhaarman.mockitokotlin2.whenever
|
import com.nhaarman.mockitokotlin2.whenever
|
||||||
import fr.free.nrw.commons.Media
|
import fr.free.nrw.commons.Media
|
||||||
import fr.free.nrw.commons.media.MediaClient
|
import fr.free.nrw.commons.media.MediaClient
|
||||||
import io.reactivex.Completable
|
import fr.free.nrw.commons.wikidata.mwapi.MwQueryPage
|
||||||
|
import fr.free.nrw.commons.wikidata.mwapi.MwQueryResponse
|
||||||
|
import fr.free.nrw.commons.wikidata.mwapi.MwQueryResult
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Assert.assertNull
|
import org.junit.Assert.assertNull
|
||||||
import org.junit.Assert.assertTrue
|
import org.junit.Assert.assertTrue
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mockito.ArgumentMatchers
|
|
||||||
import org.mockito.InjectMocks
|
|
||||||
import org.mockito.Mock
|
|
||||||
import org.mockito.Mockito.*
|
import org.mockito.Mockito.*
|
||||||
import org.mockito.MockitoAnnotations
|
|
||||||
import fr.free.nrw.commons.wikidata.mwapi.MwQueryPage
|
|
||||||
import fr.free.nrw.commons.wikidata.mwapi.MwQueryResponse
|
|
||||||
import fr.free.nrw.commons.wikidata.mwapi.MwQueryResult
|
|
||||||
import java.util.concurrent.Callable
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test class for ReviewHelper
|
* Test class for ReviewHelper
|
||||||
*/
|
*/
|
||||||
class ReviewHelperTest {
|
class ReviewHelperTest {
|
||||||
|
|
||||||
@Mock
|
private val reviewInterface = mock<ReviewInterface>()
|
||||||
internal var reviewInterface: ReviewInterface? = null
|
private val mediaClient = mock<MediaClient>()
|
||||||
@Mock
|
private val reviewHelper = ReviewHelper(mediaClient, reviewInterface)
|
||||||
internal var mediaClient: MediaClient? = null
|
|
||||||
|
|
||||||
@InjectMocks
|
|
||||||
var reviewHelper: ReviewHelper? = null
|
|
||||||
|
|
||||||
val dao = mock(ReviewDao::class.java)
|
private val mwQueryResult = mock<MwQueryResult>()
|
||||||
|
private val mockResponse = mock<MwQueryResponse>()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init mocks
|
* Init mocks
|
||||||
|
|
@ -42,28 +34,8 @@ class ReviewHelperTest {
|
||||||
@Before
|
@Before
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
MockitoAnnotations.openMocks(this)
|
whenever(mockResponse.query()).thenReturn(mwQueryResult)
|
||||||
|
whenever(reviewInterface.getRecentChanges()).thenReturn(Observable.just(mockResponse))
|
||||||
val mwQueryPage = mock(MwQueryPage::class.java)
|
|
||||||
val mockRevision = mock(MwQueryPage.Revision::class.java)
|
|
||||||
`when`(mockRevision.user).thenReturn("TestUser")
|
|
||||||
`when`(mwQueryPage.revisions()).thenReturn(listOf(mockRevision))
|
|
||||||
|
|
||||||
val mwQueryResult = mock(MwQueryResult::class.java)
|
|
||||||
`when`(mwQueryResult.firstPage()).thenReturn(mwQueryPage)
|
|
||||||
`when`(mwQueryResult.pages()).thenReturn(listOf(mwQueryPage))
|
|
||||||
val mockResponse = mock(MwQueryResponse::class.java)
|
|
||||||
`when`(mockResponse.query()).thenReturn(mwQueryResult)
|
|
||||||
`when`(reviewInterface?.getRecentChanges())
|
|
||||||
.thenReturn(Observable.just(mockResponse))
|
|
||||||
|
|
||||||
`when`(reviewInterface?.getFirstRevisionOfFile(ArgumentMatchers.anyString()))
|
|
||||||
.thenReturn(Observable.just(mockResponse))
|
|
||||||
|
|
||||||
val media = mock(Media::class.java)
|
|
||||||
whenever(media.filename).thenReturn("Test file.jpg")
|
|
||||||
`when`(mediaClient?.getMedia(ArgumentMatchers.anyString()))
|
|
||||||
.thenReturn(Single.just(media))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -71,14 +43,19 @@ class ReviewHelperTest {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
fun getRandomMedia() {
|
fun getRandomMedia() {
|
||||||
`when`(mediaClient?.checkPageExistsUsingTitle(ArgumentMatchers.anyString()))
|
whenever(mediaClient.checkPageExistsUsingTitle(any())).thenReturn(Single.just(false))
|
||||||
.thenReturn(Single.just(false))
|
|
||||||
|
|
||||||
`when`(mediaClient?.checkPageExistsUsingTitle(ArgumentMatchers.anyString()))
|
val page1 = setupMedia("one.jpg")
|
||||||
.thenReturn(Single.just(false))
|
val page2 = setupMedia("two.jpeg")
|
||||||
|
val page3 = setupMedia("three.png")
|
||||||
|
val ignored = setupMedia("ignored.txt")
|
||||||
|
whenever(mwQueryResult.pages()).thenReturn(listOf(page1, page2, page3, ignored))
|
||||||
|
|
||||||
reviewHelper?.randomMedia
|
val random = reviewHelper.getRandomMedia().test()
|
||||||
verify(reviewInterface, times(1))!!.getRecentChanges()
|
|
||||||
|
random.assertNoErrors()
|
||||||
|
assertEquals(1, random.valueCount())
|
||||||
|
assertTrue(setOf("one.jpg", "two.jpeg", "three.png").contains(random.values().first().filename))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -86,9 +63,12 @@ class ReviewHelperTest {
|
||||||
*/
|
*/
|
||||||
@Test(expected = RuntimeException::class)
|
@Test(expected = RuntimeException::class)
|
||||||
fun getRandomMediaWithWithAllMediaNominatedForDeletion() {
|
fun getRandomMediaWithWithAllMediaNominatedForDeletion() {
|
||||||
`when`(mediaClient?.checkPageExistsUsingTitle(ArgumentMatchers.anyString()))
|
whenever(mediaClient.checkPageExistsUsingTitle(any())).thenReturn(Single.just(true))
|
||||||
.thenReturn(Single.just(true))
|
|
||||||
val media = reviewHelper?.randomMedia?.blockingGet()
|
val page1 = setupMedia("one.jpg")
|
||||||
|
whenever(mwQueryResult.pages()).thenReturn(listOf(page1))
|
||||||
|
|
||||||
|
val media = reviewHelper.getRandomMedia().blockingGet()
|
||||||
assertNull(media)
|
assertNull(media)
|
||||||
verify(reviewInterface, times(1))!!.getRecentChanges()
|
verify(reviewInterface, times(1))!!.getRecentChanges()
|
||||||
}
|
}
|
||||||
|
|
@ -98,15 +78,14 @@ class ReviewHelperTest {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
fun getRandomMediaWithWithOneMediaNominatedForDeletion() {
|
fun getRandomMediaWithWithOneMediaNominatedForDeletion() {
|
||||||
`when`(mediaClient?.checkPageExistsUsingTitle("Commons:Deletion_requests/File:Test1.jpeg"))
|
whenever(mediaClient.checkPageExistsUsingTitle("Commons:Deletion_requests/one.jpg")).thenReturn(Single.just(true))
|
||||||
.thenReturn(Single.just(true))
|
|
||||||
`when`(mediaClient?.checkPageExistsUsingTitle("Commons:Deletion_requests/File:Test2.png"))
|
|
||||||
.thenReturn(Single.just(false))
|
|
||||||
`when`(mediaClient?.checkPageExistsUsingTitle("Commons:Deletion_requests/File:Test3.jpg"))
|
|
||||||
.thenReturn(Single.just(true))
|
|
||||||
|
|
||||||
reviewHelper?.randomMedia
|
val page1 = setupMedia("one.jpg")
|
||||||
verify(reviewInterface, times(1))!!.getRecentChanges()
|
whenever(mwQueryResult.pages()).thenReturn(listOf(page1))
|
||||||
|
|
||||||
|
val random = reviewHelper.getRandomMedia().test()
|
||||||
|
|
||||||
|
assertEquals("one.jpg is deleted", random.errors().first().message)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -114,57 +93,55 @@ class ReviewHelperTest {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
fun getFirstRevisionOfFile() {
|
fun getFirstRevisionOfFile() {
|
||||||
val firstRevisionOfFile = reviewHelper?.getFirstRevisionOfFile("Test.jpg")?.blockingFirst()
|
val rev1 = mock<MwQueryPage.Revision>()
|
||||||
|
whenever(rev1.user).thenReturn("TestUser")
|
||||||
|
whenever(rev1.revisionId).thenReturn(1L)
|
||||||
|
val rev2 = mock<MwQueryPage.Revision>()
|
||||||
|
whenever(rev2.user).thenReturn("TestUser")
|
||||||
|
whenever(rev2.revisionId).thenReturn(2L)
|
||||||
|
|
||||||
assertTrue(firstRevisionOfFile is MwQueryPage.Revision)
|
val page = setupMedia("Test.jpg", rev1, rev2)
|
||||||
|
whenever(mwQueryResult.firstPage()).thenReturn(page)
|
||||||
|
whenever(reviewInterface.getFirstRevisionOfFile(any())).thenReturn(Observable.just(mockResponse))
|
||||||
|
|
||||||
|
val firstRevisionOfFile = reviewHelper.getFirstRevisionOfFile("Test.jpg").blockingFirst()
|
||||||
|
|
||||||
|
assertEquals(1, firstRevisionOfFile.revisionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test the review status of the image
|
|
||||||
* Case 1: Image identifier exists in the database
|
|
||||||
*/
|
|
||||||
@Test
|
@Test
|
||||||
fun getReviewStatusWhenImageHasBeenReviewedAlready() {
|
fun checkFileUsage() {
|
||||||
val testImageId1 = "123456"
|
whenever(reviewInterface.getGlobalUsageInfo(any())).thenReturn(Observable.just(mockResponse))
|
||||||
`when`(dao.isReviewedAlready(testImageId1)).thenReturn(true)
|
val page = setupMedia("Test.jpg")
|
||||||
|
whenever(mwQueryResult.firstPage()).thenReturn(page)
|
||||||
|
whenever(page.checkWhetherFileIsUsedInWikis()).thenReturn(true)
|
||||||
|
|
||||||
val observer = io.reactivex.observers.TestObserver<Boolean>()
|
val result = reviewHelper.checkFileUsage("Test.jpg").test()
|
||||||
Observable.fromCallable(Callable<Boolean> {
|
|
||||||
dao.isReviewedAlready(testImageId1)
|
assertTrue(result.values().first())
|
||||||
}).subscribeWith(observer)
|
|
||||||
observer.assertValue(true)
|
|
||||||
observer.dispose()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test the review status of the image
|
|
||||||
* Case 2: Image identifier does not exist in the database
|
|
||||||
*/
|
|
||||||
@Test
|
@Test
|
||||||
fun getReviewStatusWhenImageHasBeenNotReviewedAlready() {
|
fun testReviewStatus() {
|
||||||
val testImageId2 = "789101"
|
val reviewDao = mock<ReviewDao>()
|
||||||
`when`(dao.isReviewedAlready(testImageId2)).thenReturn(false)
|
whenever(reviewDao.isReviewedAlready("Test.jpg")).thenReturn(true)
|
||||||
|
|
||||||
val observer = io.reactivex.observers.TestObserver<Boolean>()
|
reviewHelper.dao = reviewDao
|
||||||
Observable.fromCallable(Callable<Boolean> {
|
val result = reviewHelper.getReviewStatus("Test.jpg")
|
||||||
dao.isReviewedAlready(testImageId2)
|
|
||||||
}).subscribeWith(observer)
|
assertTrue(result)
|
||||||
observer.assertValue(false)
|
|
||||||
observer.dispose()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private fun setupMedia(file: String, vararg revision: MwQueryPage.Revision): MwQueryPage = mock<MwQueryPage>().apply {
|
||||||
* Test the successful insertion of the image identifier into the database
|
whenever(title()).thenReturn(file)
|
||||||
*/
|
if (revision.isNotEmpty()) {
|
||||||
@Test
|
whenever(revisions()).thenReturn(*revision.toMutableList())
|
||||||
fun addViewedImagesToDB() {
|
}
|
||||||
val testImageId = "123456"
|
|
||||||
|
|
||||||
val observer = io.reactivex.observers.TestObserver<Boolean>()
|
val media = mock<Media>().apply {
|
||||||
Completable.fromAction {
|
whenever(filename).thenReturn(file)
|
||||||
dao.insert(ReviewEntity(testImageId))
|
whenever(pageId).thenReturn(file.split(".").first())
|
||||||
}.subscribeWith(observer)
|
}
|
||||||
observer.assertComplete()
|
whenever(mediaClient.getMedia(file)).thenReturn(Single.just(media))
|
||||||
observer.dispose()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,84 @@
|
||||||
package fr.free.nrw.commons.wikidata
|
package fr.free.nrw.commons.wikidata
|
||||||
|
|
||||||
|
import com.nhaarman.mockitokotlin2.whenever
|
||||||
|
import fr.free.nrw.commons.auth.csrf.CsrfTokenClient
|
||||||
|
import fr.free.nrw.commons.upload.UploadResult
|
||||||
|
import fr.free.nrw.commons.upload.WikiBaseInterface
|
||||||
|
import fr.free.nrw.commons.wikidata.mwapi.MwPostResponse
|
||||||
|
import fr.free.nrw.commons.wikidata.mwapi.MwQueryPage
|
||||||
|
import fr.free.nrw.commons.wikidata.mwapi.MwQueryResponse
|
||||||
|
import fr.free.nrw.commons.wikidata.mwapi.MwQueryResult
|
||||||
|
import io.reactivex.Observable
|
||||||
|
import junit.framework.TestCase.assertEquals
|
||||||
|
import junit.framework.TestCase.assertSame
|
||||||
|
import junit.framework.TestCase.assertTrue
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mockito.InjectMocks
|
import org.mockito.Mockito.mock
|
||||||
import org.mockito.Mock
|
|
||||||
import org.mockito.Mockito
|
|
||||||
import org.mockito.MockitoAnnotations
|
|
||||||
import fr.free.nrw.commons.auth.csrf.CsrfTokenClient
|
|
||||||
|
|
||||||
class WikiBaseClientUnitTest {
|
class WikiBaseClientUnitTest {
|
||||||
|
|
||||||
@Mock
|
private val csrfTokenClient: CsrfTokenClient = mock()
|
||||||
internal var csrfTokenClient: CsrfTokenClient? = null
|
private val wikiBaseInterface: WikiBaseInterface = mock()
|
||||||
|
private val wikiBaseClient = WikiBaseClient(wikiBaseInterface, csrfTokenClient)
|
||||||
@InjectMocks
|
|
||||||
var wikiBaseClient: WikiBaseClient? = null
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
MockitoAnnotations.openMocks(this)
|
whenever(csrfTokenClient.getTokenBlocking()).thenReturn("test")
|
||||||
Mockito.`when`(csrfTokenClient!!.getTokenBlocking())
|
}
|
||||||
.thenReturn("test")
|
|
||||||
|
@Test
|
||||||
|
fun testPostEditEntity() {
|
||||||
|
val response = mock<MwPostResponse>()
|
||||||
|
whenever(response.successVal).thenReturn(1)
|
||||||
|
whenever(wikiBaseInterface.postEditEntity("the-id", "test", "the-data"))
|
||||||
|
.thenReturn(Observable.just(response))
|
||||||
|
|
||||||
|
val result = wikiBaseClient.postEditEntity("the-id", "the-data").blockingFirst()
|
||||||
|
|
||||||
|
assertTrue(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testPostEditEntityByFilename() {
|
fun testPostEditEntityByFilename() {
|
||||||
wikiBaseClient?.postEditEntityByFilename("File:Example.jpg", "data")
|
val response = mock<MwPostResponse>()
|
||||||
|
whenever(response.successVal).thenReturn(1)
|
||||||
|
whenever(wikiBaseInterface.postEditEntityByFilename("File:Example.jpg", "test", "the-data"))
|
||||||
|
.thenReturn(Observable.just(response))
|
||||||
|
|
||||||
|
val result = wikiBaseClient.postEditEntityByFilename("File:Example.jpg", "the-data").blockingFirst()
|
||||||
|
|
||||||
|
assertTrue(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getFileEntityId() {
|
||||||
|
val upload = UploadResult("result", "key", 0, "Example.jpg")
|
||||||
|
|
||||||
|
val response = mock<MwQueryResponse>()
|
||||||
|
val query = mock<MwQueryResult>()
|
||||||
|
val page = mock<MwQueryPage>()
|
||||||
|
whenever(response.query()).thenReturn(query)
|
||||||
|
whenever(query.pages()).thenReturn(mutableListOf(page))
|
||||||
|
whenever(page.pageId()).thenReturn(123)
|
||||||
|
whenever(wikiBaseInterface.getFileEntityId("File:Example.jpg"))
|
||||||
|
.thenReturn(Observable.just(response))
|
||||||
|
|
||||||
|
val result = wikiBaseClient.getFileEntityId(upload).blockingFirst()
|
||||||
|
|
||||||
|
assertEquals(123L, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun addLabelstoWikidata() {
|
||||||
|
val mwPostResponse = mock<MwPostResponse>()
|
||||||
|
whenever(wikiBaseInterface.addLabelstoWikidata(
|
||||||
|
"M123", "test", "en", "caption"
|
||||||
|
)).thenReturn(Observable.just(mwPostResponse))
|
||||||
|
|
||||||
|
val result = wikiBaseClient.addLabelstoWikidata(123L, "en", "caption").blockingFirst()
|
||||||
|
|
||||||
|
assertSame(mwPostResponse, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ package fr.free.nrw.commons.wikidata
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
|
import com.nhaarman.mockitokotlin2.anyOrNull
|
||||||
import com.nhaarman.mockitokotlin2.mock
|
import com.nhaarman.mockitokotlin2.mock
|
||||||
import com.nhaarman.mockitokotlin2.whenever
|
import com.nhaarman.mockitokotlin2.whenever
|
||||||
import fr.free.nrw.commons.kvstore.JsonKvStore
|
import fr.free.nrw.commons.kvstore.JsonKvStore
|
||||||
|
|
@ -61,7 +62,7 @@ class WikidataEditServiceTest {
|
||||||
fun createImageClaim() {
|
fun createImageClaim() {
|
||||||
whenever(directKvStore.getBoolean("Picture_Has_Correct_Location", true))
|
whenever(directKvStore.getBoolean("Picture_Has_Correct_Location", true))
|
||||||
.thenReturn(true)
|
.thenReturn(true)
|
||||||
whenever(wikibaseClient.getFileEntityId(any())).thenReturn(Observable.just(1L))
|
whenever(wikibaseClient.getFileEntityId(anyOrNull())).thenReturn(Observable.just(1L))
|
||||||
whenever(wikidataClient.setClaim(any(), anyString()))
|
whenever(wikidataClient.setClaim(any(), anyString()))
|
||||||
.thenReturn(Observable.just(1L))
|
.thenReturn(Observable.just(1L))
|
||||||
val wikidataPlace: WikidataPlace = mock()
|
val wikidataPlace: WikidataPlace = mock()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue