mirror of
				https://github.com/commons-app/apps-android-commons.git
				synced 2025-10-30 22:34:02 +01:00 
			
		
		
		
	Consolidated media wiki api calls in a single place
This commit is contained in:
		
							parent
							
								
									5396fc6ed0
								
							
						
					
					
						commit
						599e7bb453
					
				
					 18 changed files with 467 additions and 376 deletions
				
			
		|  | @ -8,41 +8,30 @@ import android.app.Application; | |||
| import android.content.Context; | ||||
| import android.content.SharedPreferences; | ||||
| import android.content.pm.PackageManager; | ||||
| import android.os.Build; | ||||
| import android.database.sqlite.SQLiteDatabase; | ||||
| import android.preference.PreferenceManager; | ||||
| import android.support.v4.util.LruCache; | ||||
| 
 | ||||
| import com.facebook.drawee.backends.pipeline.Fresco; | ||||
| import com.facebook.stetho.Stetho; | ||||
| 
 | ||||
| import fr.free.nrw.commons.caching.CacheController; | ||||
| import fr.free.nrw.commons.category.Category; | ||||
| import fr.free.nrw.commons.contributions.Contribution; | ||||
| import fr.free.nrw.commons.data.DBOpenHelper; | ||||
| import fr.free.nrw.commons.modifications.ModifierSequence; | ||||
| import fr.free.nrw.commons.auth.AccountUtil; | ||||
| import fr.free.nrw.commons.nearby.NearbyPlaces; | ||||
| 
 | ||||
| import com.squareup.leakcanary.LeakCanary; | ||||
| 
 | ||||
| import org.acra.ACRA; | ||||
| import org.acra.ReportingInteractionMode; | ||||
| import org.acra.annotation.ReportsCrashes; | ||||
| import org.apache.http.conn.ClientConnectionManager; | ||||
| import org.apache.http.conn.scheme.PlainSocketFactory; | ||||
| import org.apache.http.conn.scheme.Scheme; | ||||
| import org.apache.http.conn.scheme.SchemeRegistry; | ||||
| import org.apache.http.conn.ssl.SSLSocketFactory; | ||||
| import org.apache.http.impl.client.AbstractHttpClient; | ||||
| import org.apache.http.impl.client.DefaultHttpClient; | ||||
| import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; | ||||
| import org.apache.http.params.BasicHttpParams; | ||||
| import org.apache.http.params.CoreProtocolPNames; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| import fr.free.nrw.commons.auth.AccountUtil; | ||||
| import fr.free.nrw.commons.caching.CacheController; | ||||
| import fr.free.nrw.commons.category.Category; | ||||
| import fr.free.nrw.commons.contributions.Contribution; | ||||
| import fr.free.nrw.commons.data.DBOpenHelper; | ||||
| import fr.free.nrw.commons.modifications.ModifierSequence; | ||||
| import fr.free.nrw.commons.mwapi.ApacheHttpClientMediaWikiApi; | ||||
| import fr.free.nrw.commons.mwapi.MediaWikiApi; | ||||
| import fr.free.nrw.commons.nearby.NearbyPlaces; | ||||
| import fr.free.nrw.commons.utils.FileUtils; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
|  | @ -76,9 +65,8 @@ public class CommonsApplication extends Application { | |||
|     public static final String FEEDBACK_EMAIL_SUBJECT = "Commons Android App (%s) Feedback"; | ||||
| 
 | ||||
|     private static CommonsApplication instance = null; | ||||
|     private AbstractHttpClient httpClient = null; | ||||
|     private MWApi api = null; | ||||
|     LruCache<String, String> thumbnailUrlCache = new LruCache<>(1024); | ||||
|     private MediaWikiApi api = null; | ||||
|     private LruCache<String, String> thumbnailUrlCache = new LruCache<>(1024); | ||||
|     private CacheController cacheData = null; | ||||
|     private DBOpenHelper dbOpenHelper = null; | ||||
|     private NearbyPlaces nearbyPlaces = null; | ||||
|  | @ -98,35 +86,13 @@ public class CommonsApplication extends Application { | |||
|         return instance; | ||||
|     } | ||||
| 
 | ||||
|     public AbstractHttpClient getHttpClient() { | ||||
|         if (httpClient == null) { | ||||
|             httpClient = newHttpClient(); | ||||
|         } | ||||
|         return httpClient; | ||||
|     } | ||||
| 
 | ||||
|     private AbstractHttpClient newHttpClient() { | ||||
|         BasicHttpParams params = new BasicHttpParams(); | ||||
|         SchemeRegistry schemeRegistry = new SchemeRegistry(); | ||||
|         schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); | ||||
|         final SSLSocketFactory sslSocketFactory = SSLSocketFactory.getSocketFactory(); | ||||
|         schemeRegistry.register(new Scheme("https", sslSocketFactory, 443)); | ||||
|         ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry); | ||||
|         params.setParameter(CoreProtocolPNames.USER_AGENT, "Commons/" + BuildConfig.VERSION_NAME + " (https://mediawiki.org/wiki/Apps/Commons) Android/" + Build.VERSION.RELEASE); | ||||
|         return new DefaultHttpClient(cm, params); | ||||
|     } | ||||
| 
 | ||||
