mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 21:03:54 +01:00
* #3529 Captions/depictions are not saved to Commons - make copy of list of depictionEntityIds - uncomment editBaseDepictsProperty - refactor upload related classes * #3529 Captions/depictions are not saved to Commons - fix wrong ArrayList usage * #3529 Captions/depictions are not saved to Commons - fix test
This commit is contained in:
parent
587d97716a
commit
23b8c2e659
12 changed files with 360 additions and 504 deletions
|
|
@ -3,18 +3,12 @@ package fr.free.nrw.commons;
|
|||
import android.net.Uri;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.wikipedia.dataclient.mwapi.MwQueryPage;
|
||||
import org.wikipedia.gallery.ExtMetadata;
|
||||
import org.wikipedia.gallery.ImageInfo;
|
||||
import org.wikipedia.page.PageTitle;
|
||||
|
||||
import fr.free.nrw.commons.location.LatLng;
|
||||
import fr.free.nrw.commons.utils.CommonsDateUtil;
|
||||
import fr.free.nrw.commons.utils.MediaDataExtractorUtil;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
|
@ -23,10 +17,11 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import fr.free.nrw.commons.location.LatLng;
|
||||
import fr.free.nrw.commons.utils.CommonsDateUtil;
|
||||
import fr.free.nrw.commons.utils.MediaDataExtractorUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.wikipedia.dataclient.mwapi.MwQueryPage;
|
||||
import org.wikipedia.gallery.ExtMetadata;
|
||||
import org.wikipedia.gallery.ImageInfo;
|
||||
import org.wikipedia.page.PageTitle;
|
||||
|
||||
@Entity
|
||||
public class Media implements Parcelable {
|
||||
|
|
@ -90,7 +85,7 @@ public class Media implements Parcelable {
|
|||
* Ex: key = "en", value: "<caption in short in English>"
|
||||
* key = "de" , value: "<caption in german>"
|
||||
*/
|
||||
public HashMap<String, String> captions;
|
||||
public Map<String, String> captions;
|
||||
public HashMap<String, String> tags = new HashMap<>();
|
||||
@Nullable public LatLng coordinates;
|
||||
|
||||
|
|
@ -126,7 +121,7 @@ public class Media implements Parcelable {
|
|||
* @param dateUploaded Media date uploaded
|
||||
* @param creator Media creator
|
||||
*/
|
||||
public Media(Uri localUri, String imageUrl, String filename, HashMap<String, String> captions, String description,
|
||||
public Media(Uri localUri, String imageUrl, String filename, Map<String, String> captions, String description,
|
||||
long dataLength, Date dateCreated, Date dateUploaded, String creator) {
|
||||
this();
|
||||
this.localUri = localUri;
|
||||
|
|
@ -395,7 +390,7 @@ public class Media implements Parcelable {
|
|||
*
|
||||
* returns list of captions stored in hashmap
|
||||
*/
|
||||
public HashMap<String, String> getCaptions() {
|
||||
public Map<String, String> getCaptions() {
|
||||
return captions;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,29 +1,25 @@
|
|||
package fr.free.nrw.commons.contributions;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Parcel;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StringDef;
|
||||
import androidx.room.Entity;
|
||||
import androidx.room.PrimaryKey;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
|
||||
import fr.free.nrw.commons.CommonsApplication;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.filepicker.UploadableFile;
|
||||
import fr.free.nrw.commons.settings.Prefs;
|
||||
import fr.free.nrw.commons.utils.ConfigUtils;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.SOURCE;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@Entity(tableName = "contribution")
|
||||
public class Contribution extends Media {
|
||||
|
|
@ -83,7 +79,7 @@ public class Contribution extends Media {
|
|||
|
||||
public Contribution(Uri contentUri, String filename, Uri localUri, String imageUrl, Date dateCreated,
|
||||
int state, long dataLength, Date dateUploaded, long transferred,
|
||||
String source, HashMap<String, String> captions, String description, String creator, boolean isMultiple,
|
||||
String source, Map<String, String> captions, String description, String creator, boolean isMultiple,
|
||||
int width, int height, String license) {
|
||||
super(localUri, imageUrl, filename, captions, description, dataLength, dateCreated, dateUploaded, creator);
|
||||
this.contentUri = contentUri;
|
||||
|
|
@ -97,7 +93,7 @@ public class Contribution extends Media {
|
|||
this.dateCreatedSource = "";
|
||||
}
|
||||
|
||||
public Contribution(Uri localUri, String imageUrl, String filename, HashMap<String, String> captions, String description, long dataLength,
|
||||
public Contribution(Uri localUri, String imageUrl, String filename, Map<String, String> captions, String description, long dataLength,
|
||||
Date dateCreated, Date dateUploaded, String creator, String editSummary, ArrayList<String> depictionsEntityIds, String decimalCoords) {
|
||||
super(localUri, imageUrl, filename, captions, description, dataLength, dateCreated, dateUploaded, creator);
|
||||
this.decimalCoords = decimalCoords;
|
||||
|
|
@ -106,7 +102,7 @@ public class Contribution extends Media {
|
|||
this.depictionsEntityIds = depictionsEntityIds;
|
||||
}
|
||||
|
||||
public Contribution(Uri localUri, String imageUrl, String filename, HashMap<String, String> captions, String description, long dataLength,
|
||||
public Contribution(Uri localUri, String imageUrl, String filename, Map<String, String> captions, String description, long dataLength,
|
||||
Date dateCreated, Date dateUploaded, String creator, String editSummary, String decimalCoords, int state) {
|
||||
super(localUri, imageUrl, filename, captions, description, dataLength, dateCreated, dateUploaded, creator);
|
||||
this.decimalCoords = decimalCoords;
|
||||
|
|
|
|||
|
|
@ -1,24 +1,8 @@
|
|||
package fr.free.nrw.commons.di;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import org.wikipedia.csrf.CsrfTokenClient;
|
||||
import org.wikipedia.dataclient.Service;
|
||||
import org.wikipedia.dataclient.ServiceFactory;
|
||||
import org.wikipedia.dataclient.WikiSite;
|
||||
import org.wikipedia.json.GsonUtil;
|
||||
import org.wikipedia.login.LoginClient;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import fr.free.nrw.commons.BuildConfig;
|
||||
|
|
@ -32,14 +16,25 @@ import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient;
|
|||
import fr.free.nrw.commons.mwapi.UserInterface;
|
||||
import fr.free.nrw.commons.review.ReviewInterface;
|
||||
import fr.free.nrw.commons.upload.UploadInterface;
|
||||
import fr.free.nrw.commons.wikidata.WikidataInterface;
|
||||
import fr.free.nrw.commons.upload.WikiBaseInterface;
|
||||
import fr.free.nrw.commons.upload.depicts.DepictsInterface;
|
||||
import fr.free.nrw.commons.upload.mediaDetails.CaptionInterface;
|
||||
import fr.free.nrw.commons.wikidata.WikidataInterface;
|
||||
import java.io.File;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import okhttp3.Cache;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
import okhttp3.logging.HttpLoggingInterceptor.Level;
|
||||
import org.wikipedia.csrf.CsrfTokenClient;
|
||||
import org.wikipedia.dataclient.Service;
|
||||
import org.wikipedia.dataclient.ServiceFactory;
|
||||
import org.wikipedia.dataclient.WikiSite;
|
||||
import org.wikipedia.json.GsonUtil;
|
||||
import org.wikipedia.login.LoginClient;
|
||||
import timber.log.Timber;
|
||||
|
||||
@Module
|
||||
|
|
@ -76,7 +71,7 @@ public class NetworkingModule {
|
|||
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(message -> {
|
||||
Timber.tag("OkHttp").v(message);
|
||||
});
|
||||
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
|
||||
httpLoggingInterceptor.level(BuildConfig.DEBUG ? Level.BODY: HttpLoggingInterceptor.Level.BASIC);
|
||||
return httpLoggingInterceptor;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,17 +13,8 @@ import android.net.Uri;
|
|||
import android.os.IBinder;
|
||||
import android.provider.MediaStore;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import fr.free.nrw.commons.HandlerService;
|
||||
import fr.free.nrw.commons.Media;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import fr.free.nrw.commons.contributions.Contribution;
|
||||
|
|
@ -34,23 +25,26 @@ import io.reactivex.Single;
|
|||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Date;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import timber.log.Timber;
|
||||
|
||||
@Singleton
|
||||
public class UploadController {
|
||||
private UploadService uploadService;
|
||||
private SessionManager sessionManager;
|
||||
private Context context;
|
||||
private JsonKvStore store;
|
||||
|
||||
public interface ContributionUploadProgress {
|
||||
void onUploadStarted(Contribution contribution);
|
||||
}
|
||||
private final SessionManager sessionManager;
|
||||
private final Context context;
|
||||
private final JsonKvStore store;
|
||||
|
||||
@Inject
|
||||
public UploadController(SessionManager sessionManager,
|
||||
Context context,
|
||||
JsonKvStore store) {
|
||||
public UploadController(final SessionManager sessionManager,
|
||||
final Context context,
|
||||
final JsonKvStore store) {
|
||||
this.sessionManager = sessionManager;
|
||||
this.context = context;
|
||||
this.store = store;
|
||||
|
|
@ -59,13 +53,13 @@ public class UploadController {
|
|||
private boolean isUploadServiceConnected;
|
||||
public ServiceConnection uploadServiceConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName componentName, IBinder binder) {
|
||||
public void onServiceConnected(final ComponentName componentName, final IBinder binder) {
|
||||
uploadService = (UploadService) ((HandlerService.HandlerServiceLocalBinder) binder).getService();
|
||||
isUploadServiceConnected = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName componentName) {
|
||||
public void onServiceDisconnected(final ComponentName componentName) {
|
||||
// this should never happen
|
||||
isUploadServiceConnected = false;
|
||||
Timber.e(new RuntimeException("UploadService died but the rest of the process did not!"));
|
||||
|
|
@ -76,7 +70,7 @@ public class UploadController {
|
|||
* Prepares the upload service.
|
||||
*/
|
||||
public void prepareService() {
|
||||
Intent uploadServiceIntent = new Intent(context, UploadService.class);
|
||||
final Intent uploadServiceIntent = new Intent(context, UploadService.class);
|
||||
uploadServiceIntent.setAction(UploadService.ACTION_START_SERVICE);
|
||||
context.startService(uploadServiceIntent);
|
||||
context.bindService(uploadServiceIntent, uploadServiceConnection, Context.BIND_AUTO_CREATE);
|
||||
|
|
@ -96,28 +90,18 @@ public class UploadController {
|
|||
*
|
||||
* @param contribution the contribution object
|
||||
*/
|
||||
public void startUpload(Contribution contribution) {
|
||||
startUpload(contribution, c -> {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new upload task.
|
||||
*
|
||||
* @param contribution the contribution object
|
||||
* @param onComplete the progress tracker
|
||||
*/
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private void startUpload(final Contribution contribution, final ContributionUploadProgress onComplete) {
|
||||
public void startUpload(final Contribution contribution) {
|
||||
//Set creator, desc, and license
|
||||
|
||||
// If author name is enabled and set, use it
|
||||
if (store.getBoolean("useAuthorName", false)) {
|
||||
String authorName = store.getString("authorName", "");
|
||||
final String authorName = store.getString("authorName", "");
|
||||
contribution.setCreator(authorName);
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(contribution.getCreator())) {
|
||||
Account currentAccount = sessionManager.getCurrentAccount();
|
||||
final Account currentAccount = sessionManager.getCurrentAccount();
|
||||
if (currentAccount == null) {
|
||||
Timber.d("Current account is null");
|
||||
ViewUtil.showLongToast(context, context.getString(R.string.user_not_logged_in));
|
||||
|
|
@ -135,23 +119,23 @@ public class UploadController {
|
|||
contribution.setCaption("");
|
||||
}
|
||||
|
||||
String license = store.getString(Prefs.DEFAULT_LICENSE, Prefs.Licenses.CC_BY_SA_3);
|
||||
final String license = store.getString(Prefs.DEFAULT_LICENSE, Prefs.Licenses.CC_BY_SA_3);
|
||||
contribution.setLicense(license);
|
||||
|
||||
uploadTask(contribution, onComplete);
|
||||
uploadTask(contribution);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates the upload task
|
||||
* @param contribution
|
||||
* @param onComplete
|
||||
* @return
|
||||
*/
|
||||
private Disposable uploadTask(Contribution contribution, ContributionUploadProgress onComplete) {
|
||||
return Single.fromCallable(() -> makeUpload(contribution))
|
||||
private Disposable uploadTask(final Contribution contribution) {
|
||||
return Single.just(contribution)
|
||||
.map(this::buildUpload)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(finalContribution -> onUploadCompleted(finalContribution, onComplete));
|
||||
.subscribe(this::upload);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -159,71 +143,76 @@ public class UploadController {
|
|||
* @param contribution
|
||||
* @return
|
||||
*/
|
||||
private Contribution makeUpload(Contribution contribution) {
|
||||
long length;
|
||||
ContentResolver contentResolver = context.getContentResolver();
|
||||
private Contribution buildUpload(final Contribution contribution) {
|
||||
final ContentResolver contentResolver = context.getContentResolver();
|
||||
|
||||
contribution.setDataLength(resolveDataLength(contentResolver, contribution));
|
||||
|
||||
final String mimeType = resolveMimeType(contentResolver, contribution);
|
||||
|
||||
if (mimeType != null) {
|
||||
Timber.d("MimeType is: %s", mimeType);
|
||||
contribution.setTag("mimeType", mimeType);
|
||||
if(mimeType.startsWith("image/") && contribution.getDateCreated() == null){
|
||||
contribution.setDateCreated(resolveDateTakenOrNow(contentResolver, contribution));
|
||||
}
|
||||
}
|
||||
|
||||
return contribution;
|
||||
}
|
||||
|
||||
private String resolveMimeType(final ContentResolver contentResolver, final Contribution contribution) {
|
||||
final String mimeType = (String) contribution.getTag("mimeType");
|
||||
if (mimeType == null || TextUtils.isEmpty(mimeType) || mimeType.endsWith("*")) {
|
||||
return contentResolver.getType(contribution.getLocalUri());
|
||||
}
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
private long resolveDataLength(final ContentResolver contentResolver, final Media contribution) {
|
||||
try {
|
||||
if (contribution.getDataLength() <= 0) {
|
||||
Timber.d("UploadController/doInBackground, contribution.getLocalUri():%s", contribution.getLocalUri());
|
||||
AssetFileDescriptor assetFileDescriptor = contentResolver
|
||||
.openAssetFileDescriptor(Uri.fromFile(new File(contribution.getLocalUri().getPath())), "r");
|
||||
final AssetFileDescriptor assetFileDescriptor = contentResolver
|
||||
.openAssetFileDescriptor(Uri.fromFile(new File(contribution.getLocalUri().getPath())), "r");
|
||||
if (assetFileDescriptor != null) {
|
||||
length = assetFileDescriptor.getLength();
|
||||
if (length == -1) {
|
||||
// Let us find out the long way!
|
||||
length = countBytes(contentResolver
|
||||
.openInputStream(contribution.getLocalUri()));
|
||||
}
|
||||
contribution.setDataLength(length);
|
||||
final long length = assetFileDescriptor.getLength();
|
||||
return length != -1 ? length
|
||||
: countBytes(contentResolver.openInputStream(contribution.getLocalUri()));
|
||||
}
|
||||
}
|
||||
} catch (IOException | NullPointerException | SecurityException e) {
|
||||
} catch (final IOException | NullPointerException | SecurityException e) {
|
||||
Timber.e(e, "Exception occurred while uploading image");
|
||||
}
|
||||
return contribution.getDataLength();
|
||||
}
|
||||
|
||||
String mimeType = (String) contribution.getTag("mimeType");
|
||||
boolean imagePrefix = false;
|
||||
|
||||
if (mimeType == null || TextUtils.isEmpty(mimeType) || mimeType.endsWith("*")) {
|
||||
mimeType = contentResolver.getType(contribution.getLocalUri());
|
||||
}
|
||||
|
||||
if (mimeType != null) {
|
||||
contribution.setTag("mimeType", mimeType);
|
||||
imagePrefix = mimeType.startsWith("image/");
|
||||
Timber.d("MimeType is: %s", mimeType);
|
||||
}
|
||||
|
||||
if (imagePrefix && contribution.getDateCreated() == null) {
|
||||
Timber.d("local uri %s", contribution.getLocalUri());
|
||||
Cursor cursor = contentResolver.query(contribution.getLocalUri(),
|
||||
new String[]{MediaStore.Images.ImageColumns.DATE_TAKEN}, null, null, null);
|
||||
private Date resolveDateTakenOrNow(final ContentResolver contentResolver, final Media contribution) {
|
||||
Timber.d("local uri %s", contribution.getLocalUri());
|
||||
try(final Cursor cursor = dateTakenCursor(contentResolver, contribution)) {
|
||||
if (cursor != null && cursor.getCount() != 0 && cursor.getColumnCount() != 0) {
|
||||
cursor.moveToFirst();
|
||||
Date dateCreated = new Date(cursor.getLong(0));
|
||||
Date epochStart = new Date(0);
|
||||
if (dateCreated.equals(epochStart) || dateCreated.before(epochStart)) {
|
||||
// If date is incorrect (1st second of unix time) then set it to the current date
|
||||
dateCreated = new Date();
|
||||
final Date dateCreated = new Date(cursor.getLong(0));
|
||||
if (dateCreated.after(new Date(0))) {
|
||||
return dateCreated;
|
||||
}
|
||||
contribution.setDateCreated(dateCreated);
|
||||
cursor.close();
|
||||
} else {
|
||||
contribution.setDateCreated(new Date());
|
||||
}
|
||||
return new Date();
|
||||
}
|
||||
return contribution;
|
||||
}
|
||||
|
||||
private Cursor dateTakenCursor(final ContentResolver contentResolver, final Media contribution) {
|
||||
return contentResolver.query(contribution.getLocalUri(),
|
||||
new String[]{MediaStore.Images.ImageColumns.DATE_TAKEN}, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* When the contribution object is completely formed, the item is queued to the upload service
|
||||
* @param contribution
|
||||
* @param onComplete
|
||||
*/
|
||||
private void onUploadCompleted(Contribution contribution, ContributionUploadProgress onComplete) {
|
||||
private void upload(final Contribution contribution) {
|
||||
//Starts the upload. If commented out, user can proceed to next Fragment but upload doesn't happen
|
||||
uploadService.queue(UploadService.ACTION_UPLOAD_FILE, contribution);
|
||||
onComplete.onUploadStarted(contribution);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -234,9 +223,9 @@ public class UploadController {
|
|||
* @return the number of bytes in {@code stream}
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
private long countBytes(InputStream stream) throws IOException {
|
||||
private long countBytes(final InputStream stream) throws IOException {
|
||||
long count = 0;
|
||||
BufferedInputStream bis = new BufferedInputStream(stream);
|
||||
final BufferedInputStream bis = new BufferedInputStream(stream);
|
||||
while (bis.read() != -1) {
|
||||
count++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,117 +0,0 @@
|
|||
package fr.free.nrw.commons.upload;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
* Holds a description of an item being uploaded by {@link UploadActivity}
|
||||
*/
|
||||
public class UploadMediaDetail {
|
||||
|
||||
private String languageCode;
|
||||
private String descriptionText;
|
||||
public String captionText;
|
||||
private int selectedLanguageIndex = -1;
|
||||
private boolean isManuallyAdded=false;
|
||||
|
||||
/**
|
||||
* Formatting captions to the Wikibase format for sending labels
|
||||
* @param uploadMediaDetails list of media Details
|
||||
*/
|
||||
|
||||
public static HashMap<String, String> formatCaptions(List<UploadMediaDetail> uploadMediaDetails) {
|
||||
HashMap<String, String> caption = new HashMap<>();
|
||||
for (UploadMediaDetail uploadMediaDetail : uploadMediaDetails) {
|
||||
caption.put(uploadMediaDetail.getLanguageCode(),uploadMediaDetail.getCaptionText());
|
||||
}
|
||||
return caption;
|
||||
}
|
||||
|
||||
public String getCaptionText() {
|
||||
return captionText;
|
||||
}
|
||||
|
||||
public void setCaptionText(String captionText) {
|
||||
this.captionText = captionText;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The language code ie. "en" or "fr"
|
||||
*/
|
||||
String getLanguageCode() {
|
||||
return languageCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param languageCode The language code ie. "en" or "fr"
|
||||
*/
|
||||
public void setLanguageCode(String languageCode) {
|
||||
this.languageCode = languageCode;
|
||||
}
|
||||
|
||||
String getDescriptionText() {
|
||||
return descriptionText;
|
||||
}
|
||||
|
||||
public void setDescriptionText(String descriptionText) {
|
||||
this.descriptionText = descriptionText;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the index of the language selected in a spinner with {@link SpinnerLanguagesAdapter}
|
||||
*/
|
||||
int getSelectedLanguageIndex() {
|
||||
return selectedLanguageIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param selectedLanguageIndex the index of the language selected in a spinner with {@link SpinnerLanguagesAdapter}
|
||||
*/
|
||||
void setSelectedLanguageIndex(int selectedLanguageIndex) {
|
||||
this.selectedLanguageIndex = selectedLanguageIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns if the description was added manually (by the user, or we have added it programaticallly)
|
||||
* @return
|
||||
*/
|
||||
public boolean isManuallyAdded() {
|
||||
return isManuallyAdded;
|
||||
}
|
||||
|
||||
/**
|
||||
* sets to true if the description was manually added by the user
|
||||
* @param manuallyAdded
|
||||
*/
|
||||
public void setManuallyAdded(boolean manuallyAdded) {
|
||||
isManuallyAdded = manuallyAdded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the list of descriptions into the format Commons requires for uploads.
|
||||
*
|
||||
* @param descriptions the list of descriptions, description is ignored if text is null.
|
||||
* @return a string with the pattern of {{en|1=descriptionText}}
|
||||
*/
|
||||
static String formatList(List<UploadMediaDetail> descriptions) {
|
||||
StringBuilder descListString = new StringBuilder();
|
||||
for (UploadMediaDetail description : descriptions) {
|
||||
if (!description.isEmpty()) {
|
||||
String individualDescription = String.format("{{%s|1=%s}}", description.getLanguageCode(),
|
||||
description.getDescriptionText());
|
||||
descListString.append(individualDescription);
|
||||
}
|
||||
}
|
||||
return descListString.toString();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return descriptionText == null || descriptionText.isEmpty();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package fr.free.nrw.commons.upload
|
||||
|
||||
import fr.free.nrw.commons.nearby.Place
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Holds a description of an item being uploaded by [UploadActivity]
|
||||
*/
|
||||
data class UploadMediaDetail constructor(
|
||||
/**
|
||||
* @return The language code ie. "en" or "fr"
|
||||
*/
|
||||
/**
|
||||
* @param languageCode The language code ie. "en" or "fr"
|
||||
*/
|
||||
var languageCode: String? = null,
|
||||
var descriptionText: String = "",
|
||||
var captionText: String = ""
|
||||
) {
|
||||
constructor(place: Place) : this(
|
||||
Locale.getDefault().language,
|
||||
place.longDescription,
|
||||
place.name
|
||||
)
|
||||
/**
|
||||
* @return the index of the language selected in a spinner with [SpinnerLanguagesAdapter]
|
||||
*/
|
||||
/**
|
||||
* @param selectedLanguageIndex the index of the language selected in a spinner with [SpinnerLanguagesAdapter]
|
||||
*/
|
||||
var selectedLanguageIndex: Int = -1
|
||||
/**
|
||||
* returns if the description was added manually (by the user, or we have added it programaticallly)
|
||||
* @return
|
||||
*/
|
||||
/**
|
||||
* sets to true if the description was manually added by the user
|
||||
* @param manuallyAdded
|
||||
*/
|
||||
var isManuallyAdded: Boolean = false
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Formatting captions to the Wikibase format for sending labels
|
||||
* @param uploadMediaDetails list of media Details
|
||||
*/
|
||||
@JvmStatic
|
||||
fun formatCaptions(uploadMediaDetails: List<UploadMediaDetail>) =
|
||||
uploadMediaDetails.associate { it.languageCode to it.captionText }
|
||||
|
||||
/**
|
||||
* Formats the list of descriptions into the format Commons requires for uploads.
|
||||
*
|
||||
* @param descriptions the list of descriptions, description is ignored if text is null.
|
||||
* @return a string with the pattern of {{en|1=descriptionText}}
|
||||
*/
|
||||
@JvmStatic
|
||||
fun formatList(descriptions: List<UploadMediaDetail>) =
|
||||
descriptions.joinToString {
|
||||
if (it.descriptionText.isNotEmpty())
|
||||
"{{${it.languageCode}|1=${it.descriptionText}}}"
|
||||
else
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,9 +2,7 @@ package fr.free.nrw.commons.upload;
|
|||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
|
|
@ -107,36 +105,11 @@ public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDe
|
|||
public void init(int position) {
|
||||
UploadMediaDetail uploadMediaDetail = uploadMediaDetails.get(position);
|
||||
Timber.d("UploadMediaDetail is " + uploadMediaDetail);
|
||||
if (!TextUtils.isEmpty(uploadMediaDetail.getCaptionText())) {
|
||||
captionItemEditText.setText(uploadMediaDetail.getCaptionText());
|
||||
} else {
|
||||
captionItemEditText.setText("");
|
||||
}
|
||||
captionItemEditText.setText(uploadMediaDetail.getCaptionText());
|
||||
descItemEditText.setText(uploadMediaDetail.getDescriptionText());
|
||||
|
||||
if (!TextUtils.isEmpty(uploadMediaDetail.getDescriptionText())) {
|
||||
descItemEditText.setText(uploadMediaDetail.getDescriptionText());
|
||||
} else {
|
||||
descItemEditText.setText("");
|
||||
}
|
||||
|
||||
captionItemEditText.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
if (s.length() != 0) {
|
||||
eventListener.onEvent(true);
|
||||
} else eventListener.onEvent(false);
|
||||
}
|
||||
});
|
||||
captionItemEditText.addTextChangedListener(new AbstractTextWatcher(
|
||||
value -> eventListener.onEvent(value.length() != 0)) );
|
||||
|
||||
if (position == 0) {
|
||||
captionItemEditText.setCompoundDrawablesWithIntrinsicBounds(null, null, getInfoIcon(),
|
||||
|
|
@ -174,13 +147,11 @@ public class UploadMediaDetailAdapter extends RecyclerView.Adapter<UploadMediaDe
|
|||
}
|
||||
|
||||
captionItemEditText.addTextChangedListener(new AbstractTextWatcher(
|
||||
captionText -> uploadMediaDetails.get(position)
|
||||
.setCaptionText(captionText)));
|
||||
captionText -> uploadMediaDetails.get(position).setCaptionText(captionText)));
|
||||
initLanguageSpinner(position, uploadMediaDetail);
|
||||
|
||||
descItemEditText.addTextChangedListener(new AbstractTextWatcher(
|
||||
descriptionText -> uploadMediaDetails.get(position)
|
||||
.setDescriptionText(descriptionText)));
|
||||
descriptionText -> uploadMediaDetails.get(position).setDescriptionText(descriptionText)));
|
||||
initLanguageSpinner(position, uploadMediaDetail);
|
||||
|
||||
//If the description was manually added by the user, it deserves focus, if not, let the user decide
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import androidx.annotation.Nullable;
|
|||
import fr.free.nrw.commons.CommonsApplication;
|
||||
import fr.free.nrw.commons.auth.SessionManager;
|
||||
import fr.free.nrw.commons.contributions.Contribution;
|
||||
import fr.free.nrw.commons.filepicker.MimeTypeMapWrapper;
|
||||
import fr.free.nrw.commons.filepicker.UploadableFile;
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import fr.free.nrw.commons.nearby.Place;
|
||||
|
|
@ -18,15 +17,17 @@ import io.reactivex.Single;
|
|||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.subjects.BehaviorSubject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import timber.log.Timber;
|
||||
|
||||
@Singleton
|
||||
|
|
@ -37,23 +38,23 @@ public class UploadModel {
|
|||
private final Context context;
|
||||
private String license;
|
||||
private final Map<String, String> licensesByName;
|
||||
private List<UploadItem> items = new ArrayList<>();
|
||||
private CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
private final List<UploadItem> items = new ArrayList<>();
|
||||
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||
|
||||
private SessionManager sessionManager;
|
||||
private FileProcessor fileProcessor;
|
||||
private final SessionManager sessionManager;
|
||||
private final FileProcessor fileProcessor;
|
||||
private final ImageProcessingService imageProcessingService;
|
||||
private List<String> selectedCategories;
|
||||
private ArrayList<String> selectedDepictions;
|
||||
|
||||
@Inject
|
||||
UploadModel(@Named("licenses") List<String> licenses,
|
||||
@Named("default_preferences") JsonKvStore store,
|
||||
@Named("licenses_by_name") Map<String, String> licensesByName,
|
||||
Context context,
|
||||
SessionManager sessionManager,
|
||||
FileProcessor fileProcessor,
|
||||
ImageProcessingService imageProcessingService) {
|
||||
UploadModel(@Named("licenses") final List<String> licenses,
|
||||
@Named("default_preferences") final JsonKvStore store,
|
||||
@Named("licenses_by_name") final Map<String, String> licensesByName,
|
||||
final Context context,
|
||||
final SessionManager sessionManager,
|
||||
final FileProcessor fileProcessor,
|
||||
final ImageProcessingService imageProcessingService) {
|
||||
this.licenses = licenses;
|
||||
this.store = store;
|
||||
this.license = store.getString(Prefs.DEFAULT_LICENSE, Prefs.Licenses.CC_BY_SA_3);
|
||||
|
|
@ -80,31 +81,29 @@ public class UploadModel {
|
|||
}
|
||||
|
||||
public void setSelectedCategories(List<String> selectedCategories) {
|
||||
if (null == selectedCategories) {
|
||||
selectedCategories = new ArrayList<>();
|
||||
}
|
||||
this.selectedCategories = selectedCategories;
|
||||
this.selectedCategories = newListOf(selectedCategories);
|
||||
}
|
||||
|
||||
/**
|
||||
* pre process a one item at a time
|
||||
*/
|
||||
public Observable<UploadItem> preProcessImage(UploadableFile uploadableFile,
|
||||
Place place,
|
||||
String source,
|
||||
SimilarImageInterface similarImageInterface) {
|
||||
return Observable.just(getUploadItem(uploadableFile, place, source, similarImageInterface));
|
||||
public Observable<UploadItem> preProcessImage(final UploadableFile uploadableFile,
|
||||
final Place place,
|
||||
final String source,
|
||||
final SimilarImageInterface similarImageInterface) {
|
||||
return Observable.just(
|
||||
createAndAddUploadItem(uploadableFile, place, source, similarImageInterface));
|
||||
}
|
||||
|
||||
public Single<Integer> getImageQuality(UploadItem uploadItem) {
|
||||
public Single<Integer> getImageQuality(final UploadItem uploadItem) {
|
||||
return imageProcessingService.validateImage(uploadItem);
|
||||
}
|
||||
|
||||
private UploadItem getUploadItem(UploadableFile uploadableFile,
|
||||
Place place,
|
||||
String source,
|
||||
SimilarImageInterface similarImageInterface) {
|
||||
UploadableFile.DateTimeWithSource dateTimeWithSource = uploadableFile
|
||||
private UploadItem createAndAddUploadItem(final UploadableFile uploadableFile,
|
||||
final Place place,
|
||||
final String source,
|
||||
final SimilarImageInterface similarImageInterface) {
|
||||
final UploadableFile.DateTimeWithSource dateTimeWithSource = uploadableFile
|
||||
.getFileCreatedDate(context);
|
||||
long fileCreatedDate = -1;
|
||||
String createdTimestampSource = "";
|
||||
|
|
@ -113,23 +112,15 @@ public class UploadModel {
|
|||
createdTimestampSource = dateTimeWithSource.getSource();
|
||||
}
|
||||
Timber.d("File created date is %d", fileCreatedDate);
|
||||
ImageCoordinates imageCoordinates = fileProcessor
|
||||
final ImageCoordinates imageCoordinates = fileProcessor
|
||||
.processFileCoordinates(similarImageInterface, uploadableFile.getFilePath());
|
||||
UploadItem uploadItem = new UploadItem(uploadableFile.getContentUri(),
|
||||
final UploadItem uploadItem = new UploadItem(uploadableFile.getContentUri(),
|
||||
Uri.parse(uploadableFile.getFilePath()),
|
||||
uploadableFile.getMimeType(context), source, imageCoordinates, place, fileCreatedDate,
|
||||
createdTimestampSource);
|
||||
if (place != null) {
|
||||
uploadItem.title.setTitleText(place.name);
|
||||
if(uploadItem.uploadMediaDetails.isEmpty()) {
|
||||
uploadItem.uploadMediaDetails.add(new UploadMediaDetail());
|
||||
}
|
||||
uploadItem.uploadMediaDetails.get(0).setDescriptionText(place.getLongDescription());
|
||||
uploadItem.uploadMediaDetails.get(0).setLanguageCode("en");
|
||||
String languageCode = Locale.getDefault().getLanguage();
|
||||
uploadItem.uploadMediaDetails.get(0).setDescriptionText(place.getLongDescription());
|
||||
uploadItem.uploadMediaDetails.get(0).setLanguageCode(languageCode);
|
||||
uploadItem.uploadMediaDetails.get(0).setCaptionText(place.name);
|
||||
uploadItem.getUploadMediaDetails().set(0, new UploadMediaDetail(place));
|
||||
}
|
||||
if (!items.contains(uploadItem)) {
|
||||
items.add(uploadItem);
|
||||
|
|
@ -153,7 +144,7 @@ public class UploadModel {
|
|||
return license;
|
||||
}
|
||||
|
||||
public void setSelectedLicense(String licenseName) {
|
||||
public void setSelectedLicense(final String licenseName) {
|
||||
this.license = licensesByName.get(licenseName);
|
||||
store.putString(Prefs.DEFAULT_LICENSE, license);
|
||||
}
|
||||
|
|
@ -161,11 +152,11 @@ public class UploadModel {
|
|||
public Observable<Contribution> buildContributions() {
|
||||
return Observable.fromIterable(items).map(item ->
|
||||
{
|
||||
Contribution contribution = new Contribution(item.mediaUri, null,
|
||||
final Contribution contribution = new Contribution(item.mediaUri, null,
|
||||
item.getFileName(), item.uploadMediaDetails.size()!=0? UploadMediaDetail.formatCaptions(item.uploadMediaDetails):new HashMap<>(),
|
||||
UploadMediaDetail.formatList(item.uploadMediaDetails), -1,
|
||||
null, null, sessionManager.getAuthorName(),
|
||||
CommonsApplication.DEFAULT_EDIT_SUMMARY, selectedDepictions, item.gpsCoords.getDecimalCoords());
|
||||
CommonsApplication.DEFAULT_EDIT_SUMMARY, new ArrayList<>(selectedDepictions), item.gpsCoords.getDecimalCoords());
|
||||
if (item.place != null) {
|
||||
contribution.setWikiDataEntityId(item.place.getWikiDataEntityId());
|
||||
contribution.setWikiItemName(item.place.getName());
|
||||
|
|
@ -196,8 +187,8 @@ public class UploadModel {
|
|||
});
|
||||
}
|
||||
|
||||
public void deletePicture(String filePath) {
|
||||
Iterator<UploadItem> iterator = items.iterator();
|
||||
public void deletePicture(final String filePath) {
|
||||
final Iterator<UploadItem> iterator = items.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
if (iterator.next().mediaUri.toString().contains(filePath)) {
|
||||
iterator.remove();
|
||||
|
|
@ -213,20 +204,22 @@ public class UploadModel {
|
|||
return items;
|
||||
}
|
||||
|
||||
public void updateUploadItem(int index, UploadItem uploadItem) {
|
||||
UploadItem uploadItem1 = items.get(index);
|
||||
public void updateUploadItem(final int index, final UploadItem uploadItem) {
|
||||
final UploadItem uploadItem1 = items.get(index);
|
||||
uploadItem1.setMediaDetails(uploadItem.uploadMediaDetails);
|
||||
uploadItem1.setTitle(uploadItem.title);
|
||||
}
|
||||
|
||||
public void setSelectedDepictions(List<String> selectedDepictions) {
|
||||
if (null == selectedDepictions) {
|
||||
selectedDepictions = new ArrayList<>();
|
||||
}
|
||||
this.selectedDepictions = (ArrayList<String>) selectedDepictions;
|
||||
public void setSelectedDepictions(final List<String> selectedDepictions) {
|
||||
this.selectedDepictions = newListOf(selectedDepictions);
|
||||
}
|
||||
|
||||
public void useSimilarPictureCoordinates(ImageCoordinates imageCoordinates, int uploadItemIndex) {
|
||||
@NotNull
|
||||
private <T> ArrayList<T> newListOf(final List<T> items) {
|
||||
return items != null ? new ArrayList<>(items) : new ArrayList<>();
|
||||
}
|
||||
|
||||
public void useSimilarPictureCoordinates(final ImageCoordinates imageCoordinates, final int uploadItemIndex) {
|
||||
fileProcessor.useImageCoords(imageCoordinates);
|
||||
items.get(uploadItemIndex).setGpsCoords(imageCoordinates);
|
||||
}
|
||||
|
|
@ -239,29 +232,23 @@ public class UploadModel {
|
|||
private final String mimeType;
|
||||
private final String source;
|
||||
private ImageCoordinates gpsCoords;
|
||||
|
||||
public void setGpsCoords(ImageCoordinates gpsCoords) {
|
||||
this.gpsCoords = gpsCoords;
|
||||
}
|
||||
|
||||
private Title title;
|
||||
private List<UploadMediaDetail> uploadMediaDetails;
|
||||
private Place place;
|
||||
private long createdTimestamp;
|
||||
private String createdTimestampSource;
|
||||
private BehaviorSubject<Integer> imageQuality;
|
||||
|
||||
private final Place place;
|
||||
private final long createdTimestamp;
|
||||
private final String createdTimestampSource;
|
||||
private final BehaviorSubject<Integer> imageQuality;
|
||||
@SuppressLint("CheckResult")
|
||||
UploadItem(Uri originalContentUri,
|
||||
Uri mediaUri, String mimeType, String source, ImageCoordinates gpsCoords,
|
||||
Place place,
|
||||
long createdTimestamp,
|
||||
String createdTimestampSource) {
|
||||
UploadItem(final Uri originalContentUri,
|
||||
final Uri mediaUri, final String mimeType, final String source, final ImageCoordinates gpsCoords,
|
||||
final Place place,
|
||||
final long createdTimestamp,
|
||||
final String createdTimestampSource) {
|
||||
this.originalContentUri = originalContentUri;
|
||||
this.createdTimestampSource = createdTimestampSource;
|
||||
title = new Title();
|
||||
uploadMediaDetails = new ArrayList<>();
|
||||
uploadMediaDetails.add(new UploadMediaDetail());
|
||||
uploadMediaDetails = Collections.singletonList(new UploadMediaDetail());
|
||||
uploadMediaDetails = new ArrayList<>(Arrays.asList(new UploadMediaDetail()));
|
||||
this.place = place;
|
||||
this.mediaUri = mediaUri;
|
||||
this.mimeType = mimeType;
|
||||
|
|
@ -303,7 +290,7 @@ public class UploadModel {
|
|||
return this.imageQuality.getValue();
|
||||
}
|
||||
|
||||
public void setImageQuality(int imageQuality) {
|
||||
public void setImageQuality(final int imageQuality) {
|
||||
this.imageQuality.onNext(imageQuality);
|
||||
}
|
||||
|
||||
|
|
@ -311,12 +298,12 @@ public class UploadModel {
|
|||
return place;
|
||||
}
|
||||
|
||||
public void setTitle(Title title) {
|
||||
public void setTitle(final Title title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
|
||||
public void setMediaDetails(List<UploadMediaDetail> uploadMediaDetails) {
|
||||
public void setMediaDetails(final List<UploadMediaDetail> uploadMediaDetails) {
|
||||
this.uploadMediaDetails = uploadMediaDetails;
|
||||
}
|
||||
|
||||
|
|
@ -325,7 +312,7 @@ public class UploadModel {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
public boolean equals(@Nullable final Object obj) {
|
||||
if (!(obj instanceof UploadItem)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -345,6 +332,10 @@ public class UploadModel {
|
|||
public String getFileName() {
|
||||
return uploadMediaDetails.get(0).getCaptionText();
|
||||
}
|
||||
}
|
||||
|
||||
public void setGpsCoords(final ImageCoordinates gpsCoords) {
|
||||
this.gpsCoords = gpsCoords;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import androidx.core.app.NotificationManagerCompat;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
|
|
@ -35,18 +36,8 @@ import fr.free.nrw.commons.utils.CommonsDateUtil;
|
|||
import fr.free.nrw.commons.wikidata.WikidataEditService;
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.Scheduler;
|
||||
import io.reactivex.SingleObserver;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.inject.Inject;
|
||||
import timber.log.Timber;
|
||||
|
||||
public class UploadService extends HandlerService<Contribution> {
|
||||
|
|
@ -275,55 +266,59 @@ public class UploadService extends HandlerService<Contribution> {
|
|||
uploadStash.getFilekey());
|
||||
}
|
||||
})
|
||||
.subscribe(uploadResult -> {
|
||||
Timber.d("Stash upload response 2 is %s", uploadResult.toString());
|
||||
|
||||
notificationManager.cancel(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS);
|
||||
|
||||
String resultStatus = uploadResult.getResult();
|
||||
if (!resultStatus.equals("Success")) {
|
||||
Timber.d("Contribution upload failed. Wikidata entity won't be edited");
|
||||
showFailedNotification(contribution);
|
||||
} else {
|
||||
String canonicalFilename = "File:" + uploadResult.getFilename();
|
||||
final String wikiDataEntityId = contribution.getWikiDataEntityId();
|
||||
Timber.d("Contribution upload success. Initiating Wikidata edit for entity id %s",
|
||||
wikiDataEntityId);
|
||||
// to perform upload of depictions we pass on depiction entityId of the selected depictions to the wikidataEditService
|
||||
final String p18Value = contribution.getP18Value();
|
||||
final String wikiItemName = contribution.getWikiItemName();
|
||||
if (contribution.getDepictionsEntityIds() != null) {
|
||||
for (String depictionEntityId : contribution.getDepictionsEntityIds()) {
|
||||
wikidataEditService.createClaimWithLogging(depictionEntityId,
|
||||
wikiItemName, canonicalFilename, p18Value);
|
||||
}
|
||||
}
|
||||
Timber.d("Contribution upload success. Initiating Wikidata edit for"
|
||||
+ " entity id %s if necessary (if P18 is null). P18 value is %s",
|
||||
wikiDataEntityId, p18Value);
|
||||
wikidataEditService.createClaimWithLogging(
|
||||
wikiDataEntityId, wikiItemName, canonicalFilename,p18Value);
|
||||
|
||||
wikidataEditService.createLabelforWikidataEntity(
|
||||
wikiDataEntityId, canonicalFilename, contribution.getCaptions());
|
||||
contribution.setFilename(canonicalFilename);
|
||||
contribution.setImageUrl(uploadResult.getImageinfo().getOriginalUrl());
|
||||
contribution.setState(Contribution.STATE_COMPLETED);
|
||||
contribution.setDateUploaded(CommonsDateUtil.getIso8601DateFormatShort()
|
||||
.parse(uploadResult.getImageinfo().getTimestamp()));
|
||||
compositeDisposable.add(contributionDao
|
||||
.save(contribution)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.observeOn(mainThreadScheduler)
|
||||
.subscribe());
|
||||
}
|
||||
}, throwable -> {
|
||||
.subscribe(
|
||||
uploadResult -> onUpload(contribution, notificationTag, uploadResult),
|
||||
throwable -> {
|
||||
Timber.w(throwable, "Exception during upload");
|
||||
notificationManager.cancel(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS);
|
||||
showFailedNotification(contribution);
|
||||
});
|
||||
}
|
||||
|
||||
private void onUpload(Contribution contribution, String notificationTag,
|
||||
UploadResult uploadResult) throws ParseException {
|
||||
Timber.d("Stash upload response 2 is %s", uploadResult.toString());
|
||||
|
||||
notificationManager.cancel(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS);
|
||||
|
||||
String resultStatus = uploadResult.getResult();
|
||||
if (!resultStatus.equals("Success")) {
|
||||
Timber.d("Contribution upload failed. Wikidata entity won't be edited");
|
||||
showFailedNotification(contribution);
|
||||
} else {
|
||||
String canonicalFilename = "File:" + uploadResult.getFilename();
|
||||
final String wikiDataEntityId = contribution.getWikiDataEntityId();
|
||||
Timber.d("Contribution upload success. Initiating Wikidata edit for entity id %s",
|
||||
wikiDataEntityId);
|
||||
// to perform upload of depictions we pass on depiction entityId of the selected depictions to the wikidataEditService
|
||||
final String p18Value = contribution.getP18Value();
|
||||
final String wikiItemName = contribution.getWikiItemName();
|
||||
if (contribution.getDepictionsEntityIds() != null) {
|
||||
for (String depictionEntityId : contribution.getDepictionsEntityIds()) {
|
||||
wikidataEditService.createClaimWithLogging(depictionEntityId,
|
||||
wikiItemName, canonicalFilename, p18Value);
|
||||
}
|
||||
}
|
||||
Timber.d("Contribution upload success. Initiating Wikidata edit for"
|
||||
+ " entity id %s if necessary (if P18 is null). P18 value is %s",
|
||||
wikiDataEntityId, p18Value);
|
||||
wikidataEditService.createClaimWithLogging(
|
||||
wikiDataEntityId, wikiItemName, canonicalFilename,p18Value);
|
||||
|
||||
wikidataEditService.createLabelforWikidataEntity(canonicalFilename, contribution.getCaptions());
|
||||
contribution.setFilename(canonicalFilename);
|
||||
contribution.setImageUrl(uploadResult.getImageinfo().getOriginalUrl());
|
||||
contribution.setState(Contribution.STATE_COMPLETED);
|
||||
contribution.setDateUploaded(CommonsDateUtil.getIso8601DateFormatShort()
|
||||
.parse(uploadResult.getImageinfo().getTimestamp()));
|
||||
compositeDisposable.add(contributionDao
|
||||
.save(contribution)
|
||||
.subscribeOn(ioThreadScheduler)
|
||||
.observeOn(mainThreadScheduler)
|
||||
.subscribe());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("StringFormatInvalid")
|
||||
@SuppressWarnings("deprecation")
|
||||
private void showFailedNotification(Contribution contribution) {
|
||||
|
|
|
|||
|
|
@ -32,14 +32,12 @@ import fr.free.nrw.commons.kvstore.JsonKvStore;
|
|||
import fr.free.nrw.commons.location.LatLng;
|
||||
import fr.free.nrw.commons.nearby.Place;
|
||||
import fr.free.nrw.commons.settings.Prefs;
|
||||
import fr.free.nrw.commons.upload.Description;
|
||||
//import fr.free.nrw.commons.upload.DescriptionsAdapter;
|
||||
import fr.free.nrw.commons.upload.UploadMediaDetail;
|
||||
import fr.free.nrw.commons.upload.UploadMediaDetailAdapter;
|
||||
import fr.free.nrw.commons.upload.ImageCoordinates;
|
||||
import fr.free.nrw.commons.upload.SimilarImageDialogFragment;
|
||||
import fr.free.nrw.commons.upload.Title;
|
||||
import fr.free.nrw.commons.upload.UploadBaseFragment;
|
||||
import fr.free.nrw.commons.upload.UploadMediaDetail;
|
||||
import fr.free.nrw.commons.upload.UploadMediaDetailAdapter;
|
||||
import fr.free.nrw.commons.upload.UploadModel;
|
||||
import fr.free.nrw.commons.upload.UploadModel.UploadItem;
|
||||
import fr.free.nrw.commons.utils.DialogUtil;
|
||||
|
|
@ -55,6 +53,8 @@ import javax.inject.Named;
|
|||
import org.apache.commons.lang3.StringUtils;
|
||||
import timber.log.Timber;
|
||||
|
||||
//import fr.free.nrw.commons.upload.DescriptionsAdapter;
|
||||
|
||||
public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
||||
UploadMediaDetailsContract.View, UploadMediaDetailAdapter.EventListener {
|
||||
|
||||
|
|
@ -282,10 +282,6 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
|||
@Override
|
||||
public void onImageProcessed(UploadItem uploadItem, Place place) {
|
||||
this.uploadItem = uploadItem;
|
||||
if (uploadItem.getFileName() != null) {
|
||||
setDescriptionsInAdapter(uploadItem.getUploadMediaDetails());
|
||||
}
|
||||
|
||||
descriptions = uploadItem.getUploadMediaDetails();
|
||||
photoViewBackgroundImage.setImageURI(uploadItem.getMediaUri());
|
||||
setDescriptionsInAdapter(descriptions);
|
||||
|
|
@ -306,10 +302,7 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
|||
place.getName()),
|
||||
() -> {
|
||||
etTitle.setText(place.getName());
|
||||
UploadMediaDetail description = new UploadMediaDetail();
|
||||
description.setLanguageCode("en");
|
||||
description.setDescriptionText(place.getLongDescription());
|
||||
descriptions = Arrays.asList(description);
|
||||
descriptions = new ArrayList<>(Arrays.asList(new UploadMediaDetail()));
|
||||
setDescriptionsInAdapter(descriptions);
|
||||
},
|
||||
() -> {
|
||||
|
|
@ -431,13 +424,6 @@ public class UploadMediaDetailFragment extends UploadBaseFragment implements
|
|||
}
|
||||
|
||||
private void setDescriptionsInAdapter(List<UploadMediaDetail> uploadMediaDetails){
|
||||
if(uploadMediaDetails==null){
|
||||
uploadMediaDetails=new ArrayList<>();
|
||||
}
|
||||
|
||||
if(uploadMediaDetails.size()==0){
|
||||
uploadMediaDetails.add(new UploadMediaDetail());
|
||||
}
|
||||
uploadMediaDetailAdapter.setItems(uploadMediaDetails);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import com.google.gson.JsonObject;
|
|||
import fr.free.nrw.commons.BuildConfig;
|
||||
import fr.free.nrw.commons.R;
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore;
|
||||
import fr.free.nrw.commons.media.MediaClient;
|
||||
import fr.free.nrw.commons.upload.mediaDetails.CaptionInterface;
|
||||
import fr.free.nrw.commons.utils.ConfigUtils;
|
||||
import fr.free.nrw.commons.utils.ViewUtil;
|
||||
|
|
@ -26,7 +25,6 @@ import javax.inject.Inject;
|
|||
import javax.inject.Named;
|
||||
import javax.inject.Singleton;
|
||||
import org.wikipedia.csrf.CsrfTokenClient;
|
||||
import org.wikipedia.dataclient.Service;
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
|
|
@ -46,42 +44,31 @@ public class WikidataEditService {
|
|||
private final CaptionInterface captionInterface;
|
||||
private final WikiBaseClient wikiBaseClient;
|
||||
private final WikidataClient wikidataClient;
|
||||
private final MediaClient mediaClient;
|
||||
private final CsrfTokenClient csrfTokenClient;
|
||||
private final Service service;
|
||||
|
||||
@Inject
|
||||
public WikidataEditService(Context context,
|
||||
WikidataEditListener wikidataEditListener,
|
||||
MediaClient mediaClient,
|
||||
@Named("default_preferences") JsonKvStore directKvStore,
|
||||
WikiBaseClient wikiBaseClient,
|
||||
CaptionInterface captionInterface,
|
||||
WikidataClient wikidataClient,
|
||||
@Named("commons-csrf") CsrfTokenClient csrfTokenClient,
|
||||
@Named("commons-service") Service service) {
|
||||
public WikidataEditService(final Context context,
|
||||
final WikidataEditListener wikidataEditListener,
|
||||
@Named("default_preferences") final JsonKvStore directKvStore,
|
||||
final WikiBaseClient wikiBaseClient,
|
||||
final CaptionInterface captionInterface,
|
||||
final WikidataClient wikidataClient,
|
||||
@Named("commons-csrf") final CsrfTokenClient csrfTokenClient) {
|
||||
this.context = context;
|
||||
this.wikidataEditListener = wikidataEditListener;
|
||||
this.directKvStore = directKvStore;
|
||||
this.captionInterface = captionInterface;
|
||||
this.wikiBaseClient = wikiBaseClient;
|
||||
this.mediaClient = mediaClient;
|
||||
this.wikidataClient = wikidataClient;
|
||||
this.csrfTokenClient = csrfTokenClient;
|
||||
this.service = service;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a P18 claim and log the edit with custom tag
|
||||
<<<<<<< HEAD
|
||||
*
|
||||
* @param wikidataEntityId
|
||||
* @param fileName
|
||||
=======
|
||||
* @param wikidataEntityId a unique id of each Wikidata items
|
||||
* @param fileName name of the file we will upload
|
||||
* @param p18Value pic attribute of Wikidata item
|
||||
>>>>>>> origin/master
|
||||
*/
|
||||
public void createClaimWithLogging(String wikidataEntityId, String wikiItemName, String fileName, String p18Value) {
|
||||
if (wikidataEntityId == null) {
|
||||
|
|
@ -104,8 +91,8 @@ public class WikidataEditService {
|
|||
return;
|
||||
}
|
||||
|
||||
editWikidataProperty(wikidataEntityId, wikiItemName, fileName);
|
||||
//editWikiBaseDepictsProperty(wikidataEntityId, fileName);
|
||||
editWikidataProperty(wikidataEntityId, wikiItemName, fileName);;
|
||||
editWikiBaseDepictsProperty(wikidataEntityId, fileName);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -122,7 +109,7 @@ public class WikidataEditService {
|
|||
Timber.d("Upload successful with wiki data entity id as %s", wikidataEntityId);
|
||||
Timber.d("Attempting to edit Wikidata property %s", wikidataEntityId);
|
||||
|
||||
String propertyValue = getFileName(fileName);
|
||||
final String propertyValue = getFileName(fileName);
|
||||
|
||||
Timber.d("Entity id is %s and property value is %s", wikidataEntityId, propertyValue);
|
||||
wikidataClient.createClaim(wikidataEntityId, propertyValue)
|
||||
|
|
@ -148,7 +135,7 @@ public class WikidataEditService {
|
|||
* @param fileName
|
||||
*/
|
||||
@SuppressLint("CheckResult")
|
||||
private void editWikiBaseDepictsProperty(String wikidataEntityId, String fileName) {
|
||||
private void editWikiBaseDepictsProperty(final String wikidataEntityId, final String fileName) {
|
||||
wikiBaseClient.getFileEntityId(fileName)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
|
|
@ -166,37 +153,37 @@ public class WikidataEditService {
|
|||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private void addDepictsProperty(String entityId, String fileEntityId) {
|
||||
private void addDepictsProperty(String entityId, final String fileEntityId) {
|
||||
if (ConfigUtils.isBetaFlavour()) {
|
||||
entityId = "Q10"; // Wikipedia:Sandbox (Q10)
|
||||
}
|
||||
|
||||
JsonObject value = new JsonObject();
|
||||
final JsonObject value = new JsonObject();
|
||||
value.addProperty("entity-type", "item");
|
||||
value.addProperty("numeric-id", entityId.replace("Q", ""));
|
||||
value.addProperty("id", entityId);
|
||||
|
||||
JsonObject dataValue = new JsonObject();
|
||||
final JsonObject dataValue = new JsonObject();
|
||||
dataValue.add("value", value);
|
||||
dataValue.addProperty("type", "wikibase-entityid");
|
||||
|
||||
JsonObject mainSnak = new JsonObject();
|
||||
final JsonObject mainSnak = new JsonObject();
|
||||
mainSnak.addProperty("snaktype", "value");
|
||||
mainSnak.addProperty("property", BuildConfig.DEPICTS_PROPERTY);
|
||||
mainSnak.add("datavalue", dataValue);
|
||||
|
||||
JsonObject claim = new JsonObject();
|
||||
final JsonObject claim = new JsonObject();
|
||||
claim.add("mainsnak", mainSnak);
|
||||
claim.addProperty("type", "statement");
|
||||
claim.addProperty("rank", "preferred");
|
||||
|
||||
JsonArray claims = new JsonArray();
|
||||
final JsonArray claims = new JsonArray();
|
||||
claims.add(claim);
|
||||
|
||||
JsonObject jsonData = new JsonObject();
|
||||
final JsonObject jsonData = new JsonObject();
|
||||
jsonData.add("claims", claims);
|
||||
|
||||
String data = jsonData.toString();
|
||||
final String data = jsonData.toString();
|
||||
|
||||
Observable.defer((Callable<ObservableSource<Boolean>>) () ->
|
||||
wikiBaseClient.postEditEntity(PAGE_ID_PREFIX + fileEntityId, data))
|
||||
|
|
@ -253,18 +240,19 @@ public class WikidataEditService {
|
|||
* Adding captions as labels after image is successfully uploaded
|
||||
*/
|
||||
@SuppressLint("CheckResult")
|
||||
public void createLabelforWikidataEntity(String wikiDataEntityId, String fileName, Map<String, String> captions) {
|
||||
public void createLabelforWikidataEntity(final String fileName,
|
||||
final Map<String, String> captions) {
|
||||
Observable.fromCallable(() -> wikiBaseClient.getFileEntityId(fileName))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(fileEntityId -> {
|
||||
if (fileEntityId != null) {
|
||||
for (Map.Entry<String, String> entry : captions.entrySet()) {
|
||||
Map<String, String> caption = new HashMap<>();
|
||||
for (final Map.Entry<String, String> entry : captions.entrySet()) {
|
||||
final Map<String, String> caption = new HashMap<>();
|
||||
caption.put(entry.getKey(), entry.getValue());
|
||||
try {
|
||||
wikidataAddLabels(wikiDataEntityId, fileEntityId.toString(), caption);
|
||||
} catch (Throwable throwable) {
|
||||
wikidataAddLabels(fileEntityId.toString(), caption);
|
||||
} catch (final Throwable throwable) {
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
|
@ -280,13 +268,12 @@ public class WikidataEditService {
|
|||
/**
|
||||
* Adds label to Wikidata using the fileEntityId and the edit token, obtained from csrfTokenClient
|
||||
*
|
||||
* @param wikiDataEntityId entityId for the current contribution
|
||||
* @param fileEntityId
|
||||
* @param caption
|
||||
*/
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
private void wikidataAddLabels(String wikiDataEntityId, String fileEntityId, Map<String, String> caption) throws Throwable {
|
||||
private void wikidataAddLabels(final String fileEntityId, final Map<String, String> caption) {
|
||||
Observable.fromCallable(() -> {
|
||||
try {
|
||||
return csrfTokenClient.getTokenBlocking();
|
||||
|
|
|
|||
|
|
@ -2,12 +2,14 @@ package fr.free.nrw.commons.wikidata
|
|||
|
||||
import android.content.Context
|
||||
import com.nhaarman.mockitokotlin2.verifyZeroInteractions
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import fr.free.nrw.commons.kvstore.JsonKvStore
|
||||
import fr.free.nrw.commons.wikidata.model.AddEditTagResponse
|
||||
import io.reactivex.Observable
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.ArgumentMatchers
|
||||
import org.mockito.ArgumentMatchers.any
|
||||
import org.mockito.ArgumentMatchers.anyString
|
||||
import org.mockito.InjectMocks
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.*
|
||||
|
|
@ -15,19 +17,19 @@ import org.mockito.MockitoAnnotations
|
|||
|
||||
class WikidataEditServiceTest {
|
||||
@Mock
|
||||
internal var context: Context? = null
|
||||
@Mock
|
||||
internal var wikidataEditListener: WikidataEditListener? = null
|
||||
@Mock
|
||||
internal var directKvStore: JsonKvStore? = null
|
||||
@Mock
|
||||
internal var wikidataClient: WikidataClient? = null
|
||||
internal lateinit var context: Context
|
||||
|
||||
@Mock
|
||||
internal var wikibaseClient: WikiBaseClient? = null
|
||||
internal lateinit var directKvStore: JsonKvStore
|
||||
|
||||
@Mock
|
||||
internal lateinit var wikidataClient: WikidataClient
|
||||
|
||||
@Mock
|
||||
internal lateinit var wikibaseClient: WikiBaseClient
|
||||
|
||||
@InjectMocks
|
||||
var wikidataEditService: WikidataEditService? = null
|
||||
lateinit var wikidataEditService: WikidataEditService
|
||||
|
||||
@Before
|
||||
@Throws(Exception::class)
|
||||
|
|
@ -37,40 +39,40 @@ class WikidataEditServiceTest {
|
|||
|
||||
@Test
|
||||
fun noClaimsWhenEntityIdIsNull() {
|
||||
wikidataEditService!!.createClaimWithLogging(null, null,"Test.jpg","")
|
||||
verifyZeroInteractions(wikidataClient!!)
|
||||
wikidataEditService.createClaimWithLogging(null, null,"Test.jpg","")
|
||||
verifyZeroInteractions(wikidataClient)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun noClaimsWhenFileNameIsNull() {
|
||||
wikidataEditService!!.createClaimWithLogging("Q1", "Test", null,"")
|
||||
verifyZeroInteractions(wikidataClient!!)
|
||||
wikidataEditService.createClaimWithLogging("Q1", "Test", null,"")
|
||||
verifyZeroInteractions(wikidataClient)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun noClaimsWhenP18IsNotEmpty() {
|
||||
wikidataEditService!!.createClaimWithLogging("Q1", "Test","Test.jpg","Previous.jpg")
|
||||
verifyZeroInteractions(wikidataClient!!)
|
||||
wikidataEditService.createClaimWithLogging("Q1", "Test","Test.jpg","Previous.jpg")
|
||||
verifyZeroInteractions(wikidataClient)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun noClaimsWhenLocationIsNotCorrect() {
|
||||
`when`(directKvStore!!.getBoolean("Picture_Has_Correct_Location", true))
|
||||
.thenReturn(false)
|
||||
wikidataEditService!!.createClaimWithLogging("Q1", "","Test.jpg","")
|
||||
verifyZeroInteractions(wikidataClient!!)
|
||||
whenever(directKvStore.getBoolean("Picture_Has_Correct_Location", true))
|
||||
.thenReturn(false)
|
||||
wikidataEditService.createClaimWithLogging("Q1", "", "Test.jpg", "")
|
||||
verifyZeroInteractions(wikidataClient)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun createClaimWithLogging() {
|
||||
`when`(directKvStore!!.getBoolean("Picture_Has_Correct_Location", true))
|
||||
.thenReturn(true)
|
||||
`when`(wikidataClient!!.createClaim(ArgumentMatchers.anyString(), ArgumentMatchers.anyString()))
|
||||
.thenReturn(Observable.just(1L))
|
||||
`when`(wikidataClient!!.addEditTag(anyLong(), ArgumentMatchers.anyString(), ArgumentMatchers.anyString()))
|
||||
.thenReturn(Observable.just(mock(AddEditTagResponse::class.java)))
|
||||
wikidataEditService!!.createClaimWithLogging("Q1", "Test","Test.jpg","")
|
||||
verify(wikidataClient!!, times(1))
|
||||
.createClaim(ArgumentMatchers.anyString(), ArgumentMatchers.anyString())
|
||||
whenever(directKvStore.getBoolean("Picture_Has_Correct_Location", true))
|
||||
.thenReturn(true)
|
||||
whenever(wikidataClient.createClaim(anyString(), anyString()))
|
||||
.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))
|
||||
wikidataEditService.createClaimWithLogging("Q1", "", "Test.jpg", "")
|
||||
verify(wikidataClient, times(1)).createClaim(anyString(), anyString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue