Bugfix/p18 uploads (#3869)

* updated gradle plugin version

* BugFix #3856
* Do not use preference for deciding acceptable lat long for nearby uploads, instead save the corresponding location in the Contribution via UploadItem

* Marshall contribution's hasInvalidLocation

* reset un-related changes

* Fixed test cases

* Minor code formatting and docs
This commit is contained in:
Ashish Kumar 2020-07-14 19:20:40 +05:30 committed by GitHub
parent e471226405
commit e7d93159d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 67 additions and 33 deletions

View file

@ -60,6 +60,19 @@ public class Contribution extends Media {
private String p18Value; private String p18Value;
public Uri contentProviderUri; public Uri contentProviderUri;
public String dateCreatedSource; public String dateCreatedSource;
public int hasInvalidLocation;
/**
* Set this true when ImageProcessor has said that the location is invalid
* @param hasInvalidLocation
*/
public void setHasInvalidLocation(boolean hasInvalidLocation) {
this.hasInvalidLocation = hasInvalidLocation ? 1 : 0;
}
public boolean isHasInvalidLocation() {
return hasInvalidLocation == 1;
}
public Contribution(Uri contentUri, String filename, Uri localUri, String imageUrl, Date dateCreated, public Contribution(Uri contentUri, String filename, Uri localUri, String imageUrl, Date dateCreated,
int state, long dataLength, Date dateUploaded, long transferred, int state, long dataLength, Date dateUploaded, long transferred,
@ -269,6 +282,7 @@ public class Contribution extends Media {
this.contentProviderUri = contentProviderUri; this.contentProviderUri = contentProviderUri;
} }
@Override @Override
public int describeContents() { public int describeContents() {
return 0; return 0;
@ -290,6 +304,7 @@ public class Contribution extends Media {
dest.writeString(this.p18Value); dest.writeString(this.p18Value);
dest.writeParcelable(this.contentProviderUri, flags); dest.writeParcelable(this.contentProviderUri, flags);
dest.writeString(this.dateCreatedSource); dest.writeString(this.dateCreatedSource);
dest.writeInt(this.hasInvalidLocation);
} }
protected Contribution(Parcel in) { protected Contribution(Parcel in) {
@ -307,6 +322,7 @@ public class Contribution extends Media {
this.p18Value = in.readString(); this.p18Value = in.readString();
this.contentProviderUri = in.readParcelable(Uri.class.getClassLoader()); this.contentProviderUri = in.readParcelable(Uri.class.getClassLoader());
this.dateCreatedSource = in.readString(); this.dateCreatedSource = in.readString();
this.hasInvalidLocation = in.readInt();
} }
public static final Creator<Contribution> CREATOR = new Creator<Contribution>() { public static final Creator<Contribution> CREATOR = new Creator<Contribution>() {

View file

@ -7,7 +7,7 @@ import androidx.room.TypeConverters;
import fr.free.nrw.commons.contributions.Contribution; import fr.free.nrw.commons.contributions.Contribution;
import fr.free.nrw.commons.contributions.ContributionDao; import fr.free.nrw.commons.contributions.ContributionDao;
@Database(entities = {Contribution.class}, version = 1, exportSchema = false) @Database(entities = {Contribution.class}, version = 2, exportSchema = false)
@TypeConverters({Converters.class}) @TypeConverters({Converters.class})
abstract public class AppDatabase extends RoomDatabase { abstract public class AppDatabase extends RoomDatabase {
public abstract ContributionDao getContributionDao(); public abstract ContributionDao getContributionDao();

View file

@ -7,6 +7,8 @@ import android.content.Context;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import androidx.collection.LruCache; import androidx.collection.LruCache;
import androidx.room.Room; import androidx.room.Room;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import com.github.varunpant.quadtree.QuadTree; import com.github.varunpant.quadtree.QuadTree;
import com.google.gson.Gson; import com.google.gson.Gson;
import dagger.Module; import dagger.Module;
@ -52,6 +54,14 @@ public class CommonsApplicationModule {
public static final String MAIN_THREAD="main_thread"; public static final String MAIN_THREAD="main_thread";
private AppDatabase appDatabase; private AppDatabase appDatabase;
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
@Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE contribution "
+ " ADD COLUMN hasInvalidLocation INTEGER");
}
};
public CommonsApplicationModule(Context applicationContext) { public CommonsApplicationModule(Context applicationContext) {
this.applicationContext = applicationContext; this.applicationContext = applicationContext;
} }
@ -231,7 +241,9 @@ public class CommonsApplicationModule {
@Provides @Provides
@Singleton @Singleton
public AppDatabase provideAppDataBase() { public AppDatabase provideAppDataBase() {
appDatabase=Room.databaseBuilder(applicationContext, AppDatabase.class, "commons_room.db").build(); appDatabase=Room.databaseBuilder(applicationContext, AppDatabase.class, "commons_room.db")
.addMigrations(MIGRATION_1_2)
.build();
return appDatabase; return appDatabase;
} }

View file

@ -172,6 +172,7 @@ public class UploadModel {
contribution.setSource(item.source); contribution.setSource(item.source);
contribution.setContentProviderUri(item.mediaUri); contribution.setContentProviderUri(item.mediaUri);
contribution.setDateUploaded(new Date()); contribution.setDateUploaded(new Date());
contribution.setHasInvalidLocation(item.hasInvalidLocation);
Timber.d("Created timestamp while building contribution is %s, %s", Timber.d("Created timestamp while building contribution is %s, %s",
item.getCreatedTimestamp(), item.getCreatedTimestamp(),
@ -221,6 +222,7 @@ public class UploadModel {
private final String mimeType; private final String mimeType;
private final String source; private final String source;
private ImageCoordinates gpsCoords; private ImageCoordinates gpsCoords;
private boolean hasInvalidLocation;
public void setGpsCoords(ImageCoordinates gpsCoords) { public void setGpsCoords(ImageCoordinates gpsCoords) {
this.gpsCoords = gpsCoords; this.gpsCoords = gpsCoords;
@ -326,6 +328,10 @@ public class UploadModel {
public int hashCode() { public int hashCode() {
return mediaUri.hashCode(); return mediaUri.hashCode();
} }
public void setHasInvalidLocation(boolean hasInvalidLocation) {
this.hasInvalidLocation=hasInvalidLocation;
}
} }
} }

View file

@ -282,7 +282,15 @@ public class UploadService extends HandlerService<Contribution> {
Timber.d("Contribution upload success. Initiating Wikidata edit for" Timber.d("Contribution upload success. Initiating Wikidata edit for"
+ " entity id %s if necessary (if P18 is null). P18 value is %s", + " entity id %s if necessary (if P18 is null). P18 value is %s",
contribution.getWikiDataEntityId(), contribution.getP18Value()); contribution.getWikiDataEntityId(), contribution.getP18Value());
wikidataEditService.createClaimWithLogging(contribution.getWikiDataEntityId(), contribution.getWikiItemName(), canonicalFilename, contribution.getP18Value()); if (!contribution.isHasInvalidLocation()) {
wikidataEditService
.createClaimWithLogging(contribution.getWikiDataEntityId(),
contribution.getWikiItemName(), canonicalFilename,
contribution.getP18Value());
} else {
Timber
.d("Image location and nearby place location mismatched, so Wikidata item won't be edited");
}
contribution.setFilename(canonicalFilename); contribution.setFilename(canonicalFilename);
contribution.setImageUrl(uploadResult.getImageinfo().getOriginalUrl()); contribution.setImageUrl(uploadResult.getImageinfo().getOriginalUrl());
contribution.setState(Contribution.STATE_COMPLETED); contribution.setState(Contribution.STATE_COMPLETED);

View file

@ -120,7 +120,7 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
.observeOn(mainThreadScheduler) .observeOn(mainThreadScheduler)
.subscribe(imageResult -> { .subscribe(imageResult -> {
view.showProgress(false); view.showProgress(false);
handleImageResult(imageResult); handleImageResult(imageResult, uploadItem);
}, },
throwable -> { throwable -> {
view.showProgress(false); view.showProgress(false);
@ -165,13 +165,16 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
/** /**
* handles image quality verifications * handles image quality verifications
* *
* @param imageResult * @param imageResult
*/ * @param uploadItem
public void handleImageResult(Integer imageResult) { */
public void handleImageResult(Integer imageResult,
UploadItem uploadItem) {
if (imageResult == IMAGE_KEEP || imageResult == IMAGE_OK) { if (imageResult == IMAGE_KEEP || imageResult == IMAGE_OK) {
view.onImageValidationSuccess(); view.onImageValidationSuccess();
uploadItem.setHasInvalidLocation(false);
} else { } else {
handleBadImage(imageResult); handleBadImage(imageResult, uploadItem);
} }
} }
@ -179,12 +182,14 @@ public class UploadMediaPresenter implements UserActionListener, SimilarImageInt
* Handle images, say empty title, duplicate file name, bad picture(in all other cases) * Handle images, say empty title, duplicate file name, bad picture(in all other cases)
* *
* @param errorCode * @param errorCode
* @param uploadItem
*/ */
public void handleBadImage(Integer errorCode) { public void handleBadImage(Integer errorCode,
UploadItem uploadItem) {
Timber.d("Handle bad picture with error code %d", errorCode); Timber.d("Handle bad picture with error code %d", errorCode);
if (errorCode if (errorCode
>= 8) { // If location of image and nearby does not match, then set shared preferences to disable wikidata edits >= 8) { // If location of image and nearby does not match, then set shared preferences to disable wikidata edits
repository.saveValue("Picture_Has_Correct_Location", false); uploadItem.setHasInvalidLocation(true);
} }
switch (errorCode) { switch (errorCode) {

View file

@ -61,11 +61,6 @@ public class WikidataEditService {
return; return;
} }
if (!(directKvStore.getBoolean("Picture_Has_Correct_Location", true))) {
Timber.d("Image location and nearby place location mismatched, so Wikidata item won't be edited");
return;
}
if (p18Value != null && !p18Value.trim().isEmpty()) { if (p18Value != null && !p18Value.trim().isEmpty()) {
Timber.d("Skipping creation of claim as p18Value is not empty, we won't override existing image"); Timber.d("Skipping creation of claim as p18Value is not empty, we won't override existing image");
return; return;

View file

@ -109,20 +109,20 @@ class UploadMediaPresenterTest {
@Test @Test
fun handleImageResult() { fun handleImageResult() {
//Positive case test //Positive case test
uploadMediaPresenter.handleImageResult(IMAGE_KEEP) uploadMediaPresenter.handleImageResult(IMAGE_KEEP, uploadItem)
verify(view).onImageValidationSuccess() verify(view).onImageValidationSuccess()
//Duplicate file name //Duplicate file name
uploadMediaPresenter.handleImageResult(FILE_NAME_EXISTS) uploadMediaPresenter.handleImageResult(FILE_NAME_EXISTS, uploadItem)
verify(view).showDuplicatePicturePopup() verify(view).showDuplicatePicturePopup()
//Empty Title test //Empty Title test
uploadMediaPresenter.handleImageResult(EMPTY_TITLE) uploadMediaPresenter.handleImageResult(EMPTY_TITLE, uploadItem)
verify(view).showMessage(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt()) verify(view).showMessage(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt())
//Bad Picture test //Bad Picture test
//Empty Title test //Empty Title test
uploadMediaPresenter.handleImageResult(-7) uploadMediaPresenter.handleImageResult(-7, uploadItem)
verify(view).showBadImagePopup(ArgumentMatchers.anyInt()) verify(view).showBadImagePopup(ArgumentMatchers.anyInt())
} }
@ -158,8 +158,8 @@ class UploadMediaPresenterTest {
*/ */
@Test @Test
fun handleBadImageBaseTestInvalidLocation() { fun handleBadImageBaseTestInvalidLocation() {
uploadMediaPresenter.handleBadImage(8) uploadMediaPresenter.handleBadImage(8, uploadItem)
verify(repository).saveValue(ArgumentMatchers.anyString(), eq(false)) verify(uploadItem).setHasInvalidLocation(true)
verify(view).showBadImagePopup(8) verify(view).showBadImagePopup(8)
} }
@ -168,7 +168,7 @@ class UploadMediaPresenterTest {
*/ */
@Test @Test
fun handleBadImageBaseTestEmptyTitle() { fun handleBadImageBaseTestEmptyTitle() {
uploadMediaPresenter.handleBadImage(-3) uploadMediaPresenter.handleBadImage(-3, uploadItem)
verify(view).showMessage(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt()) verify(view).showMessage(ArgumentMatchers.anyInt(), ArgumentMatchers.anyInt())
} }
@ -177,7 +177,7 @@ class UploadMediaPresenterTest {
*/ */
@Test @Test
fun handleBadImageBaseTestFileNameExists() { fun handleBadImageBaseTestFileNameExists() {
uploadMediaPresenter.handleBadImage(-4) uploadMediaPresenter.handleBadImage(-4, uploadItem)
verify(view).showDuplicatePicturePopup() verify(view).showDuplicatePicturePopup()
} }

View file

@ -50,14 +50,6 @@ class WikidataEditServiceTest {
verifyZeroInteractions(wikidataClient!!) verifyZeroInteractions(wikidataClient!!)
} }
@Test
fun noClaimsWhenLocationIsNotCorrect() {
`when`(directKvStore!!.getBoolean("Picture_Has_Correct_Location", true))
.thenReturn(false)
wikidataEditService!!.createClaimWithLogging("Q1", "","Test.jpg","")
verifyZeroInteractions(wikidataClient!!)
}
@Test @Test
fun createClaimWithLogging() { fun createClaimWithLogging() {
`when`(directKvStore!!.getBoolean("Picture_Has_Correct_Location", true)) `when`(directKvStore!!.getBoolean("Picture_Has_Correct_Location", true))

View file

@ -7,7 +7,7 @@ buildscript {
maven { url "https://plugins.gradle.org/m2/" } maven { url "https://plugins.gradle.org/m2/" }
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.6.1' classpath 'com.android.tools.build:gradle:3.6.3'
classpath "com.hiya:jacoco-android:0.2" classpath "com.hiya:jacoco-android:0.2"
classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.8.2' classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.8.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$KOTLIN_VERSION" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$KOTLIN_VERSION"