Set Media legend for wikidata entity (#3838)

* Set media legends and P18

* Minor

* Make media legends work

* Add test cases

* Use statement partial

* With minor refactoring

* Fix build
This commit is contained in:
Vivek Maskara 2020-06-30 05:11:27 -07:00 committed by GitHub
parent 7caf73fb4b
commit f26784e9c3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 195 additions and 199 deletions

View file

@ -76,7 +76,7 @@ dependencies {
testImplementation "org.powermock:powermock-api-mockito2:2.0.0-beta.5" testImplementation "org.powermock:powermock-api-mockito2:2.0.0-beta.5"
// Unit testing // Unit testing
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.13'
testImplementation 'org.robolectric:robolectric:4.3' testImplementation 'org.robolectric:robolectric:4.3'
testImplementation 'androidx.test:core:1.2.0' testImplementation 'androidx.test:core:1.2.0'
testImplementation 'com.squareup.okhttp3:mockwebserver:3.12.1' testImplementation 'com.squareup.okhttp3:mockwebserver:3.12.1'

View file

@ -31,6 +31,7 @@ import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import fr.free.nrw.commons.media.MediaClient; import fr.free.nrw.commons.media.MediaClient;
import fr.free.nrw.commons.utils.DialogUtil; import fr.free.nrw.commons.utils.DialogUtil;
import fr.free.nrw.commons.wikidata.WikidataEditService;
import java.util.Locale; import java.util.Locale;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@ -41,7 +42,8 @@ import org.wikipedia.dataclient.WikiSite;
*/ */
public class ContributionsListFragment extends CommonsDaggerSupportFragment implements public class ContributionsListFragment extends CommonsDaggerSupportFragment implements
ContributionsListContract.View, ContributionsListAdapter.Callback, WikipediaInstructionsDialogFragment.Callback { ContributionsListContract.View, ContributionsListAdapter.Callback,
WikipediaInstructionsDialogFragment.Callback {
private static final String RV_STATE = "rv_scroll_state"; private static final String RV_STATE = "rv_scroll_state";
@ -275,7 +277,6 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
} }
public Media getMediaAtPosition(final int i) { public Media getMediaAtPosition(final int i) {
return adapter.getContributionForPosition(i); return adapter.getContributionForPosition(i);
} }
@ -296,7 +297,8 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
Utils.copy("wikicode", wikicode, getContext()); Utils.copy("wikicode", wikicode, getContext());
} }
final String url = languageWikipediaSite.mobileUrl() + "/wiki/" + contribution.getWikidataPlace() final String url =
languageWikipediaSite.mobileUrl() + "/wiki/" + contribution.getWikidataPlace()
.getWikipediaPageTitle(); .getWikipediaPageTitle();
Utils.handleWebUrl(getContext(), Uri.parse(url)); Utils.handleWebUrl(getContext(), Uri.parse(url));
} }

View file

@ -21,24 +21,16 @@ import fr.free.nrw.commons.contributions.MainActivity;
import fr.free.nrw.commons.di.CommonsApplicationModule; import fr.free.nrw.commons.di.CommonsApplicationModule;
import fr.free.nrw.commons.di.CommonsDaggerService; import fr.free.nrw.commons.di.CommonsDaggerService;
import fr.free.nrw.commons.media.MediaClient; import fr.free.nrw.commons.media.MediaClient;
import fr.free.nrw.commons.utils.CommonsDateUtil;
import fr.free.nrw.commons.wikidata.WikidataEditService; import fr.free.nrw.commons.wikidata.WikidataEditService;
import io.reactivex.Completable;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.Scheduler; import io.reactivex.Scheduler;
import io.reactivex.Single;
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Action;
import io.reactivex.functions.Consumer;
import io.reactivex.processors.PublishProcessor; import io.reactivex.processors.PublishProcessor;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.text.ParseException;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.inject.Inject; import javax.inject.Inject;
@ -313,7 +305,7 @@ public class UploadService extends CommonsDaggerService {
.add(wikidataEditService.addDepictionsAndCaptions(uploadResult, contribution)); .add(wikidataEditService.addDepictionsAndCaptions(uploadResult, contribution));
WikidataPlace wikidataPlace = contribution.getWikidataPlace(); WikidataPlace wikidataPlace = contribution.getWikidataPlace();
if (wikidataPlace != null && wikidataPlace.getImageValue() == null) { if (wikidataPlace != null && wikidataPlace.getImageValue() == null) {
wikidataEditService.createImageClaim(wikidataPlace, uploadResult); wikidataEditService.createClaim(wikidataPlace, uploadResult.getFilename(), contribution.getCaptions());
} }
saveCompletedContribution(contribution, uploadResult); saveCompletedContribution(contribution, uploadResult);
} }

