mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Convert wikidata/mwapi to kotlin (part 4) (#6010)
* Convert ImageDetails to kotlin * Convert MwException/MwServiceError to kotlin * Convert ListUserResponse to kotlin * Convert MwPostResponse to kotlin * Convert MwQueryResponse to kotlin * Convert MwQueryResult to kotlin * Convert MwQueryPage to kotlin --------- Co-authored-by: Nicolas Raoul <nicolas.raoul@gmail.com>
This commit is contained in:
parent
56ada36b83
commit
73311970c5
28 changed files with 474 additions and 615 deletions
|
|
@ -237,7 +237,7 @@ class LoginClient(
|
|||
.subscribe({ response: MwQueryResponse? ->
|
||||
loginResult.userId = response?.query()?.userInfo()?.id() ?: 0
|
||||
loginResult.groups =
|
||||
response?.query()?.getUserResponse(userName)?.groups ?: emptySet()
|
||||
response?.query()?.getUserResponse(userName)?.getGroups() ?: emptySet()
|
||||
cb.success(loginResult)
|
||||
}, { caught: Throwable ->
|
||||
Timber.e(caught, "Login succeeded but getting group information failed. ")
|
||||
|
|
|
|||
|
|
@ -938,7 +938,7 @@ class MediaDetailFragment : CommonsDaggerSupportFragment(), CategoryEditHelper.C
|
|||
|
||||
Observable.defer {
|
||||
thanksClient.thank(
|
||||
firstRevision.revisionId
|
||||
firstRevision.revisionId()
|
||||
)
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ class ReviewActivity : BaseActivity() {
|
|||
val caption = getString(
|
||||
R.string.review_is_uploaded_by,
|
||||
fileName,
|
||||
revision.user
|
||||
revision.user()
|
||||
)
|
||||
binding.tvImageCaption.text = caption
|
||||
binding.pbReviewImage.visibility = View.GONE
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException
|
|||
import fr.free.nrw.commons.wikidata.mwapi.MwQueryPage
|
||||
|
||||
import java.util.ArrayList
|
||||
import java.util.concurrent.Callable
|
||||
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Named
|
||||
|
|
@ -27,7 +26,6 @@ import fr.free.nrw.commons.delete.DeleteHelper
|
|||
import fr.free.nrw.commons.di.ApplicationlessInjection
|
||||
import fr.free.nrw.commons.utils.ViewUtil
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.ObservableSource
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import timber.log.Timber
|
||||
|
|
@ -175,7 +173,7 @@ class ReviewController @Inject constructor(
|
|||
if (firstRevision == null) return
|
||||
|
||||
Observable.defer {
|
||||
thanksClient.thank(firstRevision!!.revisionId)
|
||||
thanksClient.thank(firstRevision!!.revisionId())
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class ReviewHelper
|
|||
reviewInterface
|
||||
.getRecentChanges()
|
||||
.map { it.query()?.pages() }
|
||||
.map(MutableList<MwQueryPage>::shuffled)
|
||||
.map { it.shuffled() }
|
||||
.flatMapIterable { changes: List<MwQueryPage>? -> changes }
|
||||
.filter { isChangeReviewable(it) }
|
||||
|
||||
|
|
|
|||
|
|
@ -3,18 +3,15 @@ package fr.free.nrw.commons.review
|
|||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.text.Html
|
||||
import android.text.TextUtils
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import fr.free.nrw.commons.CommonsApplication
|
||||
import fr.free.nrw.commons.Media
|
||||
import fr.free.nrw.commons.R
|
||||
import fr.free.nrw.commons.auth.SessionManager
|
||||
import fr.free.nrw.commons.auth.csrf.InvalidLoginTokenException
|
||||
import fr.free.nrw.commons.databinding.FragmentReviewImageBinding
|
||||
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment
|
||||
import java.util.ArrayList
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
|
|
@ -126,7 +123,7 @@ class ReviewImageFragment : CommonsDaggerSupportFragment() {
|
|||
enableButtons()
|
||||
question = getString(R.string.review_thanks)
|
||||
|
||||
user = reviewActivity.reviewController.firstRevision?.user
|
||||
user = reviewActivity.reviewController.firstRevision?.user()
|
||||
?: savedInstanceState?.getString(SAVED_USER)
|
||||
|
||||
//if the user is null because of whatsoever reason, review will not be sent anyways
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ class UploadClient
|
|||
if (uploadResult.upload == null) {
|
||||
val exception = gson.fromJson(uploadResponse, MwException::class.java)
|
||||
Timber.e(exception, "Error in uploading file from stash")
|
||||
throw Exception(exception.getErrorCode())
|
||||
throw Exception(exception.errorCode)
|
||||
}
|
||||
uploadResult.upload
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
package fr.free.nrw.commons.wikidata.mwapi;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class ImageDetails {
|
||||
|
||||
private String name;
|
||||
private String title;
|
||||
|
||||
@NonNull public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@NonNull public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package fr.free.nrw.commons.wikidata.mwapi
|
||||
|
||||
class ImageDetails {
|
||||
val name: String? = null
|
||||
val title: String? = null
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
package fr.free.nrw.commons.wikidata.mwapi;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.collection.ArraySet;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
public class ListUserResponse {
|
||||
@SerializedName("name") @Nullable private String name;
|
||||
private long userid;
|
||||
@Nullable private List<String> groups;
|
||||
|
||||
@Nullable public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@NonNull public Set<String> getGroups() {
|
||||
return groups != null ? new ArraySet<>(groups) : Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package fr.free.nrw.commons.wikidata.mwapi
|
||||
|
||||
class ListUserResponse {
|
||||
private val name: String? = null
|
||||
private val userid: Long = 0
|
||||
private val groups: List<String>? = null
|
||||
|
||||
fun name(): String? = name
|
||||
|
||||
fun getGroups(): Set<String> =
|
||||
groups?.toSet() ?: emptySet()
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
package fr.free.nrw.commons.wikidata.mwapi;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
public class MwException extends RuntimeException {
|
||||
@Nullable private final MwServiceError error;
|
||||
|
||||
@Nullable private final List<MwServiceError> errors;
|
||||
|
||||
public MwException(@Nullable MwServiceError error,
|
||||
@Nullable final List<MwServiceError> errors) {
|
||||
this.error = error;
|
||||
this.errors = errors;
|
||||
}
|
||||
|
||||
public String getErrorCode() {
|
||||
if(error!=null) {
|
||||
return error.getCode();
|
||||
}
|
||||
return errors != null ? errors.get(0).getCode() : null;
|
||||
}
|
||||
|
||||
@Nullable public MwServiceError getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getTitle() {
|
||||
if (error != null) {
|
||||
return error.getTitle();
|
||||
}
|
||||
return errors != null ? errors.get(0).getTitle() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getMessage() {
|
||||
if (error != null) {
|
||||
return error.getDetails();
|
||||
}
|
||||
return errors != null ? errors.get(0).getDetails() : null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package fr.free.nrw.commons.wikidata.mwapi
|
||||
|
||||
class MwException(
|
||||
val error: MwServiceError?,
|
||||
private val errors: List<MwServiceError>?
|
||||
) : RuntimeException() {
|
||||
val errorCode: String?
|
||||
get() = error?.code ?: errors?.get(0)?.code
|
||||
|
||||
val title: String?
|
||||
get() = error?.title ?: errors?.get(0)?.title
|
||||
|
||||
override val message: String?
|
||||
get() = error?.details ?: errors?.get(0)?.details
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package fr.free.nrw.commons.wikidata.mwapi;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class MwPostResponse extends MwResponse {
|
||||
private int success;
|
||||
|
||||
public boolean success(@Nullable String result) {
|
||||
return "success".equals(result);
|
||||
}
|
||||
|
||||
public int getSuccessVal() {
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package fr.free.nrw.commons.wikidata.mwapi
|
||||
|
||||
open class MwPostResponse : MwResponse() {
|
||||
val successVal: Int = 0
|
||||
|
||||
fun success(result: String?): Boolean =
|
||||
"success" == result
|
||||
}
|
||||
|
||||
|
|
@ -1,229 +0,0 @@
|
|||
package fr.free.nrw.commons.wikidata.mwapi;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import fr.free.nrw.commons.wikidata.model.gallery.ImageInfo;
|
||||
import fr.free.nrw.commons.wikidata.model.BaseModel;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A class representing a standard page object as returned by the MediaWiki API.
|
||||
*/
|
||||
public class MwQueryPage extends BaseModel {
|
||||
private int pageid;
|
||||
private int index;
|
||||
@NonNull private String title;
|
||||
@NonNull private CategoryInfo categoryinfo;
|
||||
@Nullable private List<Revision> revisions;
|
||||
@SerializedName("fileusage") @Nullable private List<FileUsage> fileUsages;
|
||||
@SerializedName("globalusage") @Nullable private List<GlobalUsage> globalUsages;
|
||||
@Nullable private List<Coordinates> coordinates;
|
||||
@Nullable private List<Category> categories;
|
||||
@Nullable private Thumbnail thumbnail;
|
||||
@Nullable private String description;
|
||||
@SerializedName("imageinfo") @Nullable private List<ImageInfo> imageInfo;
|
||||
@Nullable private String redirectFrom;
|
||||
@Nullable private String convertedFrom;
|
||||
@Nullable private String convertedTo;
|
||||
|
||||
@NonNull public String title() {
|
||||
return title;
|
||||
}
|
||||
|
||||
@NonNull public CategoryInfo categoryInfo() {
|
||||
return categoryinfo;
|
||||
}
|
||||
|
||||
public int index() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Nullable public List<Revision> revisions() {
|
||||
return revisions;
|
||||
}
|
||||
|
||||
@Nullable public List<Category> categories() {
|
||||
return categories;
|
||||
}
|
||||
|
||||
@Nullable public List<Coordinates> coordinates() {
|
||||
// TODO: Handle null values in lists during deserialization, perhaps with a new
|
||||
// @RequiredElements annotation and corresponding TypeAdapter
|
||||
if (coordinates != null) {
|
||||
coordinates.removeAll(Collections.singleton(null));
|
||||
}
|
||||
return coordinates;
|
||||
}
|
||||
|
||||
public int pageId() {
|
||||
return pageid;
|
||||
}
|
||||
|
||||
@Nullable public String thumbUrl() {
|
||||
return thumbnail != null ? thumbnail.source() : null;
|
||||
}
|
||||
|
||||
@Nullable public String description() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Nullable public ImageInfo imageInfo() {
|
||||
return imageInfo != null ? imageInfo.get(0) : null;
|
||||
}
|
||||
|
||||
public void redirectFrom(@Nullable String from) {
|
||||
redirectFrom = from;
|
||||
}
|
||||
|
||||
public void convertedFrom(@Nullable String from) {
|
||||
convertedFrom = from;
|
||||
}
|
||||
|
||||
public void convertedTo(@Nullable String to) {
|
||||
convertedTo = to;
|
||||
}
|
||||
|
||||
public void appendTitleFragment(@Nullable String fragment) {
|
||||
title += "#" + fragment;
|
||||
}
|
||||
|
||||
public boolean checkWhetherFileIsUsedInWikis() {
|
||||
if (globalUsages != null && globalUsages.size() > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fileUsages == null || fileUsages.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int totalCount = fileUsages.size();
|
||||
|
||||
/* Ignore usage under https://commons.wikimedia.org/wiki/User:Didym/Mobile_upload/
|
||||
which has been a gallery of all of our uploads since 2014 */
|
||||
for (final FileUsage fileUsage : fileUsages) {
|
||||
if ( ! fileUsage.title().contains("User:Didym/Mobile upload")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static class Revision {
|
||||
@SerializedName("revid") private long revisionId;
|
||||
private String user;
|
||||
@SerializedName("contentformat") @NonNull private String contentFormat;
|
||||
@SerializedName("contentmodel") @NonNull private String contentModel;
|
||||
@SerializedName("timestamp") @NonNull private String timeStamp;
|
||||
@NonNull private String content;
|
||||
|
||||
@NonNull public String content() {
|
||||
return content;
|
||||
}
|
||||
|
||||
@NonNull public String timeStamp() {
|
||||
return StringUtils.defaultString(timeStamp);
|
||||
}
|
||||
|
||||
public long getRevisionId() {
|
||||
return revisionId;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String getUser() {
|
||||
return StringUtils.defaultString(user);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Coordinates {
|
||||
@Nullable private Double lat;
|
||||
@Nullable private Double lon;
|
||||
|
||||
@Nullable public Double lat() {
|
||||
return lat;
|
||||
}
|
||||
@Nullable public Double lon() {
|
||||
return lon;
|
||||
}
|
||||
}
|
||||
|
||||
public static class CategoryInfo {
|
||||
private boolean hidden;
|
||||
private int size;
|
||||
private int pages;
|
||||
private int files;
|
||||
private int subcats;
|
||||
public boolean isHidden() {
|
||||
return hidden;
|
||||
}
|
||||
}
|
||||
|
||||
static class Thumbnail {
|
||||
private String source;
|
||||
private int width;
|
||||
private int height;
|
||||
String source() {
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
public static class GlobalUsage {
|
||||
@SerializedName("title") private String title;
|
||||
@SerializedName("wiki")private String wiki;
|
||||
@SerializedName("url") private String url;
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getWiki() {
|
||||
return wiki;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
public static class FileUsage {
|
||||
@SerializedName("pageid") private int pageid;
|
||||
@SerializedName("ns") private int ns;
|
||||
@SerializedName("title") private String title;
|
||||
|
||||
public int pageId() {
|
||||
return pageid;
|
||||
}
|
||||
|
||||
public int ns() {
|
||||
return ns;
|
||||
}
|
||||
|
||||
public String title() {
|
||||
return title;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Category {
|
||||
private int ns;
|
||||
@SuppressWarnings("unused,NullableProblems") @Nullable private String title;
|
||||
private boolean hidden;
|
||||
|
||||
public int ns() {
|
||||
return ns;
|
||||
}
|
||||
|
||||
@NonNull public String title() {
|
||||
return StringUtils.defaultString(title);
|
||||
}
|
||||
|
||||
public boolean hidden() {
|
||||
return hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
package fr.free.nrw.commons.wikidata.mwapi
|
||||
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import fr.free.nrw.commons.wikidata.model.BaseModel
|
||||
import fr.free.nrw.commons.wikidata.model.gallery.ImageInfo
|
||||
import fr.free.nrw.commons.wikidata.mwapi.MwQueryPage.GlobalUsage
|
||||
|
||||
/**
|
||||
* A class representing a standard page object as returned by the MediaWiki API.
|
||||
*/
|
||||
class MwQueryPage : BaseModel() {
|
||||
private val pageid = 0
|
||||
private val index = 0
|
||||
private var title: String? = null
|
||||
private val categoryinfo: CategoryInfo? = null
|
||||
private val revisions: List<Revision>? = null
|
||||
|
||||
@SerializedName("fileusage")
|
||||
private val fileUsages: List<FileUsage>? = null
|
||||
|
||||
@SerializedName("globalusage")
|
||||
private val globalUsages: List<GlobalUsage>? = null
|
||||
private val coordinates: MutableList<Coordinates?>? = null
|
||||
private val categories: List<Category>? = null
|
||||
private val thumbnail: Thumbnail? = null
|
||||
private val description: String? = null
|
||||
|
||||
@SerializedName("imageinfo")
|
||||
private val imageInfo: List<ImageInfo>? = null
|
||||
private var redirectFrom: String? = null
|
||||
private var convertedFrom: String? = null
|
||||
private var convertedTo: String? = null
|
||||
|
||||
fun title(): String = title!!
|
||||
|
||||
fun categoryInfo(): CategoryInfo = categoryinfo!!
|
||||
|
||||
fun index(): Int = index
|
||||
|
||||
fun revisions(): List<Revision>? = revisions
|
||||
|
||||
fun categories(): List<Category>? = categories
|
||||
|
||||
// TODO: Handle null values in lists during deserialization, perhaps with a new
|
||||
// @RequiredElements annotation and corresponding TypeAdapter
|
||||
fun coordinates(): List<Coordinates?>? = coordinates?.filterNotNull()
|
||||
|
||||
fun pageId(): Int = pageid
|
||||
|
||||
fun thumbUrl(): String? = thumbnail?.source()
|
||||
|
||||
fun description(): String? = description
|
||||
|
||||
fun imageInfo(): ImageInfo? = imageInfo?.get(0)
|
||||
|
||||
fun redirectFrom(from: String?) {
|
||||
redirectFrom = from
|
||||
}
|
||||
|
||||
fun convertedFrom(from: String?) {
|
||||
convertedFrom = from
|
||||
}
|
||||
|
||||
fun convertedTo(to: String?) {
|
||||
convertedTo = to
|
||||
}
|
||||
|
||||
fun appendTitleFragment(fragment: String?) {
|
||||
title += "#$fragment"
|
||||
}
|
||||
|
||||
fun checkWhetherFileIsUsedInWikis(): Boolean {
|
||||
return checkWhetherFileIsUsedInWikis(globalUsages, fileUsages)
|
||||
}
|
||||
|
||||
class Revision {
|
||||
@SerializedName("revid")
|
||||
private val revisionId: Long = 0
|
||||
private val user: String? = null
|
||||
@SerializedName("contentformat")
|
||||
private val contentFormat: String? = null
|
||||
@SerializedName("contentmodel")
|
||||
private val contentModel: String? = null
|
||||
@SerializedName("timestamp")
|
||||
private val timeStamp: String? = null
|
||||
private val content: String? = null
|
||||
|
||||
fun revisionId(): Long = revisionId
|
||||
|
||||
fun user(): String = user ?: ""
|
||||
|
||||
fun content(): String = content!!
|
||||
|
||||
fun timeStamp(): String = timeStamp ?: ""
|
||||
}
|
||||
|
||||
class Coordinates {
|
||||
private val lat: Double? = null
|
||||
private val lon: Double? = null
|
||||
|
||||
fun lat(): Double? = lat
|
||||
|
||||
fun lon(): Double? = lon
|
||||
}
|
||||
|
||||
class CategoryInfo {
|
||||
val isHidden: Boolean = false
|
||||
private val size = 0
|
||||
private val pages = 0
|
||||
private val files = 0
|
||||
private val subcats = 0
|
||||
}
|
||||
|
||||
internal class Thumbnail {
|
||||
private val source: String? = null
|
||||
private val width = 0
|
||||
private val height = 0
|
||||
|
||||
fun source(): String? = source
|
||||
}
|
||||
|
||||
class GlobalUsage {
|
||||
@SerializedName("title")
|
||||
val title: String? = null
|
||||
|
||||
@SerializedName("wiki")
|
||||
val wiki: String? = null
|
||||
|
||||
@SerializedName("url")
|
||||
val url: String? = null
|
||||
}
|
||||
|
||||
class FileUsage {
|
||||
@SerializedName("pageid")
|
||||
private val pageid = 0
|
||||
|
||||
@SerializedName("ns")
|
||||
private val ns = 0
|
||||
|
||||
@SerializedName("title")
|
||||
private var title: String? = null
|
||||
|
||||
fun pageId(): Int = pageid
|
||||
|
||||
fun ns(): Int = ns
|
||||
|
||||
fun title(): String = title ?: ""
|
||||
|
||||
fun setTitle(value: String) {
|
||||
title = value
|
||||
}
|
||||
}
|
||||
|
||||
class Category {
|
||||
private val ns = 0
|
||||
private val title: String? = null
|
||||
private val hidden = false
|
||||
|
||||
fun ns(): Int = ns
|
||||
|
||||
fun title(): String = title ?: ""
|
||||
|
||||
fun hidden(): Boolean = hidden
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
fun checkWhetherFileIsUsedInWikis(
|
||||
globalUsages: List<GlobalUsage>?,
|
||||
fileUsages: List<MwQueryPage.FileUsage>?
|
||||
): Boolean {
|
||||
if (!globalUsages.isNullOrEmpty()) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (fileUsages.isNullOrEmpty()) {
|
||||
return false
|
||||
}
|
||||
|
||||
/* Ignore usage under https://commons.wikimedia.org/wiki/User:Didym/Mobile_upload/
|
||||
which has been a gallery of all of our uploads since 2014 */
|
||||
return fileUsages.filterNot {
|
||||
it.title().contains("User:Didym/Mobile upload")
|
||||
}.isNotEmpty()
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
package fr.free.nrw.commons.wikidata.mwapi;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class MwQueryResponse extends MwResponse {
|
||||
|
||||
@SerializedName("continue") @Nullable private Map<String, String> continuation;
|
||||
|
||||
@SerializedName("query") @Nullable private MwQueryResult query;
|
||||
|
||||
@Nullable public Map<String, String> continuation() {
|
||||
return continuation;
|
||||
}
|
||||
|
||||
@Nullable public MwQueryResult query() {
|
||||
return query;
|
||||
}
|
||||
|
||||
public boolean success() {
|
||||
return query != null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package fr.free.nrw.commons.wikidata.mwapi
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
class MwQueryResponse : MwResponse() {
|
||||
@SerializedName("continue")
|
||||
private val continuation: Map<String, String>? = null
|
||||
private val query: MwQueryResult? = null
|
||||
|
||||
fun continuation(): Map<String, String>? = continuation
|
||||
|
||||
fun query(): MwQueryResult? = query
|
||||
|
||||
fun success(): Boolean = query != null
|
||||
}
|
||||
|
|
@ -1,187 +0,0 @@
|
|||
package fr.free.nrw.commons.wikidata.mwapi;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import fr.free.nrw.commons.wikidata.json.PostProcessingTypeAdapter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import fr.free.nrw.commons.wikidata.model.gallery.ImageInfo;
|
||||
import fr.free.nrw.commons.wikidata.model.BaseModel;
|
||||
import fr.free.nrw.commons.wikidata.model.notifications.Notification;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class MwQueryResult extends BaseModel implements PostProcessingTypeAdapter.PostProcessable {
|
||||
@SerializedName("pages") @Nullable private List<MwQueryPage> pages;
|
||||
@Nullable private List<Redirect> redirects;
|
||||
@Nullable private List<ConvertedTitle> converted;
|
||||
@SerializedName("userinfo") private UserInfo userInfo;
|
||||
@Nullable private List<ListUserResponse> users;
|
||||
@Nullable private Tokens tokens;
|
||||
@Nullable private NotificationList notifications;
|
||||
@SerializedName("allimages") @Nullable private List<ImageDetails> allImages;
|
||||
|
||||
@Nullable public List<MwQueryPage> pages() {
|
||||
return pages;
|
||||
}
|
||||
|
||||
@Nullable public MwQueryPage firstPage() {
|
||||
if (pages != null && pages.size() > 0) {
|
||||
return pages.get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<ImageDetails> allImages() {
|
||||
return allImages == null ? Collections.emptyList() : allImages;
|
||||
}
|
||||
|
||||
@Nullable public UserInfo userInfo() {
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
@Nullable public String csrfToken() {
|
||||
return tokens != null ? tokens.csrf() : null;
|
||||
}
|
||||
|
||||
@Nullable public String loginToken() {
|
||||
return tokens != null ? tokens.login() : null;
|
||||
}
|
||||
|
||||
@Nullable public NotificationList notifications() {
|
||||
return notifications;
|
||||
}
|
||||
|
||||
@Nullable public ListUserResponse getUserResponse(@NonNull String userName) {
|
||||
if (users != null) {
|
||||
for (ListUserResponse user : users) {
|
||||
// MediaWiki user names are case sensitive, but the first letter is always capitalized.
|
||||
if (StringUtils.capitalize(userName).equals(user.name())) {
|
||||
return user;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NonNull public Map<String, ImageInfo> images() {
|
||||
Map<String, ImageInfo> result = new HashMap<>();
|
||||
if (pages != null) {
|
||||
for (MwQueryPage page : pages) {
|
||||
if (page.imageInfo() != null) {
|
||||
result.put(page.title(), page.imageInfo());
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcess() {
|
||||
resolveConvertedTitles();
|
||||
resolveRedirectedTitles();
|
||||
}
|
||||
|
||||
private void resolveRedirectedTitles() {
|
||||
if (redirects == null || pages == null) {
|
||||
return;
|
||||
}
|
||||
for (MwQueryPage page : pages) {
|
||||
for (MwQueryResult.Redirect redirect : redirects) {
|
||||
// TODO: Looks like result pages and redirects can also be matched on the "index"
|
||||
// property. Confirm in the API docs and consider updating.
|
||||
if (page.title().equals(redirect.to())) {
|
||||
page.redirectFrom(redirect.from());
|
||||
if (redirect.toFragment() != null) {
|
||||
page.appendTitleFragment(redirect.toFragment());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void resolveConvertedTitles() {
|
||||
if (converted == null || pages == null) {
|
||||
return;
|
||||
}
|
||||
// noinspection ConstantConditions
|
||||
for (MwQueryResult.ConvertedTitle convertedTitle : converted) {
|
||||
// noinspection ConstantConditions
|
||||
for (MwQueryPage page : pages) {
|
||||
if (page.title().equals(convertedTitle.to())) {
|
||||
page.convertedFrom(convertedTitle.from());
|
||||
page.convertedTo(convertedTitle.to());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Redirect {
|
||||
private int index;
|
||||
@Nullable private String from;
|
||||
@Nullable private String to;
|
||||
@SerializedName("tofragment") @Nullable private String toFragment;
|
||||
|
||||
@Nullable public String to() {
|
||||
return to;
|
||||
}
|
||||
|
||||
@Nullable public String from() {
|
||||
return from;
|
||||
}
|
||||
|
||||
@Nullable public String toFragment() {
|
||||
return toFragment;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConvertedTitle {
|
||||
@Nullable private String from;
|
||||
@Nullable private String to;
|
||||
|
||||
@Nullable public String to() {
|
||||
return to;
|
||||
}
|
||||
|
||||
@Nullable public String from() {
|
||||
return from;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Tokens {
|
||||
@SuppressWarnings("unused,NullableProblems") @SerializedName("csrftoken")
|
||||
@Nullable private String csrf;
|
||||
@SuppressWarnings("unused,NullableProblems") @SerializedName("createaccounttoken")
|
||||
@Nullable private String createAccount;
|
||||
@SuppressWarnings("unused,NullableProblems") @SerializedName("logintoken")
|
||||
@Nullable private String login;
|
||||
|
||||
@Nullable private String csrf() {
|
||||
return csrf;
|
||||
}
|
||||
|
||||
@Nullable private String createAccount() {
|
||||
return createAccount;
|
||||
}
|
||||
|
||||
@Nullable private String login() {
|
||||
return login;
|
||||
}
|
||||
}
|
||||
|
||||
public static class NotificationList {
|
||||
@Nullable
|
||||
private List<Notification> list;
|
||||
@Nullable
|
||||
public List<Notification> list() {
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
package fr.free.nrw.commons.wikidata.mwapi
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import fr.free.nrw.commons.wikidata.json.PostProcessingTypeAdapter.PostProcessable
|
||||
import fr.free.nrw.commons.wikidata.model.BaseModel
|
||||
import fr.free.nrw.commons.wikidata.model.gallery.ImageInfo
|
||||
import fr.free.nrw.commons.wikidata.model.notifications.Notification
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
|
||||
class MwQueryResult : BaseModel(), PostProcessable {
|
||||
private val pages: List<MwQueryPage>? = null
|
||||
private val redirects: List<Redirect>? = null
|
||||
private val converted: List<ConvertedTitle>? = null
|
||||
|
||||
@SerializedName("userinfo")
|
||||
private val userInfo: UserInfo? = null
|
||||
private val users: List<ListUserResponse>? = null
|
||||
private val tokens: Tokens? = null
|
||||
private val notifications: NotificationList? = null
|
||||
|
||||
@SerializedName("allimages")
|
||||
private val allImages: List<ImageDetails>? = null
|
||||
|
||||
fun pages(): List<MwQueryPage>? = pages
|
||||
|
||||
fun firstPage(): MwQueryPage? = pages?.firstOrNull()
|
||||
|
||||
fun allImages(): List<ImageDetails> = allImages ?: emptyList()
|
||||
|
||||
fun userInfo(): UserInfo? = userInfo
|
||||
|
||||
fun csrfToken(): String? = tokens?.csrf()
|
||||
|
||||
fun loginToken(): String? = tokens?.login()
|
||||
|
||||
fun notifications(): NotificationList? = notifications
|
||||
|
||||
fun getUserResponse(userName: String): ListUserResponse? =
|
||||
users?.find { StringUtils.capitalize(userName) == it.name() }
|
||||
|
||||
fun images() = buildMap {
|
||||
pages?.forEach { page ->
|
||||
page.imageInfo()?.let {
|
||||
put(page.title(), it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun postProcess() {
|
||||
resolveConvertedTitles()
|
||||
resolveRedirectedTitles()
|
||||
}
|
||||
|
||||
private fun resolveRedirectedTitles() {
|
||||
if (redirects == null || pages == null) {
|
||||
return
|
||||
}
|
||||
|
||||
pages.forEach { page ->
|
||||
redirects.forEach { redirect ->
|
||||
// TODO: Looks like result pages and redirects can also be matched on the "index"
|
||||
// property. Confirm in the API docs and consider updating.
|
||||
if (page.title() == redirect.to()) {
|
||||
page.redirectFrom(redirect.from())
|
||||
if (redirect.toFragment() != null) {
|
||||
page.appendTitleFragment(redirect.toFragment())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveConvertedTitles() {
|
||||
if (converted == null || pages == null) {
|
||||
return
|
||||
}
|
||||
|
||||
converted.forEach { convertedTitle ->
|
||||
pages.forEach { page ->
|
||||
if (page.title() == convertedTitle.to()) {
|
||||
page.convertedFrom(convertedTitle.from())
|
||||
page.convertedTo(convertedTitle.to())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class Redirect {
|
||||
private val index = 0
|
||||
private val from: String? = null
|
||||
private val to: String? = null
|
||||
|
||||
@SerializedName("tofragment")
|
||||
private val toFragment: String? = null
|
||||
|
||||
fun to(): String? = to
|
||||
|
||||
fun from(): String? = from
|
||||
|
||||
fun toFragment(): String? = toFragment
|
||||
}
|
||||
|
||||
class ConvertedTitle {
|
||||
private val from: String? = null
|
||||
private val to: String? = null
|
||||
|
||||
fun to(): String? = to
|
||||
|
||||
fun from(): String? = from
|
||||
}
|
||||
|
||||
private class Tokens {
|
||||
@SerializedName("csrftoken")
|
||||
private val csrf: String? = null
|
||||
|
||||
@SerializedName("createaccounttoken")
|
||||
private val createAccount: String? = null
|
||||
|
||||
@SerializedName("logintoken")
|
||||
private val login: String? = null
|
||||
|
||||
fun csrf(): String? = csrf
|
||||
|
||||
fun createAccount(): String? = createAccount
|
||||
|
||||
fun login(): String? = login
|
||||
}
|
||||
|
||||
class NotificationList {
|
||||
private val list: List<Notification>? = null
|
||||
|
||||
fun list(): List<Notification>? = list
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
package fr.free.nrw.commons.wikidata.mwapi;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import fr.free.nrw.commons.wikidata.json.PostProcessingTypeAdapter;
|
||||
import fr.free.nrw.commons.wikidata.model.BaseModel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class MwResponse extends BaseModel implements PostProcessingTypeAdapter.PostProcessable {
|
||||
@SuppressWarnings({"unused"}) @Nullable private List<MwServiceError> errors;
|
||||
@SuppressWarnings("unused,NullableProblems") @SerializedName("servedby") @NonNull private String servedBy;
|
||||
|
||||
@Override
|
||||
public void postProcess() {
|
||||
if (errors != null && !errors.isEmpty()) {
|
||||
throw new MwException(errors.get(0), errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package fr.free.nrw.commons.wikidata.mwapi
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import fr.free.nrw.commons.wikidata.json.PostProcessingTypeAdapter.PostProcessable
|
||||
import fr.free.nrw.commons.wikidata.model.BaseModel
|
||||
|
||||
abstract class MwResponse : BaseModel(), PostProcessable {
|
||||
private val errors: List<MwServiceError>? = null
|
||||
|
||||
@SerializedName("servedby")
|
||||
private val servedBy: String? = null
|
||||
|
||||
override fun postProcess() {
|
||||
if (!errors.isNullOrEmpty()) {
|
||||
throw MwException(errors[0], errors)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
package fr.free.nrw.commons.wikidata.mwapi;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import fr.free.nrw.commons.wikidata.model.BaseModel;
|
||||
|
||||
/**
|
||||
* Gson POJO for a MediaWiki API error.
|
||||
*/
|
||||
public class MwServiceError extends BaseModel {
|
||||
|
||||
@Nullable private String code;
|
||||
@Nullable private String text;
|
||||
|
||||
@NonNull public String getTitle() {
|
||||
return StringUtils.defaultString(code);
|
||||
}
|
||||
|
||||
@NonNull public String getDetails() {
|
||||
return StringUtils.defaultString(text);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package fr.free.nrw.commons.wikidata.mwapi
|
||||
|
||||
import fr.free.nrw.commons.wikidata.model.BaseModel
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
|
||||
/**
|
||||
* Gson POJO for a MediaWiki API error.
|
||||
*/
|
||||
class MwServiceError : BaseModel() {
|
||||
val code: String? = null
|
||||
private val text: String? = null
|
||||
|
||||
val title: String
|
||||
get() = code ?: ""
|
||||
|
||||
val details: String
|
||||
get() = text ?: ""
|
||||
}
|
||||
|
|
@ -139,7 +139,7 @@ class ReviewControllerTest {
|
|||
@Test
|
||||
fun testSendThanks() {
|
||||
shadowOf(Looper.getMainLooper()).idle()
|
||||
whenever(firstRevision.revisionId).thenReturn(1)
|
||||
whenever(firstRevision.revisionId()).thenReturn(1)
|
||||
Whitebox.setInternalState(controller, "firstRevision", firstRevision)
|
||||
controller.sendThanks(activity)
|
||||
assertEquals(
|
||||
|
|
|
|||
|
|
@ -95,11 +95,11 @@ class ReviewHelperTest {
|
|||
@Test
|
||||
fun getFirstRevisionOfFile() {
|
||||
val rev1 = mock<MwQueryPage.Revision>()
|
||||
whenever(rev1.user).thenReturn("TestUser")
|
||||
whenever(rev1.revisionId).thenReturn(1L)
|
||||
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)
|
||||
whenever(rev2.user()).thenReturn("TestUser")
|
||||
whenever(rev2.revisionId()).thenReturn(2L)
|
||||
|
||||
val page = setupMedia("Test.jpg", rev1, rev2)
|
||||
whenever(mwQueryResult.firstPage()).thenReturn(page)
|
||||
|
|
@ -107,7 +107,7 @@ class ReviewHelperTest {
|
|||
|
||||
val firstRevisionOfFile = reviewHelper.getFirstRevisionOfFile("Test.jpg").blockingFirst()
|
||||
|
||||
assertEquals(1, firstRevisionOfFile.revisionId)
|
||||
assertEquals(1, firstRevisionOfFile.revisionId())
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
package fr.free.nrw.commons.wikidata.mwapi
|
||||
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class MwQueryPageTest {
|
||||
private val didymUsage = MwQueryPage.FileUsage().apply {
|
||||
setTitle("User:Didym/Mobile upload")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkWhetherFileIsUsedInWikis_nullGlobalUsages() {
|
||||
assertFalse(checkWhetherFileIsUsedInWikis(null, null))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkWhetherFileIsUsedInWikis_emptyGlobalUsages() {
|
||||
assertFalse(checkWhetherFileIsUsedInWikis(emptyList(), null))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkWhetherFileIsUsedInWikis_emptyFileUsage() {
|
||||
assertFalse(checkWhetherFileIsUsedInWikis(emptyList(), emptyList()))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkWhetherFileIsUsedInWikis_singleGlobalUsages() {
|
||||
assertTrue(checkWhetherFileIsUsedInWikis(listOf(MwQueryPage.GlobalUsage()), null))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkWhetherFileIsUsedInWikis_singleFileUsageContainsDidym() {
|
||||
assertFalse(checkWhetherFileIsUsedInWikis(null, listOf(didymUsage)))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun checkWhetherFileIsUsedInWikis_didymIgnoredInList() {
|
||||
assertTrue(
|
||||
checkWhetherFileIsUsedInWikis(
|
||||
null, listOf(
|
||||
didymUsage, MwQueryPage.FileUsage().apply { setTitle("somewhere else") }
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue