mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 20:33:53 +01:00
Initial cut of EventLogging support
This commit is contained in:
parent
27ad2a6443
commit
5271cc57d1
7 changed files with 175 additions and 4 deletions
|
|
@ -56,6 +56,10 @@ public class CommonsApplication extends Application {
|
|||
private Account currentAccount = null; // Unlike a savings account...
|
||||
public static final String API_URL = "https://test.wikipedia.org/w/api.php";
|
||||
public static final String IMAGE_URL_BASE = "https://upload.wikimedia.org/wikipedia/test";
|
||||
public static final String EVENTLOG_URL = "https://bits.wikimedia.org/event.gif";
|
||||
|
||||
public static final Object[] EVENT_UPLOAD_ATTEMPT = {"MobileAppUploadAttempts", 5241449};
|
||||
public static final Object[] EVENT_LOGIN_ATTEMPT = {"MobileAppLoginAttempts", 5240393};
|
||||
|
||||
public static final String DEFAULT_EDIT_SUMMARY = "Uploaded using Android Commons app";
|
||||
|
||||
|
|
|
|||
99
commons/src/main/java/org/wikimedia/commons/EventLog.java
Normal file
99
commons/src/main/java/org/wikimedia/commons/EventLog.java
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
package org.wikimedia.commons;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import de.akquinet.android.androlog.Log;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
public class EventLog {
|
||||
private static class LogTask extends AsyncTask<LogBuilder, Void, Boolean> {
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(LogBuilder... logBuilders) {
|
||||
|
||||
boolean allSuccess = true;
|
||||
|
||||
// Going to simply use the default URLConnection.
|
||||
// This should be as lightweight as possible, and doesn't really do any fancy stuff
|
||||
for(LogBuilder logBuilder: logBuilders) {
|
||||
HttpURLConnection conn;
|
||||
try {
|
||||
URL url = logBuilder.toUrl();
|
||||
conn = (HttpURLConnection) url.openConnection();
|
||||
int respCode = conn.getResponseCode();
|
||||
if(respCode != 204) {
|
||||
allSuccess = false;
|
||||
}
|
||||
Log.d("Commons", "EventLog hit " + url.toString());
|
||||
|
||||
} catch (IOException e) {
|
||||
// Probably just ignore for now. Can be much more robust with a service, etc later on.
|
||||
// But in the interest of debugging
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return allSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
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", "commonswiki");
|
||||
fullData.put("isValid", true); // Hehe
|
||||
fullData.put("event", data);
|
||||
return new URL(CommonsApplication.EVENTLOG_URL + "?" + Utils.urlEncode(fullData.toString()) + ";");
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (JSONException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void log() {
|
||||
LogTask logTask = new LogTask();
|
||||
Utils.executeAsyncTask(logTask, this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static LogBuilder schema(String schema, long revision) {
|
||||
return new LogBuilder(schema, revision);
|
||||
}
|
||||
|
||||
public static LogBuilder schema(Object[] schema_rev) {
|
||||
if(schema_rev.length != 2) {
|
||||
throw new IllegalArgumentException("Needs an object array with schema as first param and revision as second");
|
||||
}
|
||||
return schema((String)schema_rev[0], (Long)schema_rev[1]);
|
||||
}
|
||||
}
|
||||
|
|
@ -29,9 +29,19 @@ public class ShareActivity extends AuthenticatedActivity {
|
|||
private Button uploadButton;
|
||||
private EditText titleEdit;
|
||||
private EditText descEdit;
|
||||
|
||||
|
||||
private Uri mediaUri;
|
||||
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
super.onBackPressed();
|
||||
EventLog.schema(CommonsApplication.EVENT_UPLOAD_ATTEMPT)
|
||||
.param("username", app.getCurrentAccount().name)
|
||||
.param("source", getIntent().getStringExtra(UploadService.EXTRA_SOURCE))
|
||||
.param("result", "cancelled")
|
||||
.log();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAuthCookieAcquired(String authCookie) {
|
||||
super.onAuthCookieAcquired(authCookie);
|
||||
|
|
@ -42,6 +52,12 @@ public class ShareActivity extends AuthenticatedActivity {
|
|||
|
||||
if(intent.getAction().equals(Intent.ACTION_SEND)) {
|
||||
mediaUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
|
||||
final String source;
|
||||
if(intent.hasExtra(UploadService.EXTRA_SOURCE)) {
|
||||
source = intent.getStringExtra(UploadService.EXTRA_SOURCE);
|
||||
} else {
|
||||
source = Contribution.SOURCE_EXTERNAL;
|
||||
}
|
||||
|
||||
final String mimeType = intent.getType();
|
||||
if(mimeType.startsWith("image/")) {
|
||||
|
|
@ -58,6 +74,7 @@ public class ShareActivity extends AuthenticatedActivity {
|
|||
uploadIntent.putExtra(UploadService.EXTRA_DESCRIPTION, descEdit.getText().toString());
|
||||
uploadIntent.putExtra(UploadService.EXTRA_MIMETYPE, mimeType);
|
||||
uploadIntent.putExtra(UploadService.EXTRA_EDIT_SUMMARY, "Mobile upload from Wikimedia Commons Android app");
|
||||
uploadIntent.putExtra(UploadService.EXTRA_SOURCE, source);
|
||||
startService(uploadIntent);
|
||||
Toast startingToast = Toast.makeText(that, R.string.uploading_started, Toast.LENGTH_LONG);
|
||||
startingToast.show();
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ public class UploadService extends HandlerService<Contribution> {
|
|||
public static final int ACTION_UPLOAD_FILE = 1;
|
||||
|
||||
public static final String ACTION_START_SERVICE = EXTRA_PREFIX + ".upload";
|
||||
public static final String EXTRA_SOURCE = EXTRA_PREFIX + ".source";
|
||||
|
||||
private NotificationManager notificationManager;
|
||||
private ContentProviderClient contributionsProviderClient;
|
||||
|
|
@ -118,6 +119,7 @@ public class UploadService extends HandlerService<Contribution> {
|
|||
String description = intent.getStringExtra(EXTRA_DESCRIPTION);
|
||||
String editSummary = intent.getStringExtra(EXTRA_EDIT_SUMMARY);
|
||||
String mimeType = intent.getStringExtra(EXTRA_MIMETYPE);
|
||||
String source = intent.getStringExtra(EXTRA_SOURCE);
|
||||
Date dateCreated = null;
|
||||
|
||||
Long length = null;
|
||||
|
|
@ -144,6 +146,7 @@ public class UploadService extends HandlerService<Contribution> {
|
|||
Removed Audio implementationf or now
|
||||
} */
|
||||
Contribution contribution = new Contribution(mediaUri, null, filename, description, length, dateCreated, null, app.getCurrentAccount().name, editSummary);
|
||||
contribution.setSource(source);
|
||||
return contribution;
|
||||
}
|
||||
|
||||
|
|
@ -271,7 +274,14 @@ public class UploadService extends HandlerService<Contribution> {
|
|||
|
||||
String resultStatus = result.getString("/api/upload/@result");
|
||||
if(!resultStatus.equals("Success")) {
|
||||
String errorCode = result.getString("/api/error/@code");
|
||||
showFailedNotification(contribution);
|
||||
EventLog.schema(CommonsApplication.EVENT_UPLOAD_ATTEMPT)
|
||||
.param("username", app.getCurrentAccount().name)
|
||||
.param("source", contribution.getSource())
|
||||
.param("result", errorCode)
|
||||
.param("filename", contribution.getFilename())
|
||||
.log();
|
||||
} else {
|
||||
Date dateUploaded = null;
|
||||
dateUploaded = Utils.parseMWDate(result.getString("/api/upload/imageinfo/@timestamp"));
|
||||
|
|
@ -282,6 +292,13 @@ public class UploadService extends HandlerService<Contribution> {
|
|||
contribution.setState(Contribution.STATE_COMPLETED);
|
||||
contribution.setDateUploaded(dateUploaded);
|
||||
contribution.save();
|
||||
|
||||
EventLog.schema(CommonsApplication.EVENT_UPLOAD_ATTEMPT)
|
||||
.param("username", app.getCurrentAccount().name)
|
||||
.param("source", contribution.getSource()) //FIXME
|
||||
.param("filename", contribution.getFilename())
|
||||
.param("result", "success")
|
||||
.log();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@ package org.wikimedia.commons;
|
|||
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import org.apache.commons.codec.EncoderException;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.codec.net.URLCodec;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import javax.xml.transform.TransformerConfigurationException;
|
||||
|
|
@ -90,6 +92,16 @@ public class Utils {
|
|||
}
|
||||
}
|
||||
|
||||
private static final URLCodec urlCodec = new URLCodec();
|
||||
|
||||
public static String urlEncode(String url) {
|
||||
try {
|
||||
return urlCodec.encode(url);
|
||||
} catch (EncoderException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static long countBytes(InputStream stream) throws IOException {
|
||||
long count = 0;
|
||||
BufferedInputStream bis = new BufferedInputStream(stream);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import android.net.*;
|
|||
import android.os.RemoteException;
|
||||
import android.text.TextUtils;
|
||||
import org.wikimedia.commons.CommonsApplication;
|
||||
import org.wikimedia.commons.EventLog;
|
||||
import org.wikimedia.commons.Media;
|
||||
|
||||
public class Contribution extends Media {
|
||||
|
|
@ -21,8 +22,15 @@ public class Contribution extends Media {
|
|||
public static final int STATE_QUEUED = 2;
|
||||
public static final int STATE_IN_PROGRESS = 3;
|
||||
|
||||
public static final String SOURCE_CAMERA = "camera";
|
||||
public static final String SOURCE_GALLERY = "gallery";
|
||||
public static final String SOURCE_EXTERNAL = "external";
|
||||
|
||||
private ContentProviderClient client;
|
||||
private Uri contentUri;
|
||||
private String source;
|
||||
|
||||
public EventLog.LogBuilder event;
|
||||
|
||||
public long getTransferred() {
|
||||
return transferred;
|
||||
|
|
@ -132,6 +140,7 @@ public class Contribution extends Media {
|
|||
cv.put(Table.COLUMN_TIMESTAMP, getTimestamp().getTime());
|
||||
cv.put(Table.COLUMN_STATE, getState());
|
||||
cv.put(Table.COLUMN_TRANSFERRED, transferred);
|
||||
cv.put(Table.COLUMN_SOURCE, source);
|
||||
return cv;
|
||||
}
|
||||
|
||||
|
|
@ -159,9 +168,17 @@ public class Contribution extends Media {
|
|||
c.dataLength = cursor.getLong(6);
|
||||
c.dateUploaded = cursor.getLong(7) == 0 ? null : new Date(cursor.getLong(7));
|
||||
c.transferred = cursor.getLong(8);
|
||||
c.source = cursor.getString(9);
|
||||
return c;
|
||||
}
|
||||
|
||||
public String getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public void setSource(String source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
|
||||
public static class Table {
|
||||
|
|
@ -176,6 +193,7 @@ public class Contribution extends Media {
|
|||
public static final String COLUMN_LENGTH = "length";
|
||||
public static final String COLUMN_UPLOADED = "uploaded";
|
||||
public static final String COLUMN_TRANSFERRED = "transferred"; // Currently transferred number of bytes
|
||||
public static final String COLUMN_SOURCE = "source";
|
||||
|
||||
// NOTE! KEEP IN SAME ORDER AS THEY ARE DEFINED UP THERE. HELPS HARD CODE COLUMN INDICES.
|
||||
public static final String[] ALL_FIELDS = {
|
||||
|
|
@ -187,7 +205,8 @@ public class Contribution extends Media {
|
|||
COLUMN_STATE,
|
||||
COLUMN_LENGTH,
|
||||
COLUMN_UPLOADED,
|
||||
COLUMN_TRANSFERRED
|
||||
COLUMN_TRANSFERRED,
|
||||
COLUMN_SOURCE
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -200,7 +219,8 @@ public class Contribution extends Media {
|
|||
+ "timestamp INTEGER,"
|
||||
+ "state INTEGER,"
|
||||
+ "length INTEGER,"
|
||||
+ "transferred INTEGER"
|
||||
+ "transferred INTEGER,"
|
||||
+ "source STRING"
|
||||
+ ");";
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -226,6 +226,7 @@ public class ContributionsActivity extends AuthenticatedActivity implements Load
|
|||
Log.d("Commons", "Type is " + data.getType() + " Uri is " + data.getData());
|
||||
shareIntent.setType("image/*"); //FIXME: Find out appropriate mime type
|
||||
shareIntent.putExtra(Intent.EXTRA_STREAM, data.getData());
|
||||
shareIntent.putExtra(UploadService.EXTRA_SOURCE, Contribution.SOURCE_GALLERY);
|
||||
startActivity(shareIntent);
|
||||
}
|
||||
break;
|
||||
|
|
@ -236,6 +237,7 @@ public class ContributionsActivity extends AuthenticatedActivity implements Load
|
|||
Log.d("Commons", "Uri is " + lastGeneratedCaptureURI);
|
||||
shareIntent.setType("image/jpeg"); //FIXME: Find out appropriate mime type
|
||||
shareIntent.putExtra(Intent.EXTRA_STREAM, lastGeneratedCaptureURI);
|
||||
shareIntent.putExtra(UploadService.EXTRA_SOURCE, Contribution.SOURCE_CAMERA);
|
||||
startActivity(shareIntent);
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue