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,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() }
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue