diff --git a/commons/AndroidManifest.xml b/commons/AndroidManifest.xml index c60f0119f..daa741489 100644 --- a/commons/AndroidManifest.xml +++ b/commons/AndroidManifest.xml @@ -33,6 +33,9 @@ android:name=".auth.LoginActivity" android:theme="@style/NoTitle" > + + android:resource="@xml/contributions_sync_adapter" /> + + + + + + + + + diff --git a/commons/res/layout/activity_post_upload.xml b/commons/res/layout/activity_post_upload.xml new file mode 100644 index 000000000..752ded6d2 --- /dev/null +++ b/commons/res/layout/activity_post_upload.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/commons/res/values/strings.xml b/commons/res/values/strings.xml index 2835964c5..fdeb21454 100644 --- a/commons/res/values/strings.xml +++ b/commons/res/values/strings.xml @@ -51,6 +51,7 @@ Upload Name this set + Modifications No uploads yet diff --git a/commons/res/xml/syncadapter.xml b/commons/res/xml/contributions_sync_adapter.xml similarity index 100% rename from commons/res/xml/syncadapter.xml rename to commons/res/xml/contributions_sync_adapter.xml diff --git a/commons/res/xml/modifications_sync_adapter.xml b/commons/res/xml/modifications_sync_adapter.xml new file mode 100644 index 000000000..e85d9a6d4 --- /dev/null +++ b/commons/res/xml/modifications_sync_adapter.xml @@ -0,0 +1,9 @@ + + + diff --git a/commons/src/main/java/org/wikimedia/commons/ShareActivity.java b/commons/src/main/java/org/wikimedia/commons/ShareActivity.java index 14c009026..c0b4e2d09 100644 --- a/commons/src/main/java/org/wikimedia/commons/ShareActivity.java +++ b/commons/src/main/java/org/wikimedia/commons/ShareActivity.java @@ -14,6 +14,7 @@ import android.view.*; import org.wikimedia.commons.contributions.*; import org.wikimedia.commons.auth.*; +import org.wikimedia.commons.modifications.PostUploadActivity; public class ShareActivity extends AuthenticatedActivity { @@ -64,11 +65,13 @@ public class ShareActivity extends AuthenticatedActivity { @Override protected void onPostExecute(Contribution contribution) { super.onPostExecute(contribution); + Intent postUploadIntent = new Intent(ShareActivity.this, PostUploadActivity.class); + postUploadIntent.putExtra(PostUploadActivity.EXTRA_MEDIA_URI, contribution.getContentUri()); + startActivity(postUploadIntent); finish(); } } - @Override public void onBackPressed() { super.onBackPressed(); diff --git a/commons/src/main/java/org/wikimedia/commons/auth/LoginActivity.java b/commons/src/main/java/org/wikimedia/commons/auth/LoginActivity.java index 1455e0c08..7b1ac8553 100644 --- a/commons/src/main/java/org/wikimedia/commons/auth/LoginActivity.java +++ b/commons/src/main/java/org/wikimedia/commons/auth/LoginActivity.java @@ -16,6 +16,7 @@ import android.support.v4.app.NavUtils; import org.wikimedia.commons.*; import org.wikimedia.commons.EventLog; import org.wikimedia.commons.contributions.*; +import org.wikimedia.commons.modifications.ModificationsContentProvider; public class LoginActivity extends AccountAuthenticatorActivity { @@ -64,6 +65,7 @@ public class LoginActivity extends AccountAuthenticatorActivity { } // FIXME: If the user turns it off, it shouldn't be auto turned back on ContentResolver.setSyncAutomatically(account, ContributionsContentProvider.AUTHORITY, true); // Enable sync by default! + ContentResolver.setSyncAutomatically(account, ModificationsContentProvider.AUTHORITY, true); // Enable sync by default! context.finish(); } else { int response; diff --git a/commons/src/main/java/org/wikimedia/commons/contributions/Contribution.java b/commons/src/main/java/org/wikimedia/commons/contributions/Contribution.java index 71a70f1d2..20240a6c0 100644 --- a/commons/src/main/java/org/wikimedia/commons/contributions/Contribution.java +++ b/commons/src/main/java/org/wikimedia/commons/contributions/Contribution.java @@ -297,8 +297,11 @@ public class Contribution extends Media { onUpdate(db, from, to); return; } - db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); - onCreate(db); + if(from == 3) { + // Do nothing + from++; + return; + } } } } diff --git a/commons/src/main/java/org/wikimedia/commons/contributions/ContributionsContentProvider.java b/commons/src/main/java/org/wikimedia/commons/contributions/ContributionsContentProvider.java index 438990fda..acb7c62a8 100644 --- a/commons/src/main/java/org/wikimedia/commons/contributions/ContributionsContentProvider.java +++ b/commons/src/main/java/org/wikimedia/commons/contributions/ContributionsContentProvider.java @@ -45,16 +45,27 @@ public class ContributionsContentProvider extends ContentProvider{ int uriType = uriMatcher.match(uri); + SQLiteDatabase db = dbOpenHelper.getReadableDatabase(); + Cursor cursor; + switch(uriType) { case CONTRIBUTIONS: + cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder); + break; + case CONTRIBUTIONS_ID: + cursor = queryBuilder.query(db, + Contribution.Table.ALL_FIELDS, + "_id = ?", + new String[] { uri.getLastPathSegment() }, + null, + null, + sortOrder + ); break; default: throw new IllegalArgumentException("Unknown URI" + uri); } - SQLiteDatabase db = dbOpenHelper.getReadableDatabase(); - - Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder); cursor.setNotificationUri(getContext().getContentResolver(), uri); return cursor; diff --git a/commons/src/main/java/org/wikimedia/commons/data/DBOpenHelper.java b/commons/src/main/java/org/wikimedia/commons/data/DBOpenHelper.java index e328a31d9..011baa429 100644 --- a/commons/src/main/java/org/wikimedia/commons/data/DBOpenHelper.java +++ b/commons/src/main/java/org/wikimedia/commons/data/DBOpenHelper.java @@ -4,11 +4,12 @@ import android.content.*; import android.database.sqlite.*; import org.wikimedia.commons.contributions.*; +import org.wikimedia.commons.modifications.ModifierSequence; public class DBOpenHelper extends SQLiteOpenHelper{ private static final String DATABASE_NAME = "commons.db"; - private static final int DATABASE_VERSION = 3; + private static final int DATABASE_VERSION = 4; public DBOpenHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); @@ -17,10 +18,12 @@ public class DBOpenHelper extends SQLiteOpenHelper{ @Override public void onCreate(SQLiteDatabase sqLiteDatabase) { Contribution.Table.onCreate(sqLiteDatabase); + ModifierSequence.Table.onCreate(sqLiteDatabase); } @Override public void onUpgrade(SQLiteDatabase sqLiteDatabase, int from, int to) { Contribution.Table.onUpdate(sqLiteDatabase, from, to); + ModifierSequence.Table.onUpdate(sqLiteDatabase, from, to); } } diff --git a/commons/src/main/java/org/wikimedia/commons/modifications/CategoryModifier.java b/commons/src/main/java/org/wikimedia/commons/modifications/CategoryModifier.java new file mode 100644 index 000000000..00838ade3 --- /dev/null +++ b/commons/src/main/java/org/wikimedia/commons/modifications/CategoryModifier.java @@ -0,0 +1,49 @@ +package org.wikimedia.commons.modifications; + +import android.os.Bundle; +import android.os.Parcel; +import android.text.TextUtils; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.*; + +public class CategoryModifier extends PageModifier { + + + public static String PARAM_CATEGORIES = "categories"; + + public static String MODIFIER_NAME = "CategoriesModifier"; + + public CategoryModifier(String... categories) { + super(MODIFIER_NAME); + JSONArray categoriesArray = new JSONArray(); + for(String category: categories) { + categoriesArray.put(category); + } + try { + params.putOpt(PARAM_CATEGORIES, categoriesArray); + } catch (JSONException e) { + throw new RuntimeException(e); + } + } + + public CategoryModifier(JSONObject data) { + super(MODIFIER_NAME); + this.params = data; + } + + @Override + public String doModification(String pageName, String pageContents) { + JSONArray categories; + categories = params.optJSONArray(PARAM_CATEGORIES); + + StringBuffer categoriesString = new StringBuffer(); + for(int i=0; i < categories.length(); i++) { + String category = categories.optString(i); + categoriesString.append("\n[[Category:").append(category).append("]]"); + } + return pageContents + categoriesString.toString(); + } +} diff --git a/commons/src/main/java/org/wikimedia/commons/modifications/ModificationsContentProvider.java b/commons/src/main/java/org/wikimedia/commons/modifications/ModificationsContentProvider.java new file mode 100644 index 000000000..dc7beff75 --- /dev/null +++ b/commons/src/main/java/org/wikimedia/commons/modifications/ModificationsContentProvider.java @@ -0,0 +1,160 @@ +package org.wikimedia.commons.modifications; + +import android.content.*; +import android.database.*; +import android.database.sqlite.*; +import android.net.*; +import android.text.*; +import android.util.*; + +import org.wikimedia.commons.*; +import org.wikimedia.commons.data.*; + +public class ModificationsContentProvider extends ContentProvider{ + + private static final int MODIFICATIONS = 1; + private static final int MODIFICATIONS_ID = 2; + + public static final String AUTHORITY = "org.wikimedia.commons.modifications.contentprovider"; + private static final String BASE_PATH = "modifications"; + + public static final Uri BASE_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH); + + private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); + static { + uriMatcher.addURI(AUTHORITY, BASE_PATH, MODIFICATIONS); + uriMatcher.addURI(AUTHORITY, BASE_PATH + "/#", MODIFICATIONS_ID); + } + + + public static Uri uriForId(int id) { + return Uri.parse(BASE_URI.toString() + "/" + id); + } + + private DBOpenHelper dbOpenHelper; + @Override + public boolean onCreate() { + dbOpenHelper = ((CommonsApplication)this.getContext().getApplicationContext()).getDbOpenHelper(); + return false; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { + SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder(); + queryBuilder.setTables(ModifierSequence.Table.TABLE_NAME); + + int uriType = uriMatcher.match(uri); + + switch(uriType) { + case MODIFICATIONS: + break; + default: + throw new IllegalArgumentException("Unknown URI" + uri); + } + + SQLiteDatabase db = dbOpenHelper.getReadableDatabase(); + + Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder); + cursor.setNotificationUri(getContext().getContentResolver(), uri); + + return cursor; + } + + @Override + public String getType(Uri uri) { + return null; + } + + @Override + public Uri insert(Uri uri, ContentValues contentValues) { + int uriType = uriMatcher.match(uri); + SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase(); + long id = 0; + switch (uriType) { + case MODIFICATIONS: + id = sqlDB.insert(ModifierSequence.Table.TABLE_NAME, null, contentValues); + break; + default: + throw new IllegalArgumentException("Unknown URI: " + uri); + } + getContext().getContentResolver().notifyChange(uri, null); + return Uri.parse(BASE_URI + "/" + id); + } + + @Override + public int delete(Uri uri, String s, String[] strings) { + int uriType = uriMatcher.match(uri); + SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase(); + switch (uriType) { + case MODIFICATIONS_ID: + String id = uri.getLastPathSegment(); + sqlDB.delete(ModifierSequence.Table.TABLE_NAME, + "_id = ?", + new String[] { id } + ); + return 1; + default: + throw new IllegalArgumentException("Unknown URI: " + uri); + } + } + + @Override + public int bulkInsert(Uri uri, ContentValues[] values) { + Log.d("Commons", "Hello, bulk insert!"); + int uriType = uriMatcher.match(uri); + SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase(); + sqlDB.beginTransaction(); + switch (uriType) { + case MODIFICATIONS: + for(ContentValues value: values) { + Log.d("Commons", "Inserting! " + value.toString()); + sqlDB.insert(ModifierSequence.Table.TABLE_NAME, null, value); + } + break; + default: + throw new IllegalArgumentException("Unknown URI: " + uri); + } + sqlDB.setTransactionSuccessful(); + sqlDB.endTransaction(); + getContext().getContentResolver().notifyChange(uri, null); + return values.length; + } + + @Override + public int update(Uri uri, ContentValues contentValues, String selection, String[] selectionArgs) { + /* + SQL Injection warnings: First, note that we're not exposing this to the outside world (exported="false") + Even then, we should make sure to sanitize all user input appropriately. Input that passes through ContentValues + should be fine. So only issues are those that pass in via concating. + + In here, the only concat created argument is for id. It is cast to an int, and will error out otherwise. + */ + int uriType = uriMatcher.match(uri); + SQLiteDatabase sqlDB = dbOpenHelper.getWritableDatabase(); + int rowsUpdated = 0; + switch (uriType) { + case MODIFICATIONS: + rowsUpdated = sqlDB.update(ModifierSequence.Table.TABLE_NAME, + contentValues, + selection, + selectionArgs); + break; + case MODIFICATIONS_ID: + int id = Integer.valueOf(uri.getLastPathSegment()); + + if (TextUtils.isEmpty(selection)) { + rowsUpdated = sqlDB.update(ModifierSequence.Table.TABLE_NAME, + contentValues, + ModifierSequence.Table.COLUMN_ID + " = ?", + new String[] { String.valueOf(id) } ); + } else { + throw new IllegalArgumentException("Parameter `selection` should be empty when updating an ID"); + } + break; + default: + throw new IllegalArgumentException("Unknown URI: " + uri + " with type " + uriType); + } + getContext().getContentResolver().notifyChange(uri, null); + return rowsUpdated; + } +} diff --git a/commons/src/main/java/org/wikimedia/commons/modifications/ModificationsSyncAdapter.java b/commons/src/main/java/org/wikimedia/commons/modifications/ModificationsSyncAdapter.java new file mode 100644 index 000000000..12b130398 --- /dev/null +++ b/commons/src/main/java/org/wikimedia/commons/modifications/ModificationsSyncAdapter.java @@ -0,0 +1,138 @@ +package org.wikimedia.commons.modifications; + +import android.accounts.AccountManager; +import android.accounts.AuthenticatorException; +import android.accounts.OperationCanceledException; +import android.content.*; +import android.database.Cursor; +import android.os.RemoteException; +import android.text.TextUtils; +import android.util.Log; +import android.accounts.Account; +import android.os.Bundle; + +import java.io.*; +import java.util.*; + +import org.mediawiki.api.*; +import org.wikimedia.commons.Utils; +import org.wikimedia.commons.*; +import org.wikimedia.commons.contributions.Contribution; +import org.wikimedia.commons.contributions.ContributionsContentProvider; + + +public class ModificationsSyncAdapter extends AbstractThreadedSyncAdapter { + + public ModificationsSyncAdapter(Context context, boolean autoInitialize) { + super(context, autoInitialize); + } + + @Override + 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! + + Cursor allModifications; + try { + allModifications = contentProviderClient.query(ModificationsContentProvider.BASE_URI, null, null, null, null); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + + // Exit early if nothing to do + if(allModifications == null || allModifications.getCount() == 0) { + Log.d("Commons", "No modifications to perform"); + return; + } + + CommonsApplication app = (CommonsApplication)getContext().getApplicationContext(); + String authCookie; + try { + authCookie = AccountManager.get(app).blockingGetAuthToken(account, "", false); + } catch (OperationCanceledException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (AuthenticatorException e) { + throw new RuntimeException(e); + } + + MWApi api = app.getApi(); + api.setAuthCookie(authCookie); + String editToken; + + ApiResult requestResult, responseResult; + try { + editToken = api.getEditToken(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + + allModifications.moveToFirst(); + + Log.d("Commons", "Found " + allModifications.getCount() + " modifications to execute"); + + ContentProviderClient contributionsClient = null; + try { + contributionsClient = getContext().getContentResolver().acquireContentProviderClient(ContributionsContentProvider.AUTHORITY); + + while(!allModifications.isAfterLast()) { + ModifierSequence sequence = ModifierSequence.fromCursor(allModifications); + sequence.setContentProviderClient(contentProviderClient); + Contribution contrib; + + Cursor contributionCursor; + try { + contributionCursor = contributionsClient.query(sequence.getMediaUri(), null, null, null, null); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + contributionCursor.moveToFirst(); + contrib = Contribution.fromCursor(contributionCursor); + + if(contrib.getState() == Contribution.STATE_COMPLETED) { + + try { + requestResult = api.action("query") + .param("prop", "revisions") + .param("rvprop", "timestamp|content") + .param("titles", contrib.getFilename()) + .get(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + Log.d("Commons", "Page content is " + Utils.getStringFromDOM(requestResult.getDocument())); + String pageContent = requestResult.getString("/api/query/pages/page/revisions/rev"); + String processedPageContent = sequence.executeModifications(contrib.getFilename(), pageContent); + + try { + responseResult = api.action("edit") + .param("title", contrib.getFilename()) + .param("token", editToken) + .param("text", processedPageContent) + .post(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + Log.d("Commons", "Response is" + Utils.getStringFromDOM(responseResult.getDocument())); + + String result = responseResult.getString("/api/edit/@result"); + if(!result.equals("Success")) { + throw new RuntimeException(); + } + + sequence.delete(); + allModifications.moveToNext(); + } + + } + } finally { + if(contributionsClient != null) { + contributionsClient.release(); + } + + } + } +} diff --git a/commons/src/main/java/org/wikimedia/commons/modifications/ModificationsSyncService.java b/commons/src/main/java/org/wikimedia/commons/modifications/ModificationsSyncService.java new file mode 100644 index 000000000..86a80fa94 --- /dev/null +++ b/commons/src/main/java/org/wikimedia/commons/modifications/ModificationsSyncService.java @@ -0,0 +1,26 @@ +package org.wikimedia.commons.modifications; + +import android.app.*; +import android.content.*; +import android.os.*; + +public class ModificationsSyncService extends Service { + + private static final Object sSyncAdapterLock = new Object(); + + private static ModificationsSyncAdapter sSyncAdapter = null; + + @Override + public void onCreate() { + synchronized (sSyncAdapterLock) { + if (sSyncAdapter == null) { + sSyncAdapter = new ModificationsSyncAdapter(getApplicationContext(), true); + } + } + } + + @Override + public IBinder onBind(Intent intent) { + return sSyncAdapter.getSyncAdapterBinder(); + } +} diff --git a/commons/src/main/java/org/wikimedia/commons/modifications/ModifierSequence.java b/commons/src/main/java/org/wikimedia/commons/modifications/ModifierSequence.java new file mode 100644 index 000000000..c58330185 --- /dev/null +++ b/commons/src/main/java/org/wikimedia/commons/modifications/ModifierSequence.java @@ -0,0 +1,142 @@ +package org.wikimedia.commons.modifications; + +import android.content.ContentProviderClient; +import android.content.ContentValues; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.net.Uri; +import android.os.RemoteException; +import android.text.TextUtils; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.wikimedia.commons.contributions.ContributionsContentProvider; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; + +public class ModifierSequence { + private Uri mediaUri; + private ArrayList modifiers; + private Uri contentUri; + private ContentProviderClient client; + + public ModifierSequence(Uri mediaUri) { + this.mediaUri = mediaUri; + modifiers = new ArrayList(); + } + + public ModifierSequence(Uri mediaUri, JSONObject data) { + this(mediaUri); + JSONArray modifiersJSON = data.optJSONArray("modifiers"); + for(int i=0; i< modifiersJSON.length(); i++) { + modifiers.add(PageModifier.fromJSON(modifiersJSON.optJSONObject(i))); + } + } + + public Uri getMediaUri() { + return mediaUri; + } + + public void queueModifier(PageModifier modifier) { + modifiers.add(modifier); + } + + public String executeModifications(String pageName, String pageContents) { + for(PageModifier modifier: modifiers) { + pageContents = modifier.doModification(pageName, pageContents); + } + return pageContents; + } + + public JSONObject toJSON() { + JSONObject data = new JSONObject(); + try { + JSONArray modifiersJSON = new JSONArray(); + for(PageModifier modifier: modifiers) { + modifiersJSON.put(modifier.toJSON()); + } + data.put("modifiers", modifiersJSON); + return data; + } catch (JSONException e) { + throw new RuntimeException(e); + } + } + + public ContentValues toContentValues() { + ContentValues cv = new ContentValues(); + cv.put(Table.COLUMN_MEDIA_URI, mediaUri.toString()); + cv.put(Table.COLUMN_DATA, toJSON().toString()); + return cv; + } + + public static ModifierSequence fromCursor(Cursor cursor) { + // Hardcoding column positions! + ModifierSequence ms = null; + try { + ms = new ModifierSequence(Uri.parse(cursor.getString(1)), new JSONObject(cursor.getString(2))); + } catch (JSONException e) { + throw new RuntimeException(e); + } + ms.contentUri = ModificationsContentProvider.uriForId(cursor.getInt(0)); + + return ms; + } + + public void save() { + try { + if(contentUri == null) { + contentUri = client.insert(ModificationsContentProvider.BASE_URI, this.toContentValues()); + } else { + client.update(contentUri, toContentValues(), null, null); + } + } catch(RemoteException e) { + throw new RuntimeException(e); + } + } + + public void delete() { + try { + client.delete(contentUri, null, null); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + public void setContentProviderClient(ContentProviderClient client) { + this.client = client; + } + + public static class Table { + public static final String TABLE_NAME = "modifications"; + + public static final String COLUMN_ID = "_id"; + public static final String COLUMN_MEDIA_URI = "mediauri"; + public static final String COLUMN_DATA = "data"; + + // NOTE! KEEP IN SAME ORDER AS THEY ARE DEFINED UP THERE. HELPS HARD CODE COLUMN INDICES. + public static final String[] ALL_FIELDS = { + COLUMN_ID, + COLUMN_MEDIA_URI, + COLUMN_DATA + }; + + + private static final String CREATE_TABLE_STATEMENT = "CREATE TABLE " + TABLE_NAME + " (" + + "_id INTEGER PRIMARY KEY," + + "mediauri STRING," + + "data STRING" + + ");"; + + + public static void onCreate(SQLiteDatabase db) { + db.execSQL(CREATE_TABLE_STATEMENT); + } + + public static void onUpdate(SQLiteDatabase db, int from, int to) { + db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); + onCreate(db); + } + } +} diff --git a/commons/src/main/java/org/wikimedia/commons/modifications/PageModifier.java b/commons/src/main/java/org/wikimedia/commons/modifications/PageModifier.java new file mode 100644 index 000000000..fe09307a9 --- /dev/null +++ b/commons/src/main/java/org/wikimedia/commons/modifications/PageModifier.java @@ -0,0 +1,37 @@ +package org.wikimedia.commons.modifications; + +import android.os.Bundle; +import org.json.JSONException; +import org.json.JSONObject; + +public abstract class PageModifier { + + public static PageModifier fromJSON(JSONObject data) { + String name = data.optString("name"); + if(name.equals(CategoryModifier.MODIFIER_NAME)) { + return new CategoryModifier(data.optJSONObject("data")); + } + return null; + } + + protected String name; + protected JSONObject params; + + protected PageModifier(String name) { + this.name = name; + params = new JSONObject(); + } + + public abstract String doModification(String pageName, String pageContents); + + public JSONObject toJSON() { + JSONObject data = new JSONObject(); + try { + data.putOpt("name", name); + data.put("data", params); + } catch (JSONException e) { + throw new RuntimeException(e); + } + return data; + } +} diff --git a/commons/src/main/java/org/wikimedia/commons/modifications/PostUploadActivity.java b/commons/src/main/java/org/wikimedia/commons/modifications/PostUploadActivity.java new file mode 100644 index 000000000..0ff97a6b4 --- /dev/null +++ b/commons/src/main/java/org/wikimedia/commons/modifications/PostUploadActivity.java @@ -0,0 +1,28 @@ +package org.wikimedia.commons.modifications; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.net.Uri; +import android.os.Bundle; +import android.os.IBinder; +import org.wikimedia.commons.HandlerService; +import org.wikimedia.commons.R; +import org.wikimedia.commons.UploadService; + +public class PostUploadActivity extends Activity { + public static String EXTRA_MEDIA_URI = "org.wikimedia.commons.modifications.PostUploadActivity.mediauri"; + + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_post_upload); + Uri mediaUri = getIntent().getParcelableExtra(EXTRA_MEDIA_URI); + ModifierSequence testSequence = new ModifierSequence(mediaUri); + testSequence.queueModifier(new CategoryModifier("Hello, World!")); + testSequence.setContentProviderClient(getContentResolver().acquireContentProviderClient(ModificationsContentProvider.AUTHORITY)); + testSequence.save(); + + } +} \ No newline at end of file