|     public MWApi getMWApi() { | ||||
|     public MediaWikiApi getMWApi() { | ||||
|         if (api == null) { | ||||
|             api = newMWApi(); | ||||
|             api = new ApacheHttpClientMediaWikiApi(API_URL); | ||||
|         } | ||||
|         return api; | ||||
|     } | ||||
| 
 | ||||
|     private MWApi newMWApi() { | ||||
|         return new MWApi(API_URL, getHttpClient()); | ||||
|     } | ||||
| 
 | ||||
|     public CacheController getCacheData() { | ||||
|         if (cacheData == null) { | ||||
|             cacheData = new CacheController(); | ||||
|  | @ -174,9 +140,6 @@ public class CommonsApplication extends Application { | |||
| 
 | ||||
|         Fresco.initialize(this); | ||||
| 
 | ||||
|         // Initialize EventLogging | ||||
|         EventLog.setApp(this); | ||||
| 
 | ||||
|         //For caching area -> categories | ||||
|         cacheData  = new CacheController(); | ||||
|     } | ||||
|  |  | |||
|  | @ -1,130 +0,0 @@ | |||
| package fr.free.nrw.commons; | ||||
| 
 | ||||
| import android.content.SharedPreferences; | ||||
| import android.os.AsyncTask; | ||||
| import android.os.Build; | ||||
| import android.preference.PreferenceManager; | ||||
| 
 | ||||
| import org.apache.http.HttpResponse; | ||||
| import org.apache.http.impl.client.AbstractHttpClient; | ||||
| import org.json.JSONException; | ||||
| import org.json.JSONObject; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.net.MalformedURLException; | ||||
| import java.net.URL; | ||||
| 
 | ||||
| import fr.free.nrw.commons.settings.Prefs; | ||||
| import in.yuvi.http.fluent.Http; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| public class EventLog { | ||||
| 
 | ||||
|     private static CommonsApplication app; | ||||
| 
 | ||||
|     private static class LogTask extends AsyncTask<LogBuilder, Void, Boolean> { | ||||
| 
 | ||||
|         @Override | ||||
|         protected Boolean doInBackground(LogBuilder... logBuilders) { | ||||
| 
 | ||||
|             boolean  allSuccess = true; | ||||
|             // Not using the default URL connection, since that seems to have different behavior than the rest of the code | ||||
|             for(LogBuilder logBuilder: logBuilders) { | ||||
|                 try { | ||||
|                     URL url = logBuilder.toUrl(); | ||||
|                     AbstractHttpClient httpClient = CommonsApplication.getInstance().getHttpClient(); | ||||
|                     HttpResponse response = Http.get(url.toString()).use(httpClient).asResponse(); | ||||
| 
 | ||||
|                     if(response.getStatusLine().getStatusCode() != 204) { | ||||
|                         allSuccess = false; | ||||
|                     } | ||||
|                     Timber.d("EventLog hit %s", url); | ||||
| 
 | ||||
|                 } catch (IOException e) { | ||||
|                     // Probably just ignore for now. Can be much more robust with a service, etc later on. | ||||
|                     Timber.d("IO Error, EventLog hit skipped"); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return allSuccess; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static final String DEVICE; | ||||
|     static { | ||||
|         if (Build.MODEL.startsWith(Build.MANUFACTURER)) { | ||||
|             DEVICE = Utils.capitalize(Build.MODEL); | ||||
|         } else { | ||||
|             DEVICE = Utils.capitalize(Build.MANUFACTURER) + " " + Build.MODEL; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public static void setApp(CommonsApplication app) { | ||||
|         EventLog.app = app; | ||||
|     } | ||||
| 
 | ||||
|     public static class LogBuilder { | ||||
|         private JSONObject data; | ||||
|         private long rev; | ||||
|         private String schema; | ||||
| 
 | ||||
|         private LogBuilder(String schema, long revision) { | ||||
|             data = new JSONObject(); | ||||
|             this.schema = schema; | ||||
|             this.rev = revision; | ||||
|         } | ||||
| 
 | ||||
|         public LogBuilder param(String key, Object value) { | ||||
|             try { | ||||
|                 data.put(key, value); | ||||
|             } catch (JSONException e) { | ||||
|                 throw new RuntimeException(e); | ||||
|             } | ||||
|             return this; | ||||
|         } | ||||
| 
 | ||||
|         private URL toUrl() { | ||||
|             JSONObject fullData = new JSONObject(); | ||||
|             try { | ||||
|                 fullData.put("schema", schema); | ||||
|                 fullData.put("revision", rev); | ||||
|                 fullData.put("wiki", CommonsApplication.EVENTLOG_WIKI); | ||||
|                 data.put("device", DEVICE); | ||||
|                 data.put("platform", "Android/" + Build.VERSION.RELEASE); | ||||
|                 data.put("appversion", "Android/" + BuildConfig.VERSION_NAME); | ||||
|                 fullData.put("event", data); | ||||
|                 return new URL(CommonsApplication.EVENTLOG_URL + "?" + Utils.urlEncode(fullData.toString()) + ";"); | ||||
|             } catch (MalformedURLException | JSONException e) { | ||||
|                 throw new RuntimeException(e); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // force param disregards user preference | ||||
|         // Use *only* for tracking the user preference change for EventLogging | ||||
|         // Attempting to use anywhere else will cause kitten explosions | ||||
|         public void log(boolean force) { | ||||
|             SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(app); | ||||
|             if(!settings.getBoolean(Prefs.TRACKING_ENABLED, true) && !force) { | ||||
|                 return; // User has disabled tracking | ||||
|             } | ||||
|             LogTask logTask = new LogTask(); | ||||
|             logTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, this); | ||||
|         } | ||||
| 
 | ||||
|         public void log() { | ||||
|             log(false); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public static LogBuilder schema(String schema, long revision) { | ||||
|         return new LogBuilder(schema, revision); | ||||
|     } | ||||
| 
 | ||||
|     public static LogBuilder schema(Object[] scid) { | ||||
|         if(scid.length != 2) { | ||||
|             throw new IllegalArgumentException("Needs an object array with schema as first param and revision as second"); | ||||
|         } | ||||
|         return schema((String)scid[0], (Long)scid[1]); | ||||
|     } | ||||
| } | ||||
|  | @ -1,94 +0,0 @@ | |||
| package fr.free.nrw.commons; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| import org.apache.http.impl.client.AbstractHttpClient; | ||||
| import org.mediawiki.api.ApiResult; | ||||
| 
 | ||||
| /** | ||||
|  * @author Addshore | ||||
|  */ | ||||
| public class MWApi extends org.mediawiki.api.MWApi { | ||||
| 
 | ||||
|     /** We don't actually use this but need to pass it in requests */ | ||||
|     private static String LOGIN_RETURN_TO_URL = "https://commons.wikimedia.org"; | ||||
| 
 | ||||
|     public MWApi(String apiURL, AbstractHttpClient client) { | ||||
|         super(apiURL, client); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @param username String | ||||
|      * @param password String | ||||
|      * @return String as returned by this.getErrorCodeToReturn() | ||||
|      * @throws IOException On api request IO issue | ||||
|      */ | ||||
|     public String login(String username, String password) throws IOException { | ||||
|         String token = this.getLoginToken(); | ||||
|         ApiResult loginApiResult = this.action("clientlogin") | ||||
|                 .param("rememberMe", "1") | ||||
|                 .param("username", username) | ||||
|                 .param("password", password) | ||||
|                 .param("logintoken", token) | ||||
|                 .param("loginreturnurl", LOGIN_RETURN_TO_URL) | ||||
|                 .post(); | ||||
|         return this.getErrorCodeToReturn( loginApiResult ); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @param username String | ||||
|      * @param password String | ||||
|      * @param twoFactorCode String | ||||
|      * @return String as returned by this.getErrorCodeToReturn() | ||||
|      * @throws IOException On api request IO issue | ||||
|      */ | ||||
|     public String login(String username, String password, String twoFactorCode) throws IOException { | ||||
|         String token = this.getLoginToken();//TODO cache this instead of calling again when 2FAing | ||||
|         ApiResult loginApiResult = this.action("clientlogin") | ||||
|                 .param("rememberMe", "1") | ||||
|                 .param("username", username) | ||||
|                 .param("password", password) | ||||
|                 .param("logintoken", token) | ||||
|                 .param("logincontinue", "1") | ||||
|                 .param("OATHToken", twoFactorCode) | ||||
|                 .post(); | ||||
| 
 | ||||
|         return this.getErrorCodeToReturn( loginApiResult ); | ||||
|     } | ||||
| 
 | ||||
|     private String getLoginToken() throws IOException { | ||||
|         ApiResult tokenResult = this.action("query") | ||||
|                 .param("action", "query") | ||||
|                 .param("meta", "tokens") | ||||
|                 .param("type", "login") | ||||
|                 .post(); | ||||
|         return tokenResult.getString("/api/query/tokens/@logintoken"); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @param loginApiResult ApiResult Any clientlogin api result | ||||
|      * @return String On success: "PASS" | ||||
|      *                   continue: "2FA" (More information required for 2FA) | ||||
|      *                   failure: A failure message code (defined by mediawiki) | ||||
|      *                   misc:    genericerror-UI, genericerror-REDIRECT, genericerror-RESTART | ||||
|      */ | ||||
|     private String getErrorCodeToReturn( ApiResult loginApiResult ) { | ||||
|         String status = loginApiResult.getString("/api/clientlogin/@status"); | ||||
|         if (status.equals("PASS")) { | ||||
|             this.isLoggedIn = true; | ||||
|             return status; | ||||
|         } else if (status.equals("FAIL")) { | ||||
|             return loginApiResult.getString("/api/clientlogin/@messagecode"); | ||||
|         } else if ( | ||||
|                 status.equals("UI") | ||||
|                         && loginApiResult.getString("/api/clientlogin/requests/_v/@id").equals("TOTPAuthenticationRequest") | ||||
|                         && loginApiResult.getString("/api/clientlogin/requests/_v/@provider").equals("Two-factor authentication (OATH).") | ||||
|                 ) { | ||||
|             return "2FA"; | ||||
|         } | ||||
| 
 | ||||
|         // UI, REDIRECT, RESTART | ||||
|         return "genericerror-" + status; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -21,6 +21,7 @@ import javax.xml.parsers.DocumentBuilderFactory; | |||
| import javax.xml.parsers.ParserConfigurationException; | ||||
| 
 | ||||
| import fr.free.nrw.commons.location.LatLng; | ||||
| import fr.free.nrw.commons.mwapi.MediaWikiApi; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| /** | ||||
|  | @ -62,16 +63,8 @@ public class MediaDataExtractor { | |||
|             throw new IllegalStateException("Tried to call MediaDataExtractor.fetch() again."); | ||||
|         } | ||||
| 
 | ||||
|         MWApi api = CommonsApplication.getInstance().getMWApi(); | ||||
|         ApiResult result = api.action("query") | ||||
|                 .param("prop", "revisions") | ||||
|                 .param("titles", filename) | ||||
|                 .param("rvprop", "content") | ||||
|                 .param("rvlimit", 1) | ||||
|                 .param("rvgeneratexml", 1) | ||||
|                 .get(); | ||||
| 
 | ||||
|         processResult(result); | ||||
|         MediaWikiApi api = CommonsApplication.getInstance().getMWApi(); | ||||
|         processResult(api.fetchMediaByFilename(filename)); | ||||
|         fetched = true; | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,10 +3,9 @@ package fr.free.nrw.commons; | |||
| import android.os.AsyncTask; | ||||
| import android.support.annotation.NonNull; | ||||
| 
 | ||||
| import org.mediawiki.api.ApiResult; | ||||
| import fr.free.nrw.commons.mwapi.MediaWikiApi; | ||||
| 
 | ||||
| class MediaThumbnailFetchTask extends AsyncTask<String, String, String> { | ||||
|     private static final String THUMB_SIZE = "640"; | ||||
|     protected final Media media; | ||||
| 
 | ||||
|     public MediaThumbnailFetchTask(@NonNull Media media) { | ||||
|  | @ -16,15 +15,8 @@ class MediaThumbnailFetchTask extends AsyncTask<String, String, String> { | |||
|     @Override | ||||
|     protected String doInBackground(String... params) { | ||||
|         try { | ||||
|             MWApi api = CommonsApplication.getInstance().getMWApi(); | ||||
|             ApiResult result =api.action("query") | ||||
|                     .param("format", "xml") | ||||
|                     .param("prop", "imageinfo") | ||||
|                     .param("iiprop", "url") | ||||
|                     .param("iiurlwidth", THUMB_SIZE) | ||||
|                     .param("titles", params[0]) | ||||
|                     .get(); | ||||
|             return result.getString("/api/query/pages/page/imageinfo/ii/@thumburl"); | ||||
|             MediaWikiApi api = CommonsApplication.getInstance().getMWApi(); | ||||
|             return api.findThumbnailByFilename(params[0]); | ||||
|         } catch (Exception e) { | ||||
|             // Do something better! | ||||
|         } | ||||
|  |  | |||
|  | @ -8,13 +8,13 @@ import android.accounts.NetworkErrorException; | |||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.os.Bundle; | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.annotation.Nullable; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| import android.support.annotation.NonNull; | ||||
| import android.support.annotation.Nullable; | ||||
| import fr.free.nrw.commons.CommonsApplication; | ||||
| import fr.free.nrw.commons.MWApi; | ||||
| import fr.free.nrw.commons.mwapi.MediaWikiApi; | ||||
| 
 | ||||
| public class WikiAccountAuthenticator extends AbstractAccountAuthenticator { | ||||
| 
 | ||||
|  | @ -75,7 +75,7 @@ public class WikiAccountAuthenticator extends AbstractAccountAuthenticator { | |||
|     } | ||||
| 
 | ||||
|     private String getAuthCookie(String username, String password) throws IOException { | ||||
|         MWApi api = CommonsApplication.getInstance().getMWApi(); | ||||
|         MediaWikiApi api = CommonsApplication.getInstance().getMWApi(); | ||||
|         //TODO add 2fa support here | ||||
|         String result = api.login(username, password); | ||||
|         if(result.equals("PASS")) { | ||||
|  |  | |||
|  | @ -3,7 +3,6 @@ package fr.free.nrw.commons.category; | |||
| import android.os.AsyncTask; | ||||
| import android.view.View; | ||||
| 
 | ||||
| import fr.free.nrw.commons.MWApi; | ||||
| import org.mediawiki.api.ApiResult; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
|  | @ -12,6 +11,7 @@ import java.util.Calendar; | |||
| import java.util.Iterator; | ||||
| 
 | ||||
| import fr.free.nrw.commons.CommonsApplication; | ||||
| import fr.free.nrw.commons.mwapi.MediaWikiApi; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| /** | ||||
|  | @ -79,20 +79,13 @@ public class MethodAUpdater extends AsyncTask<Void, Void, ArrayList<String>> { | |||
|     protected ArrayList<String> doInBackground(Void... voids) { | ||||
| 
 | ||||
|         //otherwise if user has typed something in that isn't in cache, search API for matching categories | ||||
|         MWApi api = CommonsApplication.getInstance().getMWApi(); | ||||
|         MediaWikiApi api = CommonsApplication.getInstance().getMWApi(); | ||||
|         ApiResult result; | ||||
|         ArrayList<String> categories = new ArrayList<>(); | ||||
| 
 | ||||
|         //URL https://commons.wikimedia.org/w/api.php?action=query&format=xml&list=search&srwhat=text&srenablerewrites=1&srnamespace=14&srlimit=10&srsearch= | ||||
|         try { | ||||
|             result = api.action("query") | ||||
|                     .param("format", "xml") | ||||
|                     .param("list", "search") | ||||
|                     .param("srwhat", "text") | ||||
|                     .param("srnamespace", "14") | ||||
|                     .param("srlimit", catFragment.SEARCH_CATS_LIMIT) | ||||
|                     .param("srsearch", filter) | ||||
|                     .get(); | ||||
|             result = api.searchCategories(CategorizationFragment.SEARCH_CATS_LIMIT, filter); | ||||
|             Timber.d("Method A URL filter %s", result); | ||||
|         } catch (IOException e) { | ||||
|             Timber.e(e, "IO Exception: "); | ||||
|  |  | |||
|  | @ -4,7 +4,6 @@ import android.os.AsyncTask; | |||
| import android.text.TextUtils; | ||||
| import android.view.View; | ||||
| 
 | ||||
| import fr.free.nrw.commons.MWApi; | ||||
| import org.mediawiki.api.ApiResult; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
|  | @ -13,6 +12,7 @@ import java.util.Calendar; | |||
| import java.util.Iterator; | ||||
| 
 | ||||
| import fr.free.nrw.commons.CommonsApplication; | ||||
| import fr.free.nrw.commons.mwapi.MediaWikiApi; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| /** | ||||
|  | @ -95,15 +95,11 @@ public class PrefixUpdater extends AsyncTask<Void, Void, ArrayList<String>> { | |||
| 
 | ||||
|         //otherwise if user has typed something in that isn't in cache, search API for matching categories | ||||
|         //URL: https://commons.wikimedia.org/w/api.php?action=query&list=allcategories&acprefix=filter&aclimit=25 | ||||
|         MWApi api = CommonsApplication.getInstance().getMWApi(); | ||||
|         MediaWikiApi api = CommonsApplication.getInstance().getMWApi(); | ||||
|         ApiResult result; | ||||
|         ArrayList<String> categories = new ArrayList<>(); | ||||
|         try { | ||||
|             result = api.action("query") | ||||
|                     .param("list", "allcategories") | ||||
|                     .param("acprefix", filter) | ||||
|                     .param("aclimit", catFragment.SEARCH_CATS_LIMIT) | ||||
|                     .get(); | ||||
|             result = api.allCategories(CategorizationFragment.SEARCH_CATS_LIMIT, this.filter); | ||||
|             Timber.d("Prefix URL filter %s", result); | ||||
|         } catch (IOException e) { | ||||
|             Timber.e(e, "IO Exception: "); | ||||
|  |  | |||
|  | @ -2,13 +2,13 @@ package fr.free.nrw.commons.category; | |||
| 
 | ||||
| import android.os.AsyncTask; | ||||
| 
 | ||||
| import fr.free.nrw.commons.MWApi; | ||||
| import org.mediawiki.api.ApiResult; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.util.ArrayList; | ||||
| 
 | ||||
| import fr.free.nrw.commons.CommonsApplication; | ||||
| import fr.free.nrw.commons.mwapi.MediaWikiApi; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| /** | ||||
|  | @ -34,20 +34,13 @@ public class TitleCategories extends AsyncTask<Void, Void, ArrayList<String>> { | |||
|     @Override | ||||
|     protected ArrayList<String> doInBackground(Void... voids) { | ||||
| 
 | ||||
|         MWApi api = CommonsApplication.getInstance().getMWApi(); | ||||
|         MediaWikiApi api = CommonsApplication.getInstance().getMWApi(); | ||||
|         ApiResult result; | ||||
|         ArrayList<String> items = new ArrayList<>(); | ||||
| 
 | ||||
|         //URL https://commons.wikimedia.org/w/api.php?action=query&format=xml&list=search&srwhat=text&srenablerewrites=1&srnamespace=14&srlimit=10&srsearch= | ||||
|         try { | ||||
|             result = api.action("query") | ||||
|                     .param("format", "xml") | ||||
|                     .param("list", "search") | ||||
|                     .param("srwhat", "text") | ||||
|                     .param("srnamespace", "14") | ||||
|                     .param("srlimit", SEARCH_CATS_LIMIT) | ||||
|                     .param("srsearch", title) | ||||
|                     .get(); | ||||
|             result = api.searchTitles(SEARCH_CATS_LIMIT, this.title); | ||||
|             Timber.d("Searching for cats for title: %s", result); | ||||
|         } catch (IOException e) { | ||||
|             Timber.e(e, "IO Exception: "); | ||||
|  |  | |||
|  | @ -19,8 +19,8 @@ import java.util.ArrayList; | |||
| import java.util.Date; | ||||
| 
 | ||||
| import fr.free.nrw.commons.CommonsApplication; | ||||
| import fr.free.nrw.commons.MWApi; | ||||
| import fr.free.nrw.commons.Utils; | ||||
| import fr.free.nrw.commons.mwapi.MediaWikiApi; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| public class ContributionsSyncAdapter extends AbstractThreadedSyncAdapter { | ||||
|  | @ -61,7 +61,7 @@ public class ContributionsSyncAdapter extends AbstractThreadedSyncAdapter { | |||
|     public void onPerformSync(Account account, Bundle bundle, String s, ContentProviderClient contentProviderClient, SyncResult syncResult) { | ||||
|         // This code is fraught with possibilities of race conditions, but lalalalala I can't hear you! | ||||
|         String user = account.name; | ||||
|         MWApi api = CommonsApplication.getInstance().getMWApi(); | ||||
|         MediaWikiApi api = CommonsApplication.getInstance().getMWApi(); | ||||
|         SharedPreferences prefs = this.getContext().getSharedPreferences("prefs", Context.MODE_PRIVATE); | ||||
|         String lastModified = prefs.getString("lastSyncTimestamp", ""); | ||||
|         Date curTime = new Date(); | ||||
|  | @ -71,19 +71,7 @@ public class ContributionsSyncAdapter extends AbstractThreadedSyncAdapter { | |||
|         while(!done) { | ||||
| 
 | ||||
|             try { | ||||
|                 MWApi.RequestBuilder builder = api.action("query") | ||||
|                         .param("list", "logevents") | ||||
|                         .param("letype", "upload") | ||||
|                         .param("leprop", "title|timestamp|ids") | ||||
|                         .param("leuser", user) | ||||
|                         .param("lelimit", getLimit()); | ||||
|                 if(!TextUtils.isEmpty(lastModified)) { | ||||
|                     builder.param("leend", lastModified); | ||||
|                 } | ||||
|                 if(!TextUtils.isEmpty(queryContinue)) { | ||||
|                     builder.param("lestart", queryContinue); | ||||
|                 } | ||||
|                 result = builder.get(); | ||||
|                 result = api.logEvents(user, lastModified, queryContinue, getLimit()); | ||||
|             } catch (IOException e) { | ||||
|                 // There isn't really much we can do, eh? | ||||
|                 // FIXME: Perhaps add EventLogging? | ||||
|  |  | |||
|  | @ -12,7 +12,6 @@ import android.database.Cursor; | |||
| import android.os.Bundle; | ||||
| import android.os.RemoteException; | ||||
| 
 | ||||
| import fr.free.nrw.commons.MWApi; | ||||
| import org.mediawiki.api.ApiResult; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
|  | @ -21,6 +20,7 @@ import fr.free.nrw.commons.CommonsApplication; | |||
| import fr.free.nrw.commons.Utils; | ||||
| import fr.free.nrw.commons.contributions.Contribution; | ||||
| import fr.free.nrw.commons.contributions.ContributionsContentProvider; | ||||
| import fr.free.nrw.commons.mwapi.MediaWikiApi; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| public class ModificationsSyncAdapter extends AbstractThreadedSyncAdapter { | ||||
|  | @ -61,7 +61,7 @@ public class ModificationsSyncAdapter extends AbstractThreadedSyncAdapter { | |||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         MWApi api = CommonsApplication.getInstance().getMWApi(); | ||||
|         MediaWikiApi api = CommonsApplication.getInstance().getMWApi(); | ||||
|         api.setAuthCookie(authCookie); | ||||
|         String editToken; | ||||
| 
 | ||||
|  | @ -98,11 +98,7 @@ public class ModificationsSyncAdapter extends AbstractThreadedSyncAdapter { | |||
|                 if(contrib.getState() == Contribution.STATE_COMPLETED) { | ||||
| 
 | ||||
|                     try { | ||||
|                         requestResult = api.action("query") | ||||
|                                 .param("prop", "revisions") | ||||
|                                 .param("rvprop", "timestamp|content") | ||||
|                                 .param("titles", contrib.getFilename()) | ||||
|                                 .get(); | ||||
|                         requestResult = api.revisionsByFilename(contrib.getFilename()); | ||||
|                     } catch (IOException e) { | ||||
|                         Timber.d("Network fuckup on modifications sync!"); | ||||
|                         continue; | ||||
|  | @ -113,12 +109,7 @@ public class ModificationsSyncAdapter extends AbstractThreadedSyncAdapter { | |||
|                     String processedPageContent = sequence.executeModifications(contrib.getFilename(),  pageContent); | ||||
| 
 | ||||
|                     try { | ||||
|                         responseResult = api.action("edit") | ||||
|                                 .param("title", contrib.getFilename()) | ||||
|                                 .param("token", editToken) | ||||
|                                 .param("text", processedPageContent) | ||||
|                                 .param("summary", sequence.getEditSummary()) | ||||
|                                 .post(); | ||||
|                         responseResult = api.edit(editToken, processedPageContent, contrib.getFilename(), sequence.getEditSummary()); | ||||
|                     } catch (IOException e) { | ||||
|                         Timber.d("Network fuckup on modifications sync!"); | ||||
|                         continue; | ||||
|  |  | |||
|  | @ -0,0 +1,258 @@ | |||
| package fr.free.nrw.commons.mwapi; | ||||
| 
 | ||||
| import android.os.Build; | ||||
| import android.text.TextUtils; | ||||
| 
 | ||||
| import org.apache.http.HttpResponse; | ||||
| import org.apache.http.conn.ClientConnectionManager; | ||||
| import org.apache.http.conn.scheme.PlainSocketFactory; | ||||
| import org.apache.http.conn.scheme.Scheme; | ||||
| import org.apache.http.conn.scheme.SchemeRegistry; | ||||
| import org.apache.http.conn.ssl.SSLSocketFactory; | ||||
| import org.apache.http.impl.client.AbstractHttpClient; | ||||
| import org.apache.http.impl.client.DefaultHttpClient; | ||||
| import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; | ||||
| import org.apache.http.params.BasicHttpParams; | ||||
| import org.apache.http.params.CoreProtocolPNames; | ||||
| import org.mediawiki.api.ApiResult; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.net.URL; | ||||
| 
 | ||||
| import fr.free.nrw.commons.BuildConfig; | ||||
| import in.yuvi.http.fluent.Http; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| /** | ||||
|  * @author Addshore | ||||
|  */ | ||||
| public class ApacheHttpClientMediaWikiApi extends org.mediawiki.api.MWApi implements MediaWikiApi { | ||||
|     private static final String THUMB_SIZE = "640"; | ||||
|     private static AbstractHttpClient httpClient; | ||||
| 
 | ||||
|     public ApacheHttpClientMediaWikiApi(String apiURL) { | ||||
|         super(apiURL, getHttpClient()); | ||||
|     } | ||||
| 
 | ||||
|     private static AbstractHttpClient getHttpClient() { | ||||
|         if (httpClient == null) { | ||||
|             httpClient = newHttpClient(); | ||||
|         } | ||||
|         return httpClient; | ||||
|     } | ||||
| 
 | ||||
|     private static AbstractHttpClient newHttpClient() { | ||||
|         BasicHttpParams params = new BasicHttpParams(); | ||||
|         SchemeRegistry schemeRegistry = new SchemeRegistry(); | ||||
|         schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); | ||||
|         final SSLSocketFactory sslSocketFactory = SSLSocketFactory.getSocketFactory(); | ||||
|         schemeRegistry.register(new Scheme("https", sslSocketFactory, 443)); | ||||
|         ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry); | ||||
|         params.setParameter(CoreProtocolPNames.USER_AGENT, "Commons/" + BuildConfig.VERSION_NAME + " (https://mediawiki.org/wiki/Apps/Commons) Android/" + Build.VERSION.RELEASE); | ||||
|         return new DefaultHttpClient(cm, params); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * @param username String | ||||
|      * @param password String | ||||
|      * @return String as returned by this.getErrorCodeToReturn() | ||||
|      * @throws IOException On api request IO issue | ||||
|      */ | ||||
|     public String login(String username, String password) throws IOException { | ||||
|         return getErrorCodeToReturn(action("clientlogin") | ||||
|                 .param("rememberMe", "1") | ||||
|                 .param("username", username) | ||||
|                 .param("password", password) | ||||
|                 .param("logintoken", this.getLoginToken()) | ||||
|                 .param("loginreturnurl", "https://commons.wikimedia.org") | ||||
|                 .post()); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @param username      String | ||||
|      * @param password      String | ||||
|      * @param twoFactorCode String | ||||
|      * @return String as returned by this.getErrorCodeToReturn() | ||||
|      * @throws IOException On api request IO issue | ||||
|      */ | ||||
|     public String login(String username, String password, String twoFactorCode) throws IOException { | ||||
|         return getErrorCodeToReturn(action("clientlogin") | ||||
|                 .param("rememberMe", "1") | ||||
|                 .param("username", username) | ||||
|                 .param("password", password) | ||||
|                 .param("logintoken", getLoginToken()) | ||||
|                 .param("logincontinue", "1") | ||||
|                 .param("OATHToken", twoFactorCode) | ||||
|                 .post()); | ||||
|     } | ||||
| 
 | ||||
|     private String getLoginToken() throws IOException { | ||||
|         return this.action("query") | ||||
|                 .param("action", "query") | ||||
|                 .param("meta", "tokens") | ||||
|                 .param("type", "login") | ||||
|                 .post() | ||||
|                 .getString("/api/query/tokens/@logintoken"); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @param loginApiResult ApiResult Any clientlogin api result | ||||
|      * @return String On success: "PASS" | ||||
|      * continue: "2FA" (More information required for 2FA) | ||||
|      * failure: A failure message code (defined by mediawiki) | ||||
|      * misc:    genericerror-UI, genericerror-REDIRECT, genericerror-RESTART | ||||
|      */ | ||||
|     private String getErrorCodeToReturn(ApiResult loginApiResult) { | ||||
|         String status = loginApiResult.getString("/api/clientlogin/@status"); | ||||
|         if (status.equals("PASS")) { | ||||
|             this.isLoggedIn = true; | ||||
|             return status; | ||||
|         } else if (status.equals("FAIL")) { | ||||
|             return loginApiResult.getString("/api/clientlogin/@messagecode"); | ||||
|         } else if ( | ||||
|                 status.equals("UI") | ||||
|                         && loginApiResult.getString("/api/clientlogin/requests/_v/@id").equals("TOTPAuthenticationRequest") | ||||
|                         && loginApiResult.getString("/api/clientlogin/requests/_v/@provider").equals("Two-factor authentication (OATH).") | ||||
|                 ) { | ||||
|             return "2FA"; | ||||
|         } | ||||
| 
 | ||||
|         // UI, REDIRECT, RESTART | ||||
|         return "genericerror-" + status; | ||||
|     } | ||||
| 
 | ||||
|     // Moved / consolidated methods | ||||
|     @Override | ||||
|     public boolean fileExistsWithName(String fileName) throws IOException { | ||||
|         return action("query") | ||||
|                 .param("prop", "imageinfo") | ||||
|                 .param("titles", "File:" + fileName) | ||||
|                 .get() | ||||
|                 .getNodes("/api/query/pages/page/imageinfo").size() > 0; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public ApiResult edit(String editToken, String processedPageContent, String filename, String summary) throws IOException { | ||||
|         return action("edit") | ||||
|                 .param("title", filename) | ||||
|                 .param("token", editToken) | ||||
|                 .param("text", processedPageContent) | ||||
|                 .param("summary", summary) | ||||
|                 .post(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public String findThumbnailByFilename(String filename) throws IOException { | ||||
|         return action("query") | ||||
|                 .param("format", "xml") | ||||
|                 .param("prop", "imageinfo") | ||||
|                 .param("iiprop", "url") | ||||
|                 .param("iiurlwidth", THUMB_SIZE) | ||||
|                 .param("titles", filename) | ||||
|                 .get() | ||||
|                 .getString("/api/query/pages/page/imageinfo/ii/@thumburl"); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public ApiResult fetchMediaByFilename(String filename) throws IOException { | ||||
|         return action("query") | ||||
|                 .param("prop", "revisions") | ||||
|                 .param("titles", filename) | ||||
|                 .param("rvprop", "content") | ||||
|                 .param("rvlimit", 1) | ||||
|                 .param("rvgeneratexml", 1) | ||||
|                 .get(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public ApiResult searchCategories(int searchCatsLimit, String filterValue) throws IOException { | ||||
|         return action("query") | ||||
|                 .param("format", "xml") | ||||
|                 .param("list", "search") | ||||
|                 .param("srwhat", "text") | ||||
|                 .param("srnamespace", "14") | ||||
|                 .param("srlimit", searchCatsLimit) | ||||
|                 .param("srsearch", filterValue) | ||||
|                 .get(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public ApiResult allCategories(int searchCatsLimit, String filterValue) throws IOException { | ||||
|         return action("query") | ||||
|                 .param("list", "allcategories") | ||||
|                 .param("acprefix", filterValue) | ||||
|                 .param("aclimit", searchCatsLimit) | ||||
|                 .get(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public ApiResult searchTitles(int searchCatsLimit, String title) throws IOException { | ||||
|         return action("query") | ||||
|                 .param("format", "xml") | ||||
|                 .param("list", "search") | ||||
|                 .param("srwhat", "text") | ||||
|                 .param("srnamespace", "14") | ||||
|                 .param("srlimit", searchCatsLimit) | ||||
|                 .param("srsearch", title) | ||||
|                 .get(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public ApiResult logEvents(String user, String lastModified, String queryContinue, int limit) throws IOException { | ||||
|         org.mediawiki.api.MWApi.RequestBuilder builder = action("query") | ||||
|                 .param("list", "logevents") | ||||
|                 .param("letype", "upload") | ||||
|                 .param("leprop", "title|timestamp|ids") | ||||
|                 .param("leuser", user) | ||||
|                 .param("lelimit", limit); | ||||
|         if (!TextUtils.isEmpty(lastModified)) { | ||||
|             builder.param("leend", lastModified); | ||||
|         } | ||||
|         if (!TextUtils.isEmpty(queryContinue)) { | ||||
|             builder.param("lestart", queryContinue); | ||||
|         } | ||||
|         return builder.get(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public ApiResult revisionsByFilename(String filename) throws IOException { | ||||
|         return action("query") | ||||
|                 .param("prop", "revisions") | ||||
|                 .param("rvprop", "timestamp|content") | ||||
|                 .param("titles", filename) | ||||
|                 .get(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public ApiResult existingFile(String fileSha1) throws IOException { | ||||
|         return action("query") | ||||
|                 .param("format", "xml") | ||||
|                 .param("list", "allimages") | ||||
|                 .param("aisha1", fileSha1) | ||||
|                 .get(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean logEvents(LogBuilder[] logBuilders) { | ||||
|         boolean allSuccess = true; | ||||
|         // Not using the default URL connection, since that seems to have different behavior than the rest of the code | ||||
|         for (LogBuilder logBuilder : logBuilders) { | ||||
|             try { | ||||
|                 URL url = logBuilder.toUrl(); | ||||
|                 HttpResponse response = Http.get(url.toString()).use(httpClient).asResponse(); | ||||
| 
 | ||||
|                 if (response.getStatusLine().getStatusCode() != 204) { | ||||
|                     allSuccess = false; | ||||
|                 } | ||||
|                 Timber.d("EventLog hit %s", url); | ||||
| 
 | ||||
|             } catch (IOException e) { | ||||
|                 // Probably just ignore for now. Can be much more robust with a service, etc later on. | ||||
|                 Timber.d("IO Error, EventLog hit skipped"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return allSuccess; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										28
									
								
								app/src/main/java/fr/free/nrw/commons/mwapi/EventLog.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								app/src/main/java/fr/free/nrw/commons/mwapi/EventLog.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | |||
| package fr.free.nrw.commons.mwapi; | ||||
| 
 | ||||
| import android.os.Build; | ||||
| 
 | ||||
| import fr.free.nrw.commons.Utils; | ||||
| 
 | ||||
| public class EventLog { | ||||
|     static final String DEVICE; | ||||
| 
 | ||||
|     static { | ||||
|         if (Build.MODEL.startsWith(Build.MANUFACTURER)) { | ||||
|             DEVICE = Utils.capitalize(Build.MODEL); | ||||
|         } else { | ||||
|             DEVICE = Utils.capitalize(Build.MANUFACTURER) + " " + Build.MODEL; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static LogBuilder schema(String schema, long revision) { | ||||
|         return new LogBuilder(schema, revision); | ||||
|     } | ||||
| 
 | ||||
|     public static LogBuilder schema(Object[] scid) { | ||||
|         if (scid.length != 2) { | ||||
|             throw new IllegalArgumentException("Needs an object array with schema as first param and revision as second"); | ||||
|         } | ||||
|         return schema((String) scid[0], (Long) scid[1]); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										71
									
								
								app/src/main/java/fr/free/nrw/commons/mwapi/LogBuilder.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								app/src/main/java/fr/free/nrw/commons/mwapi/LogBuilder.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,71 @@ | |||
| package fr.free.nrw.commons.mwapi; | ||||
| 
 | ||||
| import android.content.SharedPreferences; | ||||
| import android.os.AsyncTask; | ||||
| import android.os.Build; | ||||
| import android.preference.PreferenceManager; | ||||
| 
 | ||||
| import org.json.JSONException; | ||||
| import org.json.JSONObject; | ||||
| 
 | ||||
| import java.net.MalformedURLException; | ||||
| import java.net.URL; | ||||
| 
 | ||||
| import fr.free.nrw.commons.BuildConfig; | ||||
| import fr.free.nrw.commons.CommonsApplication; | ||||
| import fr.free.nrw.commons.Utils; | ||||
| import fr.free.nrw.commons.settings.Prefs; | ||||
| 
 | ||||
| public class LogBuilder { | ||||
|     private JSONObject data; | ||||
|     private long rev; | ||||
|     private String schema; | ||||
| 
 | ||||
|     LogBuilder(String schema, long revision) { | ||||
|         data = new JSONObject(); | ||||
|         this.schema = schema; | ||||
|         this.rev = revision; | ||||
|     } | ||||
| 
 | ||||
|     public LogBuilder param(String key, Object value) { | ||||
|         try { | ||||
|             data.put(key, value); | ||||
|         } catch (JSONException e) { | ||||
|             throw new RuntimeException(e); | ||||
|         } | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     URL toUrl() { | ||||
|         JSONObject fullData = new JSONObject(); | ||||
|         try { | ||||
|             fullData.put("schema", schema); | ||||
|             fullData.put("revision", rev); | ||||
|             fullData.put("wiki", CommonsApplication.EVENTLOG_WIKI); | ||||
|             data.put("device", EventLog.DEVICE); | ||||
|             data.put("platform", "Android/" + Build.VERSION.RELEASE); | ||||
|             data.put("appversion", "Android/" + BuildConfig.VERSION_NAME); | ||||
|             fullData.put("event", data); | ||||
|             return new URL(CommonsApplication.EVENTLOG_URL + "?" + Utils.urlEncode(fullData.toString()) + ";"); | ||||
|         } catch (MalformedURLException | JSONException e) { | ||||
|             throw new RuntimeException(e); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // force param disregards user preference | ||||
|     // Use *only* for tracking the user preference change for EventLogging | ||||
|     // Attempting to use anywhere else will cause kitten explosions | ||||
|     public void log(boolean force) { | ||||
|         SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(CommonsApplication.getInstance()); | ||||
|         if (!settings.getBoolean(Prefs.TRACKING_ENABLED, true) && !force) { | ||||
|             return; // User has disabled tracking | ||||
|         } | ||||
|         LogTask logTask = new LogTask(); | ||||
|         logTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, this); | ||||
|     } | ||||
| 
 | ||||
|     public void log() { | ||||
|         log(false); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										12
									
								
								app/src/main/java/fr/free/nrw/commons/mwapi/LogTask.java
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								app/src/main/java/fr/free/nrw/commons/mwapi/LogTask.java
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| package fr.free.nrw.commons.mwapi; | ||||
| 
 | ||||
| import android.os.AsyncTask; | ||||
| 
 | ||||
| import fr.free.nrw.commons.CommonsApplication; | ||||
| 
 | ||||
| class LogTask extends AsyncTask<LogBuilder, Void, Boolean> { | ||||
|     @Override | ||||
|     protected Boolean doInBackground(LogBuilder... logBuilders) { | ||||
|         return CommonsApplication.getInstance().getMWApi().logEvents(logBuilders); | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,46 @@ | |||
| package fr.free.nrw.commons.mwapi; | ||||
| 
 | ||||
| import org.mediawiki.api.ApiResult; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| 
 | ||||
| import in.yuvi.http.fluent.ProgressListener; | ||||
| 
 | ||||
| public interface MediaWikiApi { | ||||
|     String getAuthCookie(); | ||||
| 
 | ||||
|     void setAuthCookie(String authCookie); | ||||
| 
 | ||||
|     String login(String username, String password) throws IOException; | ||||
| 
 | ||||
|     String login(String username, String password, String twoFactorCode) throws IOException; | ||||
| 
 | ||||
|     boolean validateLogin() throws IOException; | ||||
| 
 | ||||
|     String getEditToken() throws IOException; | ||||
| 
 | ||||
|     ApiResult upload(String filename, InputStream file, long dataLength, String pageContents, String editSummary, ProgressListener progressListener) throws IOException; | ||||
| 
 | ||||
|     boolean fileExistsWithName(String fileName) throws IOException; | ||||
| 
 | ||||
|     ApiResult edit(String editToken, String processedPageContent, String filename, String summary) throws IOException; | ||||
| 
 | ||||
|     String findThumbnailByFilename(String filename) throws IOException; | ||||
| 
 | ||||
|     ApiResult fetchMediaByFilename(String filename) throws IOException; | ||||
| 
 | ||||
|     ApiResult searchCategories(int searchCatsLimit, String filterValue) throws IOException; | ||||
| 
 | ||||
|     ApiResult allCategories(int searchCatsLimit, String filter) throws IOException; | ||||
| 
 | ||||
|     ApiResult searchTitles(int searchCatsLimit, String title) throws IOException; | ||||
| 
 | ||||
|     ApiResult logEvents(String user, String lastModified, String queryContinue, int limit) throws IOException; | ||||
| 
 | ||||
|     ApiResult revisionsByFilename(String filename) throws IOException; | ||||
| 
 | ||||
|     ApiResult existingFile(String fileSha1) throws IOException; | ||||
| 
 | ||||
|     boolean logEvents(LogBuilder[] logBuilders); | ||||
| } | ||||
|  | @ -12,9 +12,9 @@ import java.io.IOException; | |||
| import java.util.ArrayList; | ||||
| 
 | ||||
| import fr.free.nrw.commons.CommonsApplication; | ||||
| import fr.free.nrw.commons.MWApi; | ||||
| import fr.free.nrw.commons.R; | ||||
| import fr.free.nrw.commons.contributions.ContributionsActivity; | ||||
| import fr.free.nrw.commons.mwapi.MediaWikiApi; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
| /** | ||||
|  | @ -49,16 +49,13 @@ public class ExistingFileAsync extends AsyncTask<Void, Void, Boolean> { | |||
| 
 | ||||
|     @Override | ||||
|     protected Boolean doInBackground(Void... voids) { | ||||
|         MWApi api = CommonsApplication.getInstance().getMWApi(); | ||||
|         MediaWikiApi api = CommonsApplication.getInstance().getMWApi(); | ||||
|         ApiResult result; | ||||
| 
 | ||||
|         // https://commons.wikimedia.org/w/api.php?action=query&list=allimages&format=xml&aisha1=801957214aba50cb63bb6eb1b0effa50188900ba | ||||
|         try { | ||||
|             result = api.action("query") | ||||
|                     .param("format", "xml") | ||||
|                     .param("list", "allimages") | ||||
|                     .param("aisha1", fileSha1) | ||||
|                     .get(); | ||||
|             String fileSha1 = this.fileSha1; | ||||
|             result = api.existingFile(fileSha1); | ||||
|             Timber.d("Searching Commons API for existing file: %s", result); | ||||
|         } catch (IOException e) { | ||||
|             Timber.e(e, "IO Exception: "); | ||||
|  |  | |||
|  | @ -13,7 +13,6 @@ import android.support.v4.app.NotificationCompat; | |||
| import android.webkit.MimeTypeMap; | ||||
| import android.widget.Toast; | ||||
| 
 | ||||
| import fr.free.nrw.commons.*; | ||||
| import org.mediawiki.api.ApiResult; | ||||
| 
 | ||||
| import java.io.FileNotFoundException; | ||||
|  | @ -25,10 +24,16 @@ import java.util.Set; | |||
| import java.util.regex.Matcher; | ||||
| import java.util.regex.Pattern; | ||||
| 
 | ||||
| import fr.free.nrw.commons.CommonsApplication; | ||||
| import fr.free.nrw.commons.HandlerService; | ||||
| import fr.free.nrw.commons.R; | ||||
| import fr.free.nrw.commons.Utils; | ||||
| import fr.free.nrw.commons.contributions.Contribution; | ||||
| import fr.free.nrw.commons.contributions.ContributionsActivity; | ||||
| import fr.free.nrw.commons.contributions.ContributionsContentProvider; | ||||
| import fr.free.nrw.commons.modifications.ModificationsContentProvider; | ||||
| import fr.free.nrw.commons.mwapi.EventLog; | ||||
| import fr.free.nrw.commons.mwapi.MediaWikiApi; | ||||
| import in.yuvi.http.fluent.ProgressListener; | ||||
| import timber.log.Timber; | ||||
| 
 | ||||
|  | @ -176,7 +181,7 @@ public class UploadService extends HandlerService<Contribution> { | |||
|     } | ||||
| 
 | ||||
|     private void uploadContribution(Contribution contribution) { | ||||
|         MWApi api = app.getMWApi(); | ||||
|         MediaWikiApi api = app.getMWApi(); | ||||
| 
 | ||||
|         ApiResult result; | ||||
|         InputStream file = null; | ||||
|  | @ -304,7 +309,7 @@ public class UploadService extends HandlerService<Contribution> { | |||
|     } | ||||
| 
 | ||||
|     private String findUniqueFilename(String fileName) throws IOException { | ||||
|         MWApi api = app.getMWApi(); | ||||
|         MediaWikiApi api = app.getMWApi(); | ||||
|         String sequenceFileName; | ||||
|         for ( int sequenceNumber = 1; true; sequenceNumber++ ) { | ||||
|             if (sequenceNumber == 1) { | ||||
|  | @ -320,7 +325,7 @@ public class UploadService extends HandlerService<Contribution> { | |||
|                     sequenceFileName = regexMatcher.replaceAll("$1 " + sequenceNumber + "$2"); | ||||
|                 } | ||||
|             } | ||||
|             if ( fileExistsWithName(api, sequenceFileName) || unfinishedUploads.contains(sequenceFileName) ) { | ||||
|             if ( api.fileExistsWithName(sequenceFileName) || unfinishedUploads.contains(sequenceFileName) ) { | ||||
|                 continue; | ||||
|             } else { | ||||
|                 break; | ||||
|  | @ -328,15 +333,4 @@ public class UploadService extends HandlerService<Contribution> { | |||
|         } | ||||
|         return sequenceFileName; | ||||
|     } | ||||
| 
 | ||||
|     private static boolean fileExistsWithName(MWApi api, String fileName) throws IOException { | ||||
|         ApiResult result; | ||||
| 
 | ||||
|         result = api.action("query") | ||||
|                 .param("prop", "imageinfo") | ||||
|                 .param("titles", "File:" + fileName) | ||||
|                 .get(); | ||||
| 
 | ||||
|         return result.getNodes("/api/query/pages/page/imageinfo").size() > 0; | ||||
|     } | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Paul Hawke
						Paul Hawke