View file

@ -1,6 +1,6 @@
package fr.free.nrw.commons.wikidata; package fr.free.nrw.commons.wikidata;
import fr.free.nrw.commons.upload.WikidataItem; import com.google.gson.Gson;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import javax.inject.Inject; import javax.inject.Inject;
@ -9,64 +9,38 @@ import javax.inject.Singleton;
import fr.free.nrw.commons.wikidata.model.AddEditTagResponse; import fr.free.nrw.commons.wikidata.model.AddEditTagResponse;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.ObservableSource; import io.reactivex.ObservableSource;
import okhttp3.MediaType; import org.wikipedia.wikidata.Statement_partial;
import okhttp3.RequestBody;
@Singleton @Singleton
public class WikidataClient { public class WikidataClient {
private final WikidataInterface wikidataInterface; private final WikidataInterface wikidataInterface;
private final Gson gson;
@Inject @Inject
public WikidataClient(WikidataInterface wikidataInterface) { public WikidataClient(WikidataInterface wikidataInterface, final Gson gson) {
this.wikidataInterface = wikidataInterface; this.wikidataInterface = wikidataInterface;
this.gson = gson;
} }
/** /**
* Create wikidata claim to add P18 value * Create wikidata claim to add P18 value
* @param entity wikidata entity ID *
* @param value value of the P18 edit
* @return revisionID of the edit * @return revisionID of the edit
*/ */
Observable<Long> createImageClaim(WikidataItem entity, String value) { Observable<Long> setClaim(Statement_partial claim, String tags) {
return getCsrfToken() return getCsrfToken()
.flatMap(csrfToken -> wikidataInterface.postCreateClaim( .flatMap(csrfToken -> wikidataInterface.postSetClaim(gson.toJson(claim), tags, csrfToken))
toRequestBody(entity.getId()),
toRequestBody("value"),
toRequestBody(WikidataProperties.IMAGE.getPropertyName()),
toRequestBody(value),
toRequestBody("en"),
toRequestBody(csrfToken)))
.map(mwPostResponse -> mwPostResponse.getPageinfo().getLastrevid()); .map(mwPostResponse -> mwPostResponse.getPageinfo().getLastrevid());
} }
/**
* Converts string value to RequestBody for multipart request
*/
private RequestBody toRequestBody(String value) {
return RequestBody.create(MediaType.parse("text/plain"), value);
}
/** /**
* Get csrf token for wikidata edit * Get csrf token for wikidata edit
*/ */
@NotNull @NotNull
private Observable<String> getCsrfToken() { private Observable<String> getCsrfToken() {
return wikidataInterface.getCsrfToken().map(mwQueryResponse -> mwQueryResponse.query().csrfToken()); return wikidataInterface.getCsrfToken()
} .map(mwQueryResponse -> mwQueryResponse.query().csrfToken());
/**
* Add edit tag for a given revision ID. The app currently uses this to tag P18 edits
* @param revisionId revision ID of the page edited
* @param tag to be added
* @param reason to be mentioned
*/
ObservableSource<AddEditTagResponse> addEditTag(Long revisionId, String tag, String reason) {
return getCsrfToken()
.flatMap(csrfToken -> wikidataInterface.addEditTag(String.valueOf(revisionId),
tag,
reason,
csrfToken));
} }
} }

View file

