Merge pull request #1584 from commons-app/wikidataEdits

Merge Wikidata edits branch to master
This commit is contained in:
Vivek Maskara 2018-06-05 01:09:55 +05:30 committed by GitHub
commit 32d45b2687
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 422 additions and 37 deletions

View file

@ -16,4 +16,4 @@ Tested on {API level & name of device/emulator}, with {build variant, e.g. ProdD
{Only for user interface changes, otherwise remove this section. See [how to take a screenshot](https://android.stackexchange.com/questions/1759/how-to-take-a-screenshot-with-an-android-device)} {Only for user interface changes, otherwise remove this section. See [how to take a screenshot](https://android.stackexchange.com/questions/1759/how-to-take-a-screenshot-with-an-android-device)}
_Note: Please ensure that you have read CONTRIBUTING.md if this is your first pull request._ _Note: Please ensure that you have read CONTRIBUTING.md if this is your first pull request._

View file

@ -135,6 +135,7 @@ android {
productFlavors { productFlavors {
prod { prod {
buildConfigField "String", "WIKIMEDIA_API_HOST", "\"https://commons.wikimedia.org/w/api.php\"" buildConfigField "String", "WIKIMEDIA_API_HOST", "\"https://commons.wikimedia.org/w/api.php\""
buildConfigField "String", "WIKIDATA_API_HOST", "\"https://www.wikidata.org/w/api.php\""
buildConfigField "String", "WIKIMEDIA_FORGE_API_HOST", "\"https://tools.wmflabs.org/\"" buildConfigField "String", "WIKIMEDIA_FORGE_API_HOST", "\"https://tools.wmflabs.org/\""
buildConfigField "String", "IMAGE_URL_BASE", "\"https://upload.wikimedia.org/wikipedia/commons\"" buildConfigField "String", "IMAGE_URL_BASE", "\"https://upload.wikimedia.org/wikipedia/commons\""
buildConfigField "String", "HOME_URL", "\"https://commons.wikimedia.org/wiki/\"" buildConfigField "String", "HOME_URL", "\"https://commons.wikimedia.org/wiki/\""
@ -151,6 +152,7 @@ android {
beta { beta {
// What values do we need to hit the BETA versions of the site / api ? // What values do we need to hit the BETA versions of the site / api ?
buildConfigField "String", "WIKIMEDIA_API_HOST", "\"https://commons.wikimedia.beta.wmflabs.org/w/api.php\"" buildConfigField "String", "WIKIMEDIA_API_HOST", "\"https://commons.wikimedia.beta.wmflabs.org/w/api.php\""
buildConfigField "String", "WIKIDATA_API_HOST", "\"https://www.wikidata.org/w/api.php\""
buildConfigField "String", "WIKIMEDIA_FORGE_API_HOST", "\"https://tools.wmflabs.org/\"" buildConfigField "String", "WIKIMEDIA_FORGE_API_HOST", "\"https://tools.wmflabs.org/\""
buildConfigField "String", "IMAGE_URL_BASE", "\"https://upload.beta.wmflabs.org/wikipedia/commons\"" buildConfigField "String", "IMAGE_URL_BASE", "\"https://upload.beta.wmflabs.org/wikipedia/commons\""
buildConfigField "String", "HOME_URL", "\"https://commons.wikimedia.beta.wmflabs.org/wiki/\"" buildConfigField "String", "HOME_URL", "\"https://commons.wikimedia.beta.wmflabs.org/wiki/\""

View file

@ -21,6 +21,7 @@ import java.io.File;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import fr.free.nrw.commons.BuildConfig;
import fr.free.nrw.commons.auth.SessionManager; import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.category.CategoryDao; import fr.free.nrw.commons.category.CategoryDao;
import fr.free.nrw.commons.contributions.ContributionDao; import fr.free.nrw.commons.contributions.ContributionDao;

View file

@ -178,6 +178,7 @@ public class Utils {
} }
public static void handleWebUrl(Context context, Uri url) { public static void handleWebUrl(Context context, Uri url) {
Timber.d("Launching web url %s", url.toString());
Intent browserIntent = new Intent(Intent.ACTION_VIEW, url); Intent browserIntent = new Intent(Intent.ACTION_VIEW, url);
if (browserIntent.resolveActivity(context.getPackageManager()) == null) { if (browserIntent.resolveActivity(context.getPackageManager()) == null) {
Toast toast = Toast.makeText(context, context.getString(R.string.no_web_browser), LENGTH_SHORT); Toast toast = Toast.makeText(context, context.getString(R.string.no_web_browser), LENGTH_SHORT);

View file

@ -228,7 +228,7 @@ public class CategoryImagesListFragment extends DaggerFragment {
/** /**
* This method will be called on back pressed of CategoryImagesActivity. * This method will be called on back pressed of CategoryImagesActivity.
* It initializes the grid view by setting adapter. * It initializes the grid view by setting adapter.
\ */ */
@Override @Override
public void onResume() { public void onResume() {
gridView.setAdapter(gridAdapter); gridView.setAdapter(gridAdapter);

View file

@ -45,6 +45,7 @@ public class Contribution extends Media {
private long transferred; private long transferred;
private String decimalCoords; private String decimalCoords;
private boolean isMultiple; private boolean isMultiple;
private String wikiDataEntityId;
public Contribution(Uri contentUri, String filename, Uri localUri, String imageUrl, Date timestamp, public Contribution(Uri contentUri, String filename, Uri localUri, String imageUrl, Date timestamp,
int state, long dataLength, Date dateUploaded, long transferred, int state, long dataLength, Date dateUploaded, long transferred,
@ -222,4 +223,17 @@ public class Contribution extends Media {
throw new RuntimeException("Unrecognized license value: " + license); throw new RuntimeException("Unrecognized license value: " + license);
} }
public String getWikiDataEntityId() {
return wikiDataEntityId;
}
/**
* When the corresponding wikidata entity is known as in case of nearby uploads, it can be set
* using the setter method
* @param wikiDataEntityId
*/
public void setWikiDataEntityId(String wikiDataEntityId) {
this.wikiDataEntityId = wikiDataEntityId;
}
} }

View file

@ -90,7 +90,7 @@ public class ContributionController {
fragment.startActivityForResult(pickImageIntent, SELECT_FROM_GALLERY); fragment.startActivityForResult(pickImageIntent, SELECT_FROM_GALLERY);
} }
public void handleImagePicked(int requestCode, Intent data, boolean isDirectUpload) { public void handleImagePicked(int requestCode, Intent data, boolean isDirectUpload, String wikiDataEntityId) {
FragmentActivity activity = fragment.getActivity(); FragmentActivity activity = fragment.getActivity();
Timber.d("handleImagePicked() called with onActivityResult()"); Timber.d("handleImagePicked() called with onActivityResult()");
Intent shareIntent = new Intent(activity, ShareActivity.class); Intent shareIntent = new Intent(activity, ShareActivity.class);
@ -102,9 +102,6 @@ public class ContributionController {
shareIntent.setType(activity.getContentResolver().getType(imageData)); shareIntent.setType(activity.getContentResolver().getType(imageData));
shareIntent.putExtra(EXTRA_STREAM, imageData); shareIntent.putExtra(EXTRA_STREAM, imageData);
shareIntent.putExtra(EXTRA_SOURCE, SOURCE_GALLERY); shareIntent.putExtra(EXTRA_SOURCE, SOURCE_GALLERY);
if (isDirectUpload) {
shareIntent.putExtra("isDirectUpload", true);
}
break; break;
case SELECT_FROM_CAMERA: case SELECT_FROM_CAMERA:
//FIXME: Find out appropriate mime type //FIXME: Find out appropriate mime type
@ -113,9 +110,6 @@ public class ContributionController {
shareIntent.setType("image/jpeg"); shareIntent.setType("image/jpeg");
shareIntent.putExtra(EXTRA_STREAM, lastGeneratedCaptureUri); shareIntent.putExtra(EXTRA_STREAM, lastGeneratedCaptureUri);
shareIntent.putExtra(EXTRA_SOURCE, SOURCE_CAMERA); shareIntent.putExtra(EXTRA_SOURCE, SOURCE_CAMERA);
if (isDirectUpload) {
shareIntent.putExtra("isDirectUpload", true);
}
break; break;
default: default:
@ -123,6 +117,10 @@ public class ContributionController {
} }
Timber.i("Image selected"); Timber.i("Image selected");
try { try {
shareIntent.putExtra("isDirectUpload", isDirectUpload);
if (wikiDataEntityId != null && !wikiDataEntityId.equals("")) {
shareIntent.putExtra("wikiDataEntityId", wikiDataEntityId);
}
activity.startActivity(shareIntent); activity.startActivity(shareIntent);
} catch (SecurityException e) { } catch (SecurityException e) {
Timber.e(e, "Security Exception"); Timber.e(e, "Security Exception");

View file

@ -117,7 +117,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment {
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
Timber.d("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s", Timber.d("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
requestCode, resultCode, data); requestCode, resultCode, data);
controller.handleImagePicked(requestCode, data, false); controller.handleImagePicked(requestCode, data, false, null);
} else { } else {
Timber.e("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s", Timber.e("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
requestCode, resultCode, data); requestCode, resultCode, data);

View file

@ -6,18 +6,25 @@ import android.content.SharedPreferences;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.v4.util.LruCache; import android.support.v4.util.LruCache;
import com.google.gson.Gson;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Singleton; import javax.inject.Singleton;
import dagger.Module; import dagger.Module;
import dagger.Provides; import dagger.Provides;
import fr.free.nrw.commons.BuildConfig;
import fr.free.nrw.commons.auth.AccountUtil; import fr.free.nrw.commons.auth.AccountUtil;
import fr.free.nrw.commons.auth.SessionManager; import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.data.DBOpenHelper; import fr.free.nrw.commons.data.DBOpenHelper;
import fr.free.nrw.commons.location.LocationServiceManager; import fr.free.nrw.commons.location.LocationServiceManager;
import fr.free.nrw.commons.mwapi.ApacheHttpClientMediaWikiApi;
import fr.free.nrw.commons.mwapi.MediaWikiApi; import fr.free.nrw.commons.mwapi.MediaWikiApi;
import fr.free.nrw.commons.nearby.NearbyPlaces; import fr.free.nrw.commons.nearby.NearbyPlaces;
import fr.free.nrw.commons.upload.UploadController; import fr.free.nrw.commons.upload.UploadController;
import fr.free.nrw.commons.wikidata.WikidataEditListener;
import fr.free.nrw.commons.wikidata.WikidataEditListenerImpl;
import static android.content.Context.MODE_PRIVATE; import static android.content.Context.MODE_PRIVATE;
import static fr.free.nrw.commons.contributions.ContributionsContentProvider.CONTRIBUTION_AUTHORITY; import static fr.free.nrw.commons.contributions.ContributionsContentProvider.CONTRIBUTION_AUTHORITY;
@ -133,4 +140,10 @@ public class CommonsApplicationModule {
public LruCache<String, String> provideLruCache() { public LruCache<String, String> provideLruCache() {
return new LruCache<>(1024); return new LruCache<>(1024);
} }
@Provides
@Singleton
public WikidataEditListener provideWikidataEditListener() {
return new WikidataEditListenerImpl();
}
} }

View file

@ -35,7 +35,7 @@ public class NetworkingModule {
@Named("default_preferences") SharedPreferences defaultPreferences, @Named("default_preferences") SharedPreferences defaultPreferences,
@Named("category_prefs") SharedPreferences categoryPrefs, @Named("category_prefs") SharedPreferences categoryPrefs,
Gson gson) { Gson gson) {
return new ApacheHttpClientMediaWikiApi(context, BuildConfig.WIKIMEDIA_API_HOST, defaultPreferences, categoryPrefs, gson); return new ApacheHttpClientMediaWikiApi(context, BuildConfig.WIKIMEDIA_API_HOST, BuildConfig.WIKIDATA_API_HOST, defaultPreferences, categoryPrefs, gson);
} }
@Provides @Provides

View file

@ -284,6 +284,7 @@ public class LocationServiceManager implements LocationListener {
LOCATION_SIGNIFICANTLY_CHANGED, //Went out of borders of nearby markers LOCATION_SIGNIFICANTLY_CHANGED, //Went out of borders of nearby markers
LOCATION_SLIGHTLY_CHANGED, //User might be walking or driving LOCATION_SLIGHTLY_CHANGED, //User might be walking or driving
LOCATION_NOT_CHANGED, LOCATION_NOT_CHANGED,
PERMISSION_JUST_GRANTED PERMISSION_JUST_GRANTED,
MAP_UPDATED
} }
} }

View file

@ -23,6 +23,9 @@ import android.widget.ScrollView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import java.io.IOException; import java.io.IOException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;

View file

@ -25,6 +25,8 @@ import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
import org.mediawiki.api.ApiResult; import org.mediawiki.api.ApiResult;
import org.mediawiki.api.MWApi; import org.mediawiki.api.MWApi;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import java.io.IOException; import java.io.IOException;
@ -62,6 +64,7 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
private static final String THUMB_SIZE = "640"; private static final String THUMB_SIZE = "640";
private AbstractHttpClient httpClient; private AbstractHttpClient httpClient;
private MWApi api; private MWApi api;
private MWApi wikidataApi;
private Context context; private Context context;
private SharedPreferences defaultPreferences; private SharedPreferences defaultPreferences;
private SharedPreferences categoryPreferences; private SharedPreferences categoryPreferences;
@ -69,6 +72,7 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
public ApacheHttpClientMediaWikiApi(Context context, public ApacheHttpClientMediaWikiApi(Context context,
String apiURL, String apiURL,
String wikidatApiURL,
SharedPreferences defaultPreferences, SharedPreferences defaultPreferences,
SharedPreferences categoryPreferences, SharedPreferences categoryPreferences,
Gson gson) { Gson gson) {
@ -82,6 +86,7 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
params.setParameter(CoreProtocolPNames.USER_AGENT, getUserAgent()); params.setParameter(CoreProtocolPNames.USER_AGENT, getUserAgent());
httpClient = new DefaultHttpClient(cm, params); httpClient = new DefaultHttpClient(cm, params);
api = new MWApi(apiURL, httpClient); api = new MWApi(apiURL, httpClient);
wikidataApi = new MWApi(wikidatApiURL, httpClient);
this.defaultPreferences = defaultPreferences; this.defaultPreferences = defaultPreferences;
this.categoryPreferences = categoryPreferences; this.categoryPreferences = categoryPreferences;
this.gson = gson; this.gson = gson;
@ -206,6 +211,15 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
return api.getEditToken(); return api.getEditToken();
} }
@Override
public String getCentralAuthToken() throws IOException {
String centralAuthToken = api.action("centralauthtoken")
.get()
.getString("/api/centralauthtoken/@centralauthtoken");
Timber.d("MediaWiki Central auth token is %s", centralAuthToken);
return centralAuthToken;
}
@Override @Override
public boolean fileExistsWithName(String fileName) throws IOException { public boolean fileExistsWithName(String fileName) throws IOException {
return api.action("query") return api.action("query")
@ -351,6 +365,98 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
}).flatMapObservable(Observable::fromIterable); }).flatMapObservable(Observable::fromIterable);
} }
/**
* Get the edit token for making wiki data edits
* https://www.mediawiki.org/wiki/API:Tokens
* @return
* @throws IOException
*/
private String getWikidataEditToken() throws IOException {
return wikidataApi.getEditToken();
}
@Override
public String getWikidataCsrfToken() throws IOException {
String wikidataCsrfToken = wikidataApi.action("query")
.param("action", "query")
.param("centralauthtoken", getCentralAuthToken())
.param("meta", "tokens")
.post()
.getString("/api/query/tokens/@csrftoken");
Timber.d("Wikidata csrf token is %s", wikidataCsrfToken);
return wikidataCsrfToken;
}
/**
* Creates a new claim using the wikidata API
* https://www.mediawiki.org/wiki/Wikibase/API
* @param entityId the wikidata entity to be edited
* @param property the property to be edited, for eg P18 for images
* @param snaktype the type of value stored for that property
* @param value the actual value to be stored for the property, for eg filename in case of P18
* @return returns revisionId if the claim is successfully created else returns null
* @throws IOException
*/
@Nullable
@Override
public String wikidatCreateClaim(String entityId, String property, String snaktype, String value) throws IOException {
Timber.d("Filename is %s", value);
ApiResult result = wikidataApi.action("wbcreateclaim")
.param("entity", entityId)
.param("centralauthtoken", getCentralAuthToken())
.param("token", getWikidataCsrfToken())
.param("snaktype", snaktype)
.param("property", property)
.param("value", value)
.post();
if (result == null || result.getNode("api") == null) {
return null;
}
Node node = result.getNode("api").getDocument();
Element element = (Element) node;
if (element != null && element.getAttribute("success").equals("1")) {
return result.getString("api/pageinfo/@lastrevid");
} else {
Timber.e(result.getString("api/error/@code") + " " + result.getString("api/error/@info"));
}
return null;
}
/**
* Adds the wikimedia-commons-app tag to the edits made on wikidata
* @param revisionId
* @return
* @throws IOException
*/
@Nullable
@Override
public boolean addWikidataEditTag(String revisionId) throws IOException {
ApiResult result = wikidataApi.action("tag")
.param("revid", revisionId)
.param("centralauthtoken", getCentralAuthToken())
.param("token", getWikidataCsrfToken())
.param("add", "wikimedia-commons-app")
.param("reason", "Add tag for edits made using Android Commons app")
.post();
if (result == null || result.getNode("api") == null) {
return false;
}
Node node = result.getNode("api").getDocument();
Element element = (Element) node;
if (element != null && element.getAttribute("status").equals("success")) {
return true;
} else {
Timber.e(result.getString("api/error/@code") + " " + result.getString("api/error/@info"));
}
return false;
}
@Override @Override
@NonNull @NonNull
public Observable<String> searchTitles(String title, int searchCatsLimit) { public Observable<String> searchTitles(String title, int searchCatsLimit) {
@ -586,6 +692,7 @@ public class ApacheHttpClientMediaWikiApi implements MediaWikiApi {
String resultStatus = result.getString("/api/upload/@result"); String resultStatus = result.getString("/api/upload/@result");
if (!resultStatus.equals("Success")) { if (!resultStatus.equals("Success")) {
String errorCode = result.getString("/api/error/@code"); String errorCode = result.getString("/api/error/@code");
Timber.e(errorCode);
return new UploadResult(resultStatus, errorCode); return new UploadResult(resultStatus, errorCode);
} else { } else {
Date dateUploaded = parseMWDate(result.getString("/api/upload/imageinfo/@timestamp")); Date dateUploaded = parseMWDate(result.getString("/api/upload/imageinfo/@timestamp"));

View file

@ -27,6 +27,10 @@ public interface MediaWikiApi {
String getEditToken() throws IOException; String getEditToken() throws IOException;
String getWikidataCsrfToken() throws IOException;
String getCentralAuthToken() throws IOException;
boolean fileExistsWithName(String fileName) throws IOException; boolean fileExistsWithName(String fileName) throws IOException;
boolean pageExists(String pageName) throws IOException; boolean pageExists(String pageName) throws IOException;
@ -49,6 +53,12 @@ public interface MediaWikiApi {
@Nullable @Nullable
String appendEdit(String editToken, String processedPageContent, String filename, String summary) throws IOException; String appendEdit(String editToken, String processedPageContent, String filename, String summary) throws IOException;
@Nullable
String wikidatCreateClaim(String entityId, String property, String snaktype, String value) throws IOException;
@Nullable
boolean addWikidataEditTag(String revisionId) throws IOException;
@NonNull @NonNull
MediaResult fetchMediaByFilename(String filename) throws IOException; MediaResult fetchMediaByFilename(String filename) throws IOException;

View file

@ -42,11 +42,13 @@ import butterknife.ButterKnife;
import fr.free.nrw.commons.R; import fr.free.nrw.commons.R;
import fr.free.nrw.commons.location.LatLng; import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.location.LocationServiceManager; import fr.free.nrw.commons.location.LocationServiceManager;
import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType;
import fr.free.nrw.commons.location.LocationUpdateListener; import fr.free.nrw.commons.location.LocationUpdateListener;
import fr.free.nrw.commons.theme.NavigationBaseActivity; import fr.free.nrw.commons.theme.NavigationBaseActivity;
import fr.free.nrw.commons.utils.NetworkUtils; import fr.free.nrw.commons.utils.NetworkUtils;
import fr.free.nrw.commons.utils.UriSerializer; import fr.free.nrw.commons.utils.UriSerializer;
import fr.free.nrw.commons.utils.ViewUtil; import fr.free.nrw.commons.utils.ViewUtil;
import fr.free.nrw.commons.wikidata.WikidataEditListener;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable; import io.reactivex.disposables.Disposable;
@ -55,8 +57,12 @@ import timber.log.Timber;
import uk.co.deanwild.materialshowcaseview.IShowcaseListener; import uk.co.deanwild.materialshowcaseview.IShowcaseListener;
import uk.co.deanwild.materialshowcaseview.MaterialShowcaseView; import uk.co.deanwild.materialshowcaseview.MaterialShowcaseView;
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.*;
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.MAP_UPDATED;
public class NearbyActivity extends NavigationBaseActivity implements LocationUpdateListener {
public class NearbyActivity extends NavigationBaseActivity implements LocationUpdateListener,
WikidataEditListener.WikidataP18EditListener {
private static final int LOCATION_REQUEST = 1; private static final int LOCATION_REQUEST = 1;
@ -76,6 +82,8 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
LocationServiceManager locationManager; LocationServiceManager locationManager;
@Inject @Inject
NearbyController nearbyController; NearbyController nearbyController;
@Inject WikidataEditListener wikidataEditListener;
@Inject @Inject
@Named("application_preferences") SharedPreferences applicationPrefs; @Named("application_preferences") SharedPreferences applicationPrefs;
private LatLng curLatLng; private LatLng curLatLng;
@ -110,6 +118,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
initBottomSheetBehaviour(); initBottomSheetBehaviour();
initDrawer(); initDrawer();
wikidataEditListener.setAuthenticationStateListener(this);
} }
private void resumeFragment() { private void resumeFragment() {
@ -219,7 +228,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
//Still need to check if GPS is enabled //Still need to check if GPS is enabled
checkGps(); checkGps();
lastKnownLocation = locationManager.getLKL(); lastKnownLocation = locationManager.getLKL();
refreshView(LocationServiceManager.LocationChangeType.PERMISSION_JUST_GRANTED); refreshView(PERMISSION_JUST_GRANTED);
} else { } else {
//If permission not granted, go to page that says Nearby Places cannot be displayed //If permission not granted, go to page that says Nearby Places cannot be displayed
hideProgressBar(); hideProgressBar();
@ -279,7 +288,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
private void checkLocationPermission() { private void checkLocationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (locationManager.isLocationPermissionGranted()) { if (locationManager.isLocationPermissionGranted()) {
refreshView(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED); refreshView(LOCATION_SIGNIFICANTLY_CHANGED);
} else { } else {
// Should we show an explanation? // Should we show an explanation?
if (locationManager.isPermissionExplanationRequired(this)) { if (locationManager.isPermissionExplanationRequired(this)) {
@ -305,7 +314,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
} }
} }
} else { } else {
refreshView(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED); refreshView(LOCATION_SIGNIFICANTLY_CHANGED);
} }
} }
@ -314,7 +323,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1) { if (requestCode == 1) {
Timber.d("User is back from Settings page"); Timber.d("User is back from Settings page");
refreshView(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED); refreshView(LOCATION_SIGNIFICANTLY_CHANGED);
} }
} }
@ -373,8 +382,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
if (NetworkUtils.isInternetConnectionEstablished(NearbyActivity.this)) { if (NetworkUtils.isInternetConnectionEstablished(NearbyActivity.this)) {
refreshView(LocationServiceManager refreshView(LOCATION_SIGNIFICANTLY_CHANGED);
.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED);
} else { } else {
ViewUtil.showLongToast(NearbyActivity.this, getString(R.string.no_internet)); ViewUtil.showLongToast(NearbyActivity.this, getString(R.string.no_internet));
} }
@ -390,7 +398,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
* *
* @param locationChangeType defines if location shanged significantly or slightly * @param locationChangeType defines if location shanged significantly or slightly
*/ */
private void refreshView(LocationServiceManager.LocationChangeType locationChangeType) { private void refreshView(LocationChangeType locationChangeType) {
if (lockNearbyView) { if (lockNearbyView) {
return; return;
} }
@ -403,12 +411,13 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
registerLocationUpdates(); registerLocationUpdates();
LatLng lastLocation = locationManager.getLastLocation(); LatLng lastLocation = locationManager.getLastLocation();
if (curLatLng != null && curLatLng.equals(lastLocation)) { //refresh view only if location has changed if (curLatLng != null && curLatLng.equals(lastLocation)
&& !locationChangeType.equals(MAP_UPDATED)) { //refresh view only if location has changed
return; return;
} }
curLatLng = lastLocation; curLatLng = lastLocation;
if (locationChangeType.equals(LocationServiceManager.LocationChangeType.PERMISSION_JUST_GRANTED)) { if (locationChangeType.equals(PERMISSION_JUST_GRANTED)) {
curLatLng = lastKnownLocation; curLatLng = lastKnownLocation;
} }
@ -417,8 +426,9 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
return; return;
} }
if (locationChangeType.equals(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED) if (locationChangeType.equals(LOCATION_SIGNIFICANTLY_CHANGED)
|| locationChangeType.equals(LocationServiceManager.LocationChangeType.PERMISSION_JUST_GRANTED)) { || locationChangeType.equals(PERMISSION_JUST_GRANTED)
|| locationChangeType.equals(MAP_UPDATED)) {
progressBar.setVisibility(View.VISIBLE); progressBar.setVisibility(View.VISIBLE);
//TODO: This hack inserts curLatLng before populatePlaces is called (see #1440). Ideally a proper fix should be found //TODO: This hack inserts curLatLng before populatePlaces is called (see #1440). Ideally a proper fix should be found
@ -440,7 +450,7 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
progressBar.setVisibility(View.GONE); progressBar.setVisibility(View.GONE);
}); });
} else if (locationChangeType } else if (locationChangeType
.equals(LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED)) { .equals(LOCATION_SLIGHTLY_CHANGED)) {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.registerTypeAdapter(Uri.class, new UriSerializer()) .registerTypeAdapter(Uri.class, new UriSerializer())
.create(); .create();
@ -685,12 +695,12 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
@Override @Override
public void onLocationChangedSignificantly(LatLng latLng) { public void onLocationChangedSignificantly(LatLng latLng) {
refreshView(LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED); refreshView(LOCATION_SIGNIFICANTLY_CHANGED);
} }
@Override @Override
public void onLocationChangedSlightly(LatLng latLng) { public void onLocationChangedSlightly(LatLng latLng) {
refreshView(LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED); refreshView(LOCATION_SLIGHTLY_CHANGED);
} }
public void prepareViewsForSheetPosition(int bottomSheetState) { public void prepareViewsForSheetPosition(int bottomSheetState) {
@ -700,4 +710,9 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
private void showErrorMessage(String message) { private void showErrorMessage(String message) {
ViewUtil.showLongToast(NearbyActivity.this, message); ViewUtil.showLongToast(NearbyActivity.this, message);
} }
@Override
public void onWikidataEditSuccessful() {
refreshView(MAP_UPDATED);
}
} }

View file

@ -2,6 +2,7 @@ package fr.free.nrw.commons.nearby;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
@ -21,6 +22,9 @@ import java.lang.reflect.Type;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
import dagger.android.support.AndroidSupportInjection; import dagger.android.support.AndroidSupportInjection;
import dagger.android.support.DaggerFragment; import dagger.android.support.DaggerFragment;
import fr.free.nrw.commons.R; import fr.free.nrw.commons.R;
@ -47,6 +51,11 @@ public class NearbyListFragment extends DaggerFragment {
private RecyclerView recyclerView; private RecyclerView recyclerView;
private ContributionController controller; private ContributionController controller;
@Inject
@Named("direct_nearby_upload_prefs")
SharedPreferences directPrefs;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -137,7 +146,7 @@ public class NearbyListFragment extends DaggerFragment {
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
Timber.d("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s", Timber.d("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
requestCode, resultCode, data); requestCode, resultCode, data);
controller.handleImagePicked(requestCode, data, true); controller.handleImagePicked(requestCode, data, true, directPrefs.getString("WikiDataEntityId", null));
} else { } else {
Timber.e("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s", Timber.e("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
requestCode, resultCode, data); requestCode, resultCode, data);

View file

@ -731,6 +731,7 @@ public class NearbyMapFragment extends DaggerFragment {
editor.putString("Title", place.getName()); editor.putString("Title", place.getName());
editor.putString("Desc", place.getLongDescription()); editor.putString("Desc", place.getLongDescription());
editor.putString("Category", place.getCategory()); editor.putString("Category", place.getCategory());
editor.putString("WikiDataEntityId", place.getWikiDataEntityId());
editor.apply(); editor.apply();
} }
@ -766,7 +767,7 @@ public class NearbyMapFragment extends DaggerFragment {
if (resultCode == RESULT_OK) { if (resultCode == RESULT_OK) {
Timber.d("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s", Timber.d("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
requestCode, resultCode, data); requestCode, resultCode, data);
controller.handleImagePicked(requestCode, data, true); controller.handleImagePicked(requestCode, data, true, directPrefs.getString("WikiDataEntityId", null));
} else { } else {
Timber.e("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s", Timber.e("OnActivityResult() parameters: Req code: %d Result code: %d Data: %s",
requestCode, resultCode, data); requestCode, resultCode, data);

View file

@ -3,6 +3,7 @@ package fr.free.nrw.commons.nearby;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.net.Uri; import android.net.Uri;
import android.support.annotation.DrawableRes; import android.support.annotation.DrawableRes;
import android.support.annotation.Nullable;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -50,6 +51,20 @@ public class Place {
this.distance = distance; this.distance = distance;
} }
/**
* Extracts the entity id from the wikidata link
* @return returns the entity id if wikidata link exists
*/
@Nullable
public String getWikiDataEntityId() {
if (!hasWikidataLink()) {
return null;
}
String wikiDataLink = siteLinks.getWikidataLink().toString();
return wikiDataLink.replace("http://www.wikidata.org/entity/", "");
}
public boolean hasWikipediaLink() { public boolean hasWikipediaLink() {
return !(siteLinks == null || Uri.EMPTY.equals(siteLinks.getWikipediaLink())); return !(siteLinks == null || Uri.EMPTY.equals(siteLinks.getWikipediaLink()));
} }

View file

@ -16,7 +16,6 @@ import android.widget.RelativeLayout;
import com.pedrogomez.renderers.RVRendererAdapter; import com.pedrogomez.renderers.RVRendererAdapter;
import java.lang.ref.WeakReference;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -26,6 +25,7 @@ import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import fr.free.nrw.commons.R; import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils; import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.mwapi.MediaWikiApi;
import fr.free.nrw.commons.theme.NavigationBaseActivity; import fr.free.nrw.commons.theme.NavigationBaseActivity;
import fr.free.nrw.commons.utils.NetworkUtils; import fr.free.nrw.commons.utils.NetworkUtils;
import fr.free.nrw.commons.utils.ViewUtil; import fr.free.nrw.commons.utils.ViewUtil;
@ -46,6 +46,8 @@ public class NotificationActivity extends NavigationBaseActivity {
@BindView(R.id.container) RelativeLayout relativeLayout; @BindView(R.id.container) RelativeLayout relativeLayout;
@Inject NotificationController controller; @Inject NotificationController controller;
@Inject
MediaWikiApi mediaWikiApi;
private static final String TAG_NOTIFICATION_WORKER_FRAGMENT = "NotificationWorkerFragment"; private static final String TAG_NOTIFICATION_WORKER_FRAGMENT = "NotificationWorkerFragment";
private NotificationWorkerFragment mNotificationWorkerFragment; private NotificationWorkerFragment mNotificationWorkerFragment;
@ -81,7 +83,6 @@ public class NotificationActivity extends NavigationBaseActivity {
} }
} }
@SuppressLint("CheckResult") @SuppressLint("CheckResult")
private void addNotifications() { private void addNotifications() {
Timber.d("Add notifications"); Timber.d("Add notifications");

View file

@ -81,6 +81,7 @@ import io.reactivex.schedulers.Schedulers;
import fr.free.nrw.commons.utils.ViewUtil; import fr.free.nrw.commons.utils.ViewUtil;
import timber.log.Timber; import timber.log.Timber;
import android.support.design.widget.FloatingActionButton;
import static fr.free.nrw.commons.upload.ExistingFileAsync.Result.DUPLICATE_PROCEED; import static fr.free.nrw.commons.upload.ExistingFileAsync.Result.DUPLICATE_PROCEED;
import static fr.free.nrw.commons.upload.ExistingFileAsync.Result.NO_DUPLICATE; import static fr.free.nrw.commons.upload.ExistingFileAsync.Result.NO_DUPLICATE;
@ -138,6 +139,8 @@ public class ShareActivity
private Uri mediaUri; private Uri mediaUri;
private Contribution contribution; private Contribution contribution;
private FloatingActionButton maps_fragment;
private boolean cacheFound; private boolean cacheFound;
private GPSExtractor imageObj; private GPSExtractor imageObj;
@ -150,6 +153,7 @@ public class ShareActivity
private String title; private String title;
private String description; private String description;
private String wikiDataEntityId;
private Snackbar snackbar; private Snackbar snackbar;
private boolean duplicateCheckPassed = false; private boolean duplicateCheckPassed = false;
@ -160,7 +164,7 @@ public class ShareActivity
private long ShortAnimationDuration; private long ShortAnimationDuration;
private boolean isFABOpen = false; private boolean isFABOpen = false;
//Had to make them class variables, to extract out the click listeners, also I see no harm in this //Had to make them class variables, to extract out the click listeners, also I see no harm in this
final Rect startBounds = new Rect(); final Rect startBounds = new Rect();
final Rect finalBounds = new Rect(); final Rect finalBounds = new Rect();
final Point globalOffset = new Point(); final Point globalOffset = new Point();
@ -212,7 +216,7 @@ public class ShareActivity
Timber.d("Cache the categories found"); Timber.d("Cache the categories found");
} }
uploadController.startUpload(title, mediaUri, description, mimeType, source, decimalCoords, c -> { uploadController.startUpload(title, mediaUri, description, mimeType, source, decimalCoords, wikiDataEntityId, c -> {
ShareActivity.this.contribution = c; ShareActivity.this.contribution = c;
showPostUpload(); showPostUpload();
}); });
@ -295,7 +299,10 @@ public class ShareActivity
} }
if (intent.hasExtra("isDirectUpload")) { if (intent.hasExtra("isDirectUpload")) {
Timber.d("This was initiated by a direct upload from Nearby"); Timber.d("This was initiated by a direct upload from Nearby");
isNearbyUpload = true; isNearbyUpload = intent.getBooleanExtra("isDirectUpload", false);
}
if (intent.hasExtra("wikiDataEntityId")) {
wikiDataEntityId = intent.getStringExtra("wikiDataEntityId");
} }
mimeType = intent.getType(); mimeType = intent.getType();
} }

View file

@ -91,7 +91,7 @@ public class UploadController {
* @param decimalCoords the coordinates in decimal. (e.g. "37.51136|-77.602615") * @param decimalCoords the coordinates in decimal. (e.g. "37.51136|-77.602615")
* @param onComplete the progress tracker * @param onComplete the progress tracker
*/ */
public void startUpload(String title, Uri mediaUri, String description, String mimeType, String source, String decimalCoords, ContributionUploadProgress onComplete) { public void startUpload(String title, Uri mediaUri, String description, String mimeType, String source, String decimalCoords, String wikiDataEntityId, ContributionUploadProgress onComplete) {
Contribution contribution; Contribution contribution;
//TODO: Modify this to include coords //TODO: Modify this to include coords
@ -101,6 +101,7 @@ public class UploadController {
contribution.setTag("mimeType", mimeType); contribution.setTag("mimeType", mimeType);
contribution.setSource(source); contribution.setSource(source);
contribution.setWikiDataEntityId(wikiDataEntityId);
//Calls the next overloaded method //Calls the next overloaded method
startUpload(contribution, onComplete); startUpload(contribution, onComplete);

View file

@ -18,6 +18,7 @@ import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.HashSet; import java.util.HashSet;
import java.util.Locale;
import java.util.Set; import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -36,6 +37,12 @@ import fr.free.nrw.commons.contributions.ContributionsContentProvider;
import fr.free.nrw.commons.modifications.ModificationsContentProvider; import fr.free.nrw.commons.modifications.ModificationsContentProvider;
import fr.free.nrw.commons.mwapi.MediaWikiApi; import fr.free.nrw.commons.mwapi.MediaWikiApi;
import fr.free.nrw.commons.mwapi.UploadResult; import fr.free.nrw.commons.mwapi.UploadResult;
import fr.free.nrw.commons.utils.ViewUtil;
import fr.free.nrw.commons.wikidata.WikidataEditListener;
import fr.free.nrw.commons.wikidata.WikidataEditService;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import timber.log.Timber; import timber.log.Timber;
public class UploadService extends HandlerService<Contribution> { public class UploadService extends HandlerService<Contribution> {
@ -49,8 +56,8 @@ public class UploadService extends HandlerService<Contribution> {
public static final String EXTRA_CAMPAIGN = EXTRA_PREFIX + ".campaign"; public static final String EXTRA_CAMPAIGN = EXTRA_PREFIX + ".campaign";
@Inject MediaWikiApi mwApi; @Inject MediaWikiApi mwApi;
@Inject WikidataEditService wikidataEditService;
@Inject SessionManager sessionManager; @Inject SessionManager sessionManager;
@Inject @Named("default_preferences") SharedPreferences prefs;
@Inject ContributionDao contributionDao; @Inject ContributionDao contributionDao;
private NotificationManager notificationManager; private NotificationManager notificationManager;
@ -137,6 +144,7 @@ public class UploadService extends HandlerService<Contribution> {
@Override @Override
public void queue(int what, Contribution contribution) { public void queue(int what, Contribution contribution) {
Timber.d("Upload service queue has contribution with wiki data entity id as %s", contribution.getWikiDataEntityId());
switch (what) { switch (what) {
case ACTION_UPLOAD_FILE: case ACTION_UPLOAD_FILE:
@ -253,6 +261,7 @@ public class UploadService extends HandlerService<Contribution> {
if (!resultStatus.equals("Success")) { if (!resultStatus.equals("Success")) {
showFailedNotification(contribution); showFailedNotification(contribution);
} else { } else {
wikidataEditService.createClaimWithLogging(contribution.getWikiDataEntityId(), filename);
contribution.setFilename(uploadResult.getCanonicalFilename()); contribution.setFilename(uploadResult.getCanonicalFilename());
contribution.setImageUrl(uploadResult.getImageUrl()); contribution.setImageUrl(uploadResult.getImageUrl());
contribution.setState(Contribution.STATE_COMPLETED); contribution.setState(Contribution.STATE_COMPLETED);

View file

@ -0,0 +1,16 @@
package fr.free.nrw.commons.wikidata;
public abstract class WikidataEditListener {
protected WikidataP18EditListener wikidataP18EditListener;
public abstract void onSuccessfulWikidataEdit();
public void setAuthenticationStateListener(WikidataP18EditListener wikidataP18EditListener) {
this.wikidataP18EditListener = wikidataP18EditListener;
}
public interface WikidataP18EditListener {
void onWikidataEditSuccessful();
}
}

View file

@ -0,0 +1,20 @@
package fr.free.nrw.commons.wikidata;
/**
* Listener for wikidata edits
*/
public class WikidataEditListenerImpl extends WikidataEditListener {
public WikidataEditListenerImpl() {
}
/**
* Fired when wikidata P18 edit is successful. If there's an active listener, then it is fired
*/
@Override
public void onSuccessfulWikidataEdit() {
if (wikidataP18EditListener != null) {
wikidataP18EditListener.onWikidataEditSuccessful();
}
}
}

View file

@ -0,0 +1,134 @@
package fr.free.nrw.commons.wikidata;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import java.util.Locale;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.mwapi.MediaWikiApi;
import fr.free.nrw.commons.utils.ViewUtil;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import timber.log.Timber;
/**
* This class is meant to handle the Wikidata edits made through the app
* It will talk with MediaWikiApi to make necessary API calls, log the edits and fire listeners
* on successful edits
*/
@Singleton
public class WikidataEditService {
private final Context context;
private final MediaWikiApi mediaWikiApi;
private final WikidataEditListener wikidataEditListener;
private final SharedPreferences directPrefs;
@Inject
public WikidataEditService(Context context,
MediaWikiApi mediaWikiApi,
WikidataEditListener wikidataEditListener,
@Named("direct_nearby_upload_prefs") SharedPreferences directPrefs) {
this.context = context;
this.mediaWikiApi = mediaWikiApi;
this.wikidataEditListener = wikidataEditListener;
this.directPrefs = directPrefs;
}
/**
* Create a P18 claim and log the edit with custom tag
* @param wikidataEntityId
* @param fileName
*/
public void createClaimWithLogging(String wikidataEntityId, String fileName) {
if(wikidataEntityId == null
|| fileName == null) {
return;
}
editWikidataProperty(wikidataEntityId, fileName);
}
/**
* Edits the wikidata entity by adding the P18 property to it.
* Adding the P18 edit requires calling the wikidata API to create a claim against the entity
*
* @param wikidataEntityId
* @param fileName
*/
@SuppressLint("CheckResult")
private void editWikidataProperty(String wikidataEntityId, String fileName) {
Timber.d("Upload successful with wiki data entity id as %s", wikidataEntityId);
Timber.d("Attempting to edit Wikidata property %s", wikidataEntityId);
Observable.fromCallable(() -> {
String propertyValue = getFileName(fileName);
return mediaWikiApi.wikidatCreateClaim(wikidataEntityId, "P18", "value", propertyValue);
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(revisionId -> handleClaimResult(wikidataEntityId, revisionId), throwable -> {
Timber.e(throwable, "Error occurred while making claim");
ViewUtil.showLongToast(context, context.getString(R.string.wikidata_edit_failure));
});
}
private void handleClaimResult(String wikidataEntityId, String revisionId) {
if (revisionId != null) {
wikidataEditListener.onSuccessfulWikidataEdit();
showSuccessToast();
logEdit(revisionId);
} else {
Timber.d("Unable to make wiki data edit for entity %s", wikidataEntityId);
ViewUtil.showLongToast(context, context.getString(R.string.wikidata_edit_failure));
}
}
/**
* Log the Wikidata edit by adding Wikimedia Commons App tag to the edit
* @param revisionId
*/
@SuppressLint("CheckResult")
private void logEdit(String revisionId) {
Observable.fromCallable(() -> mediaWikiApi.addWikidataEditTag(revisionId))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(result -> {
if (result) {
Timber.d("Wikidata edit was tagged successfully");
} else {
Timber.d("Wikidata edit couldn't be tagged");
}
}, throwable -> {
Timber.e(throwable, "Error occurred while adding tag to the edit");
});
}
/**
* Show a success toast when the edit is made successfully
*/
private void showSuccessToast() {
String title = directPrefs.getString("Title", "");
String successStringTemplate = context.getString(R.string.successful_wikidata_edit);
String successMessage = String.format(Locale.getDefault(), successStringTemplate, title);
ViewUtil.showLongToast(context, successMessage);
}
/**
* Formats and returns the filename as accepted by the wiki base API
* https://www.mediawiki.org/wiki/Wikibase/API#wbcreateclaim
*
* @param fileName
* @return
*/
private String getFileName(String fileName) {
fileName = String.format("\"%s\"", fileName.replace("File:", ""));
Timber.d("Wikidata property name is %s", fileName);
return fileName;
}
}

View file

@ -283,6 +283,8 @@
<string name="share_coordinates_not_present">Coordinates were not specified during image selection</string> <string name="share_coordinates_not_present">Coordinates were not specified during image selection</string>
<string name="error_fetching_nearby_places">Error fetching nearby places.</string> <string name="error_fetching_nearby_places">Error fetching nearby places.</string>
<string name="successful_wikidata_edit">Image successfully added to %1$s on Wikidata!</string>
<string name="wikidata_edit_failure">Failed to update corresponding wiki data entity!</string>
<string name="menu_set_wallpaper">Set wallpaper</string> <string name="menu_set_wallpaper">Set wallpaper</string>
<string name="wallpaper_set_successfully">Wallpaper set successfully!</string> <string name="wallpaper_set_successfully">Wallpaper set successfully!</string>
</resources> </resources>

View file

@ -4,6 +4,7 @@ import android.content.ContentProviderClient
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.support.v4.util.LruCache import android.support.v4.util.LruCache
import com.google.gson.Gson
import com.nhaarman.mockito_kotlin.mock import com.nhaarman.mockito_kotlin.mock
import com.squareup.leakcanary.RefWatcher import com.squareup.leakcanary.RefWatcher
import fr.free.nrw.commons.auth.AccountUtil import fr.free.nrw.commons.auth.AccountUtil
@ -37,6 +38,7 @@ class MockCommonsApplicationModule(appContext: Context) : CommonsApplicationModu
val accountUtil: AccountUtil = mock() val accountUtil: AccountUtil = mock()
val appSharedPreferences: SharedPreferences = mock() val appSharedPreferences: SharedPreferences = mock()
val defaultSharedPreferences: SharedPreferences = mock() val defaultSharedPreferences: SharedPreferences = mock()
val categorySharedPreferences: SharedPreferences = mock()
val otherSharedPreferences: SharedPreferences = mock() val otherSharedPreferences: SharedPreferences = mock()
val uploadController: UploadController = mock() val uploadController: UploadController = mock()
val mockSessionManager: SessionManager = mock() val mockSessionManager: SessionManager = mock()
@ -44,6 +46,7 @@ class MockCommonsApplicationModule(appContext: Context) : CommonsApplicationModu
val mockDbOpenHelper: DBOpenHelper = mock() val mockDbOpenHelper: DBOpenHelper = mock()
val nearbyPlaces: NearbyPlaces = mock() val nearbyPlaces: NearbyPlaces = mock()
val lruCache: LruCache<String, String> = mock() val lruCache: LruCache<String, String> = mock()
val gson: Gson = Gson()
val categoryClient: ContentProviderClient = mock() val categoryClient: ContentProviderClient = mock()
val contributionClient: ContentProviderClient = mock() val contributionClient: ContentProviderClient = mock()
val modificationClient: ContentProviderClient = mock() val modificationClient: ContentProviderClient = mock()

View file

@ -26,15 +26,17 @@ class ApacheHttpClientMediaWikiApiTest {
private lateinit var testObject: ApacheHttpClientMediaWikiApi private lateinit var testObject: ApacheHttpClientMediaWikiApi
private lateinit var server: MockWebServer private lateinit var server: MockWebServer
private lateinit var wikidataServer: MockWebServer
private lateinit var sharedPreferences: SharedPreferences private lateinit var sharedPreferences: SharedPreferences
private lateinit var categoryPreferences: SharedPreferences private lateinit var categoryPreferences: SharedPreferences
@Before @Before
fun setUp() { fun setUp() {
server = MockWebServer() server = MockWebServer()
wikidataServer = MockWebServer()
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(RuntimeEnvironment.application) sharedPreferences = PreferenceManager.getDefaultSharedPreferences(RuntimeEnvironment.application)
categoryPreferences = PreferenceManager.getDefaultSharedPreferences(RuntimeEnvironment.application) categoryPreferences = PreferenceManager.getDefaultSharedPreferences(RuntimeEnvironment.application)
testObject = ApacheHttpClientMediaWikiApi(RuntimeEnvironment.application, "http://" + server.hostName + ":" + server.port + "/", sharedPreferences, categoryPreferences, Gson()) testObject = ApacheHttpClientMediaWikiApi(RuntimeEnvironment.application, "http://" + server.hostName + ":" + server.port + "/", "http://" + wikidataServer.hostName + ":" + wikidataServer.port + "/", sharedPreferences, categoryPreferences, Gson())
testObject.setWikiMediaToolforgeUrl("http://" + server.hostName + ":" + server.port + "/") testObject.setWikiMediaToolforgeUrl("http://" + server.hostName + ":" + server.port + "/")
} }