@ -20,24 +20,33 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable; import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.wikipedia.dataclient.mwapi.MwPostResponse; import org.wikipedia.dataclient.mwapi.MwPostResponse;
import org.wikipedia.wikidata.DataValue;
import org.wikipedia.wikidata.DataValue.ValueString;
import org.wikipedia.wikidata.EditClaim; import org.wikipedia.wikidata.EditClaim;
import org.wikipedia.wikidata.Snak_partial;
import org.wikipedia.wikidata.Statement_partial;
import org.wikipedia.wikidata.WikiBaseMonolingualTextValue;
import timber.log.Timber; import timber.log.Timber;
/** /**
* This class is meant to handle the Wikidata edits made through the app * This class is meant to handle the Wikidata edits made through the app It will talk with MediaWiki
* It will talk with MediaWiki Apis to make the necessary calls, log the edits and fire listeners * Apis to make the necessary calls, log the edits and fire listeners on successful edits
* on successful edits
*/ */
@Singleton @Singleton
public class WikidataEditService { public class WikidataEditService {
private static final String COMMONS_APP_TAG = "wikimedia-commons-app"; public static final String COMMONS_APP_TAG = "wikimedia-commons-app";
private static final String COMMONS_APP_EDIT_REASON = "Add tag for edits made using Android Commons app";
private final Context context; private final Context context;
private final WikidataEditListener wikidataEditListener; private final WikidataEditListener wikidataEditListener;
@ -61,8 +70,8 @@ public class WikidataEditService {
} }
/** /**
* Edits the wikibase entity by adding DEPICTS property. * Edits the wikibase entity by adding DEPICTS property. Adding DEPICTS property requires call to
* Adding DEPICTS property requires call to the wikibase API to set tag against the entity. * the wikibase API to set tag against the entity.
*/ */
@SuppressLint("CheckResult") @SuppressLint("CheckResult")
private Observable<Boolean> addDepictsProperty(final String fileEntityId, private Observable<Boolean> addDepictsProperty(final String fileEntityId,
@ -97,12 +106,14 @@ public class WikidataEditService {
*/ */
private void showSuccessToast(final String wikiItemName) { private void showSuccessToast(final String wikiItemName) {
final String successStringTemplate = context.getString(R.string.successful_wikidata_edit); final String successStringTemplate = context.getString(R.string.successful_wikidata_edit);
final String successMessage = String.format(Locale.getDefault(), successStringTemplate, wikiItemName); final String successMessage = String
.format(Locale.getDefault(), successStringTemplate, wikiItemName);
ViewUtil.showLongToast(context, successMessage); ViewUtil.showLongToast(context, successMessage);
} }
/** /**
* Adds label to Wikidata using the fileEntityId and the edit token, obtained from csrfTokenClient * Adds label to Wikidata using the fileEntityId and the edit token, obtained from
* csrfTokenClient
* *
* @param fileEntityId * @param fileEntityId
* @return * @return
@ -128,29 +139,41 @@ public class WikidataEditService {
} }
} }
public void createImageClaim(@Nullable final WikidataPlace wikidataPlace, final UploadResult imageUpload) { public void createClaim(@Nullable final WikidataPlace wikidataPlace, final String fileName, final
Map<String, String> captions) {
if (!(directKvStore.getBoolean("Picture_Has_Correct_Location", true))) { if (!(directKvStore.getBoolean("Picture_Has_Correct_Location", true))) {
Timber.d("Image location and nearby place location mismatched, so Wikidata item won't be edited"); Timber
.d("Image location and nearby place location mismatched, so Wikidata item won't be edited");
return; return;
} }
editWikidataImageProperty(wikidataPlace, imageUpload); addImageAndMediaLegends(wikidataPlace, fileName, captions);
} }
@SuppressLint("CheckResult") public void addImageAndMediaLegends(final WikidataItem wikidataItem, final String fileName,
private void editWikidataImageProperty(final WikidataItem wikidataItem, final UploadResult imageUpload) { final Map<String, String> captions) {
wikidataClient.createImageClaim(wikidataItem, String.format("\"%s\"", imageUpload.getFilename())) final Snak_partial p18 = new Snak_partial("value", WikidataProperties.IMAGE.getPropertyName(),
.flatMap(revisionId -> { new ValueString(fileName.replace("File:", "")));
if (revisionId != -1) {
return wikidataClient.addEditTag(revisionId, COMMONS_APP_TAG, COMMONS_APP_EDIT_REASON); final List<Snak_partial> snaks = new ArrayList<>();
for (final Map.Entry<String, String> entry : captions.entrySet()) {
snaks.add(new Snak_partial("value",
WikidataProperties.MEDIA_LEGENDS.getPropertyName(), new DataValue.MonoLingualText(
new WikiBaseMonolingualTextValue(entry.getValue(), entry.getKey()))));
} }
throw new RuntimeException("Unable to edit wikidata item");
}) final String id = wikidataItem.getId() + "$" + UUID.randomUUID().toString();
.subscribeOn(Schedulers.io()) final Statement_partial claim = new Statement_partial(p18, "statement", "normal", id,
Collections.singletonMap(WikidataProperties.MEDIA_LEGENDS.getPropertyName(), snaks),
Arrays.asList(WikidataProperties.MEDIA_LEGENDS.getPropertyName()));
wikidataClient.setClaim(claim, COMMONS_APP_TAG).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(revisionId -> handleImageClaimResult(wikidataItem, String.valueOf(revisionId)), throwable -> { .subscribe(revisionId -> handleImageClaimResult(wikidataItem, String.valueOf(revisionId)),
throwable -> {
Timber.e(throwable, "Error occurred while making claim"); Timber.e(throwable, "Error occurred while making claim");
ViewUtil.showLongToast(context, context.getString(R.string.wikidata_edit_failure)); ViewUtil.showLongToast(context, context.getString(R.string.wikidata_edit_failure));
}); });
;
} }
private void handleImageClaimResult(final WikidataItem wikidataItem, final String revisionId) { private void handleImageClaimResult(final WikidataItem wikidataItem, final String revisionId) {

View file

@ -2,6 +2,7 @@ package fr.free.nrw.commons.wikidata;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.google.gson.JsonObject;
import org.wikipedia.dataclient.mwapi.MwQueryResponse; import org.wikipedia.dataclient.mwapi.MwQueryResponse;
import fr.free.nrw.commons.wikidata.model.AddEditTagResponse; import fr.free.nrw.commons.wikidata.model.AddEditTagResponse;
@ -20,30 +21,6 @@ import static org.wikipedia.dataclient.Service.MW_API_PREFIX;
public interface WikidataInterface { public interface WikidataInterface {
/**
* Wikidata create claim API. Posts a new claim for the given entity ID
*/
@Headers("Cache-Control: no-cache")
@POST("w/api.php?format=json&errorformat=plaintext&action=wbcreateclaim&errorlang=uselang")
@Multipart
Observable<WbCreateClaimResponse> postCreateClaim(@NonNull @Part("entity") RequestBody entity,
@NonNull @Part("snaktype") RequestBody snakType,
@NonNull @Part("property") RequestBody property,
@NonNull @Part("value") RequestBody value,
@NonNull @Part("uselang") RequestBody useLang,
@NonNull @Part("token") RequestBody token);
/**
* Add edit tag and reason for any revision
*/
@Headers("Cache-Control: no-cache")
@POST(MW_API_PREFIX + "action=tag")
@FormUrlEncoded
Observable<AddEditTagResponse> addEditTag(@NonNull @Field("revid") String revId,
@NonNull @Field("add") String tagName,
@NonNull @Field("reason") String reason,
@NonNull @Field("token") String token);
/** /**
* Get edit token for wikidata wiki site * Get edit token for wikidata wiki site
*/ */
@ -51,4 +28,14 @@ public interface WikidataInterface {
@GET(MW_API_PREFIX + "action=query&meta=tokens&type=csrf") @GET(MW_API_PREFIX + "action=query&meta=tokens&type=csrf")
@NonNull @NonNull
Observable<MwQueryResponse> getCsrfToken(); Observable<MwQueryResponse> getCsrfToken();
/**
* Wikidata create claim API. Posts a new claim for the given entity ID
*/
@Headers("Cache-Control: no-cache")
@POST("w/api.php?format=json&action=wbsetclaim")
@FormUrlEncoded
Observable<WbCreateClaimResponse> postSetClaim(@NonNull @Field("claim") String request,
@NonNull @Field("tags") String tags,
@NonNull @Field("token") String token);
} }

View file

@ -6,5 +6,6 @@ enum class WikidataProperties(val propertyName: String) {
IMAGE("P18"), IMAGE("P18"),
DEPICTS(BuildConfig.DEPICTS_PROPERTY), DEPICTS(BuildConfig.DEPICTS_PROPERTY),
COMMONS_CATEGORY("P373"), COMMONS_CATEGORY("P373"),
INSTANCE_OF("P31"); INSTANCE_OF("P31"),
MEDIA_LEGENDS("P2096");
} }

View file

@ -1,7 +1,9 @@
package fr.free.nrw.commons.wikidata package fr.free.nrw.commons.wikidata
import com.nhaarman.mockitokotlin2.mock import com.google.gson.Gson
import fr.free.nrw.commons.wikidata.model.AddEditTagResponse import com.nhaarman.mockitokotlin2.whenever
import fr.free.nrw.commons.wikidata.model.PageInfo
import fr.free.nrw.commons.wikidata.model.WbCreateClaimResponse
import io.reactivex.Observable import io.reactivex.Observable
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@ -14,12 +16,16 @@ import org.mockito.Mockito.mock
import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations
import org.wikipedia.dataclient.mwapi.MwQueryResponse import org.wikipedia.dataclient.mwapi.MwQueryResponse
import org.wikipedia.dataclient.mwapi.MwQueryResult import org.wikipedia.dataclient.mwapi.MwQueryResult
import org.wikipedia.wikidata.Statement_partial
class WikidataClientTest { class WikidataClientTest {
@Mock @Mock
internal var wikidataInterface: WikidataInterface? = null internal var wikidataInterface: WikidataInterface? = null
@Mock
internal var gson: Gson? = null
@InjectMocks @InjectMocks
var wikidataClient: WikidataClient? = null var wikidataClient: WikidataClient? = null
@ -35,26 +41,18 @@ class WikidataClientTest {
.thenReturn(Observable.just(mwQueryResponse)) .thenReturn(Observable.just(mwQueryResponse))
} }
@Test
fun createClaim() {
`when`(
wikidataInterface!!.postCreateClaim(
any(),
any(),
any(),
any(),
any(),
any()
)
)
.thenReturn(Observable.just(mock()))
wikidataClient!!.createImageClaim(mock(), "test.jpg")
}
@Test @Test
fun addEditTag() { fun addEditTag() {
`when`(wikidataInterface!!.addEditTag(anyString(), anyString(), anyString(), anyString())) val response = mock(WbCreateClaimResponse::class.java)
.thenReturn(Observable.just(mock(AddEditTagResponse::class.java))) val pageInfo = mock(PageInfo::class.java)
wikidataClient!!.addEditTag(1L, "test", "test") whenever(pageInfo.lastrevid).thenReturn(1)
whenever(response.pageinfo).thenReturn(pageInfo)
`when`(wikidataInterface!!.postSetClaim(anyString(), anyString(), anyString()))
.thenReturn(Observable.just(response))
whenever(gson!!.toJson(any(Statement_partial::class.java))).thenReturn("claim")
val request = mock(Statement_partial::class.java)
val claim = wikidataClient!!.setClaim(request, "test").test()
.assertValue(1L)
} }
} }

View file

@ -1,13 +1,13 @@
package fr.free.nrw.commons.wikidata package fr.free.nrw.commons.wikidata
import android.content.Context import android.content.Context
import com.google.gson.Gson
import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.verifyZeroInteractions import com.nhaarman.mockitokotlin2.verifyZeroInteractions
import com.nhaarman.mockitokotlin2.whenever import com.nhaarman.mockitokotlin2.whenever
import fr.free.nrw.commons.kvstore.JsonKvStore import fr.free.nrw.commons.kvstore.JsonKvStore
import fr.free.nrw.commons.upload.UploadResult import fr.free.nrw.commons.upload.UploadResult
import fr.free.nrw.commons.upload.WikidataPlace import fr.free.nrw.commons.upload.WikidataPlace
import fr.free.nrw.commons.wikidata.model.AddEditTagResponse
import io.reactivex.Observable import io.reactivex.Observable
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
@ -15,7 +15,6 @@ import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.anyString import org.mockito.ArgumentMatchers.anyString
import org.mockito.InjectMocks import org.mockito.InjectMocks
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito.*
import org.mockito.MockitoAnnotations import org.mockito.MockitoAnnotations
class WikidataEditServiceTest { class WikidataEditServiceTest {
@ -31,6 +30,9 @@ class WikidataEditServiceTest {
@Mock @Mock
internal lateinit var wikibaseClient: WikiBaseClient internal lateinit var wikibaseClient: WikiBaseClient
@Mock
internal lateinit var gson: Gson
@InjectMocks @InjectMocks
lateinit var wikidataEditService: WikidataEditService lateinit var wikidataEditService: WikidataEditService
@ -44,7 +46,7 @@ class WikidataEditServiceTest {
fun noClaimsWhenLocationIsNotCorrect() { fun noClaimsWhenLocationIsNotCorrect() {
whenever(directKvStore.getBoolean("Picture_Has_Correct_Location", true)) whenever(directKvStore.getBoolean("Picture_Has_Correct_Location", true))
.thenReturn(false) .thenReturn(false)
wikidataEditService.createImageClaim(mock(), mock()) wikidataEditService.createClaim(mock(), "Test.jpg", hashMapOf())
verifyZeroInteractions(wikidataClient) verifyZeroInteractions(wikidataClient)
} }
@ -52,15 +54,16 @@ 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(wikidataClient.createImageClaim(any(), any()))
.thenReturn(Observable.just(1L))
whenever(wikidataClient.addEditTag(anyLong(), anyString(), anyString()))
.thenReturn(Observable.just(mock(AddEditTagResponse::class.java)))
whenever(wikibaseClient.getFileEntityId(any())).thenReturn(Observable.just(1L)) whenever(wikibaseClient.getFileEntityId(any())).thenReturn(Observable.just(1L))
whenever(wikidataClient.setClaim(any(), anyString()))
.thenReturn(Observable.just(1L))
val wikidataPlace: WikidataPlace = mock() val wikidataPlace: WikidataPlace = mock()
val uploadResult = mock<UploadResult>() val uploadResult = mock<UploadResult>()
whenever(uploadResult.filename).thenReturn("file") whenever(uploadResult.filename).thenReturn("file")
wikidataEditService.createImageClaim(wikidataPlace, uploadResult) wikidataEditService.createClaim(
verify(wikidataClient, times(1)).createImageClaim(wikidataPlace, """"file"""") wikidataPlace,
uploadResult.filename,
hashMapOf<String, String>()
)
} }
} }

View file

@ -12,7 +12,7 @@ sealed class DataValue(val type: String) {
.registerSubtype(GlobeCoordinate_partial::class.java, GlobeCoordinate_partial.TYPE) .registerSubtype(GlobeCoordinate_partial::class.java, GlobeCoordinate_partial.TYPE)
.registerSubtype(Time_partial::class.java, Time_partial.TYPE) .registerSubtype(Time_partial::class.java, Time_partial.TYPE)
.registerSubtype(Quantity_partial::class.java, Quantity_partial.TYPE) .registerSubtype(Quantity_partial::class.java, Quantity_partial.TYPE)
.registerSubtype(MonoLingualText_partial::class.java, MonoLingualText_partial.TYPE) .registerSubtype(MonoLingualText::class.java, MonoLingualText.TYPE)
} }
// "value": { // "value": {
@ -87,7 +87,7 @@ sealed class DataValue(val type: String) {
// "language": "ko" // "language": "ko"
// } // }
// } // }
class MonoLingualText_partial() : DataValue(TYPE) { class MonoLingualText(val value: WikiBaseMonolingualTextValue) : DataValue(TYPE) {
companion object { companion object {
const val TYPE = "monolingualtext" const val TYPE = "monolingualtext"
} }

View file

@ -21,5 +21,8 @@ import com.google.gson.annotations.SerializedName
data class Statement_partial( data class Statement_partial(
@SerializedName("mainsnak") val mainSnak: Snak_partial, @SerializedName("mainsnak") val mainSnak: Snak_partial,
val type: String, val type: String,
val rank: String val rank: String,
val id: String? = null,
val qualifiers: Map<String, List<Snak_partial>> = mapOf(),
@SerializedName("qualifiers-order") val qualifiersOrder: List<String> = listOf()
) )

View file

@ -0,0 +1,13 @@
package org.wikipedia.wikidata
import com.google.gson.annotations.SerializedName
/*"value": {
"type": "monolingualtext",
"value": {
"text": "some value",
"language": "en"
}
}*/
data class WikiBaseMonolingualTextValue(val text: String, val language: String)