mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-27 04:43:54 +01:00
Merge pull request #1022 from psh/extract-and-test-modifier-sequence-db
Extracted and tested the database interactions from ModifierSequence
This commit is contained in:
commit
feb435304f
9 changed files with 330 additions and 122 deletions
|
|
@ -27,7 +27,7 @@ import fr.free.nrw.commons.data.DBOpenHelper;
|
||||||
import fr.free.nrw.commons.di.CommonsApplicationComponent;
|
import fr.free.nrw.commons.di.CommonsApplicationComponent;
|
||||||
import fr.free.nrw.commons.di.CommonsApplicationModule;
|
import fr.free.nrw.commons.di.CommonsApplicationModule;
|
||||||
import fr.free.nrw.commons.di.DaggerCommonsApplicationComponent;
|
import fr.free.nrw.commons.di.DaggerCommonsApplicationComponent;
|
||||||
import fr.free.nrw.commons.modifications.ModifierSequence;
|
import fr.free.nrw.commons.modifications.ModifierSequenceDao;
|
||||||
import fr.free.nrw.commons.utils.FileUtils;
|
import fr.free.nrw.commons.utils.FileUtils;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
@ -168,7 +168,7 @@ public class CommonsApplication extends DaggerApplication {
|
||||||
dbOpenHelper.getReadableDatabase().close();
|
dbOpenHelper.getReadableDatabase().close();
|
||||||
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
|
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
|
||||||
|
|
||||||
ModifierSequence.Table.onDelete(db);
|
ModifierSequenceDao.Table.onDelete(db);
|
||||||
CategoryDao.Table.onDelete(db);
|
CategoryDao.Table.onDelete(db);
|
||||||
ContributionDao.Table.onDelete(db);
|
ContributionDao.Table.onDelete(db);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
import android.database.sqlite.SQLiteOpenHelper;
|
||||||
|
|
||||||
import fr.free.nrw.commons.contributions.ContributionDao;
|
import fr.free.nrw.commons.contributions.ContributionDao;
|
||||||
import fr.free.nrw.commons.modifications.ModifierSequence;
|
import fr.free.nrw.commons.modifications.ModifierSequenceDao;
|
||||||
|
|
||||||
public class DBOpenHelper extends SQLiteOpenHelper {
|
public class DBOpenHelper extends SQLiteOpenHelper {
|
||||||
|
|
||||||
|
|
@ -13,7 +13,8 @@ public class DBOpenHelper extends SQLiteOpenHelper {
|
||||||
private static final int DATABASE_VERSION = 6;
|
private static final int DATABASE_VERSION = 6;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do not use, please call CommonsApplication.getDBOpenHelper()
|
* Do not use directly - @Inject an instance where it's needed and let
|
||||||
|
* dependency injection take care of managing this as a singleton.
|
||||||
*/
|
*/
|
||||||
public DBOpenHelper(Context context) {
|
public DBOpenHelper(Context context) {
|
||||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||||
|
|
@ -22,14 +23,14 @@ public class DBOpenHelper extends SQLiteOpenHelper {
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(SQLiteDatabase sqLiteDatabase) {
|
public void onCreate(SQLiteDatabase sqLiteDatabase) {
|
||||||
ContributionDao.Table.onCreate(sqLiteDatabase);
|
ContributionDao.Table.onCreate(sqLiteDatabase);
|
||||||
ModifierSequence.Table.onCreate(sqLiteDatabase);
|
ModifierSequenceDao.Table.onCreate(sqLiteDatabase);
|
||||||
CategoryDao.Table.onCreate(sqLiteDatabase);
|
CategoryDao.Table.onCreate(sqLiteDatabase);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int from, int to) {
|
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int from, int to) {
|
||||||
ContributionDao.Table.onUpdate(sqLiteDatabase, from, to);
|
ContributionDao.Table.onUpdate(sqLiteDatabase, from, to);
|
||||||
ModifierSequence.Table.onUpdate(sqLiteDatabase, from, to);
|
ModifierSequenceDao.Table.onUpdate(sqLiteDatabase, from, to);
|
||||||
CategoryDao.Table.onUpdate(sqLiteDatabase, from, to);
|
CategoryDao.Table.onUpdate(sqLiteDatabase, from, to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,15 @@ import dagger.android.AndroidInjection;
|
||||||
import fr.free.nrw.commons.data.DBOpenHelper;
|
import fr.free.nrw.commons.data.DBOpenHelper;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
import static fr.free.nrw.commons.modifications.ModifierSequenceDao.Table.TABLE_NAME;
|
||||||
|
|
||||||
public class ModificationsContentProvider extends ContentProvider {
|
public class ModificationsContentProvider extends ContentProvider {
|
||||||
|
|
||||||
private static final int MODIFICATIONS = 1;
|
private static final int MODIFICATIONS = 1;
|
||||||
private static final int MODIFICATIONS_ID = 2;
|
private static final int MODIFICATIONS_ID = 2;
|
||||||
|
|
||||||
public static final String AUTHORITY = "fr.free.nrw.commons.modifications.contentprovider";
|
public static final String AUTHORITY = "fr.free.nrw.commons.modifications.contentprovider";
|
||||||
private static final String BASE_PATH = "modifications";
|
public static final String BASE_PATH = "modifications";
|
||||||
|
|
||||||
public static final Uri BASE_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH);
|
public static final Uri BASE_URI = Uri.parse("content://" + AUTHORITY + "/" + BASE_PATH);
|
||||||
|
|
||||||
|
|
@ -47,7 +49,7 @@ public class ModificationsContentProvider extends ContentProvider {
|
||||||
@Override
|
@Override
|
||||||
public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
|
public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
|
||||||
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
|
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
|
||||||
queryBuilder.setTables(ModifierSequence.Table.TABLE_NAME);
|
queryBuilder.setTables(TABLE_NAME);
|
||||||
|
|
||||||
int uriType = uriMatcher.match(uri);
|
int uriType = uriMatcher.match(uri);
|
||||||
|
|
||||||
|
|
@ -78,7 +80,7 @@ public class ModificationsContentProvider extends ContentProvider {
|
||||||
long id = 0;
|
long id = 0;
|
||||||
switch (uriType) {
|
switch (uriType) {
|
||||||
case MODIFICATIONS:
|
case MODIFICATIONS:
|
||||||
id = sqlDB.insert(ModifierSequence.Table.TABLE_NAME, null, contentValues);
|
id = sqlDB.insert(TABLE_NAME, null, contentValues);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unknown URI: " + uri);
|
throw new IllegalArgumentException("Unknown URI: " + uri);
|
||||||
|
|
@ -94,7 +96,7 @@ public class ModificationsContentProvider extends ContentProvider {
|
||||||
switch (uriType) {
|
switch (uriType) {
|
||||||
case MODIFICATIONS_ID:
|
case MODIFICATIONS_ID:
|
||||||
String id = uri.getLastPathSegment();
|
String id = uri.getLastPathSegment();
|
||||||
sqlDB.delete(ModifierSequence.Table.TABLE_NAME,
|
sqlDB.delete(TABLE_NAME,
|
||||||
"_id = ?",
|
"_id = ?",
|
||||||
new String[] { id }
|
new String[] { id }
|
||||||
);
|
);
|
||||||
|
|
@ -114,7 +116,7 @@ public class ModificationsContentProvider extends ContentProvider {
|
||||||
case MODIFICATIONS:
|
case MODIFICATIONS:
|
||||||
for (ContentValues value: values) {
|
for (ContentValues value: values) {
|
||||||
Timber.d("Inserting! %s", value);
|
Timber.d("Inserting! %s", value);
|
||||||
sqlDB.insert(ModifierSequence.Table.TABLE_NAME, null, value);
|
sqlDB.insert(TABLE_NAME, null, value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
@ -140,7 +142,7 @@ public class ModificationsContentProvider extends ContentProvider {
|
||||||
int rowsUpdated = 0;
|
int rowsUpdated = 0;
|
||||||
switch (uriType) {
|
switch (uriType) {
|
||||||
case MODIFICATIONS:
|
case MODIFICATIONS:
|
||||||
rowsUpdated = sqlDB.update(ModifierSequence.Table.TABLE_NAME,
|
rowsUpdated = sqlDB.update(TABLE_NAME,
|
||||||
contentValues,
|
contentValues,
|
||||||
selection,
|
selection,
|
||||||
selectionArgs);
|
selectionArgs);
|
||||||
|
|
@ -149,9 +151,9 @@ public class ModificationsContentProvider extends ContentProvider {
|
||||||
int id = Integer.valueOf(uri.getLastPathSegment());
|
int id = Integer.valueOf(uri.getLastPathSegment());
|
||||||
|
|
||||||
if (TextUtils.isEmpty(selection)) {
|
if (TextUtils.isEmpty(selection)) {
|
||||||
rowsUpdated = sqlDB.update(ModifierSequence.Table.TABLE_NAME,
|
rowsUpdated = sqlDB.update(TABLE_NAME,
|
||||||
contentValues,
|
contentValues,
|
||||||
ModifierSequence.Table.COLUMN_ID + " = ?",
|
ModifierSequenceDao.Table.COLUMN_ID + " = ?",
|
||||||
new String[] { String.valueOf(id) } );
|
new String[] { String.valueOf(id) } );
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Parameter `selection` should be empty when updating an ID");
|
throw new IllegalArgumentException("Parameter `selection` should be empty when updating an ID");
|
||||||
|
|
|
||||||
|
|
@ -83,8 +83,8 @@ public class ModificationsSyncAdapter extends AbstractThreadedSyncAdapter {
|
||||||
contributionsClient = getContext().getContentResolver().acquireContentProviderClient(ContributionsContentProvider.AUTHORITY);
|
contributionsClient = getContext().getContentResolver().acquireContentProviderClient(ContributionsContentProvider.AUTHORITY);
|
||||||
|
|
||||||
while (!allModifications.isAfterLast()) {
|
while (!allModifications.isAfterLast()) {
|
||||||
ModifierSequence sequence = ModifierSequence.fromCursor(allModifications);
|
ModifierSequence sequence = ModifierSequenceDao.fromCursor(allModifications);
|
||||||
sequence.setContentProviderClient(contentProviderClient);
|
ModifierSequenceDao dao = new ModifierSequenceDao(contributionsClient);
|
||||||
Contribution contrib;
|
Contribution contrib;
|
||||||
|
|
||||||
Cursor contributionCursor;
|
Cursor contributionCursor;
|
||||||
|
|
@ -122,7 +122,7 @@ public class ModificationsSyncAdapter extends AbstractThreadedSyncAdapter {
|
||||||
// FIXME: Log this somewhere else
|
// FIXME: Log this somewhere else
|
||||||
Timber.d("Non success result! %s", editResult);
|
Timber.d("Non success result! %s", editResult);
|
||||||
} else {
|
} else {
|
||||||
sequence.delete();
|
dao.delete(sequence);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
allModifications.moveToNext();
|
allModifications.moveToNext();
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,8 @@
|
||||||
package fr.free.nrw.commons.modifications;
|
package fr.free.nrw.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.net.Uri;
|
||||||
import android.os.RemoteException;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
@ -17,14 +11,13 @@ public class ModifierSequence {
|
||||||
private Uri mediaUri;
|
private Uri mediaUri;
|
||||||
private ArrayList<PageModifier> modifiers;
|
private ArrayList<PageModifier> modifiers;
|
||||||
private Uri contentUri;
|
private Uri contentUri;
|
||||||
private ContentProviderClient client;
|
|
||||||
|
|
||||||
public ModifierSequence(Uri mediaUri) {
|
public ModifierSequence(Uri mediaUri) {
|
||||||
this.mediaUri = mediaUri;
|
this.mediaUri = mediaUri;
|
||||||
modifiers = new ArrayList<>();
|
modifiers = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModifierSequence(Uri mediaUri, JSONObject data) {
|
ModifierSequence(Uri mediaUri, JSONObject data) {
|
||||||
this(mediaUri);
|
this(mediaUri);
|
||||||
JSONArray modifiersJSON = data.optJSONArray("modifiers");
|
JSONArray modifiersJSON = data.optJSONArray("modifiers");
|
||||||
for (int i = 0; i < modifiersJSON.length(); i++) {
|
for (int i = 0; i < modifiersJSON.length(); i++) {
|
||||||
|
|
@ -32,7 +25,7 @@ public class ModifierSequence {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Uri getMediaUri() {
|
Uri getMediaUri() {
|
||||||
return mediaUri;
|
return mediaUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,14 +33,14 @@ public class ModifierSequence {
|
||||||
modifiers.add(modifier);
|
modifiers.add(modifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String executeModifications(String pageName, String pageContents) {
|
String executeModifications(String pageName, String pageContents) {
|
||||||
for (PageModifier modifier: modifiers) {
|
for (PageModifier modifier: modifiers) {
|
||||||
pageContents = modifier.doModification(pageName, pageContents);
|
pageContents = modifier.doModification(pageName, pageContents);
|
||||||
}
|
}
|
||||||
return pageContents;
|
return pageContents;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getEditSummary() {
|
String getEditSummary() {
|
||||||
StringBuilder editSummary = new StringBuilder();
|
StringBuilder editSummary = new StringBuilder();
|
||||||
for (PageModifier modifier: modifiers) {
|
for (PageModifier modifier: modifiers) {
|
||||||
editSummary.append(modifier.getEditSumary()).append(" ");
|
editSummary.append(modifier.getEditSumary()).append(" ");
|
||||||
|
|
@ -56,97 +49,16 @@ public class ModifierSequence {
|
||||||
return editSummary.toString();
|
return editSummary.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject toJSON() {
|
ArrayList<PageModifier> getModifiers() {
|
||||||
JSONObject data = new JSONObject();
|
return modifiers;
|
||||||
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() {
|
Uri getContentUri() {
|
||||||
ContentValues cv = new ContentValues();
|
return contentUri;
|
||||||
cv.put(Table.COLUMN_MEDIA_URI, mediaUri.toString());
|
|
||||||
cv.put(Table.COLUMN_DATA, toJSON().toString());
|
|
||||||
return cv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ModifierSequence fromCursor(Cursor cursor) {
|
void setContentUri(Uri contentUri) {
|
||||||
// Hardcoding column positions!
|
this.contentUri = contentUri;
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void onDelete(SQLiteDatabase db) {
|
|
||||||
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
|
|
||||||
onCreate(db);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
package fr.free.nrw.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 org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
public class ModifierSequenceDao {
|
||||||
|
|
||||||
|
private final ContentProviderClient client;
|
||||||
|
|
||||||
|
public ModifierSequenceDao(ContentProviderClient client) {
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.setContentUri( ModificationsContentProvider.uriForId(cursor.getInt(0)));
|
||||||
|
|
||||||
|
return ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save(ModifierSequence sequence) {
|
||||||
|
try {
|
||||||
|
if (sequence.getContentUri() == null) {
|
||||||
|
sequence.setContentUri(client.insert(ModificationsContentProvider.BASE_URI, toContentValues(sequence)));
|
||||||
|
} else {
|
||||||
|
client.update(sequence.getContentUri(), toContentValues(sequence), null, null);
|
||||||
|
}
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delete(ModifierSequence sequence) {
|
||||||
|
try {
|
||||||
|
client.delete(sequence.getContentUri(), null, null);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private JSONObject toJSON(ModifierSequence sequence) {
|
||||||
|
JSONObject data = new JSONObject();
|
||||||
|
try {
|
||||||
|
JSONArray modifiersJSON = new JSONArray();
|
||||||
|
for (PageModifier modifier: sequence.getModifiers()) {
|
||||||
|
modifiersJSON.put(modifier.toJSON());
|
||||||
|
}
|
||||||
|
data.put("modifiers", modifiersJSON);
|
||||||
|
return data;
|
||||||
|
} catch (JSONException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ContentValues toContentValues(ModifierSequence sequence) {
|
||||||
|
ContentValues cv = new ContentValues();
|
||||||
|
cv.put(Table.COLUMN_MEDIA_URI, sequence.getMediaUri().toString());
|
||||||
|
cv.put(Table.COLUMN_DATA, toJSON(sequence).toString());
|
||||||
|
return cv;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Table {
|
||||||
|
static final String TABLE_NAME = "modifications";
|
||||||
|
|
||||||
|
static final String COLUMN_ID = "_id";
|
||||||
|
static final String COLUMN_MEDIA_URI = "mediauri";
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
static final String DROP_TABLE_STATEMENT = "DROP TABLE IF EXISTS " + TABLE_NAME;
|
||||||
|
|
||||||
|
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_STATEMENT);
|
||||||
|
onCreate(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void onDelete(SQLiteDatabase db) {
|
||||||
|
db.execSQL(DROP_TABLE_STATEMENT);
|
||||||
|
onCreate(db);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -40,6 +40,7 @@ import fr.free.nrw.commons.media.MediaDetailPagerFragment;
|
||||||
import fr.free.nrw.commons.modifications.CategoryModifier;
|
import fr.free.nrw.commons.modifications.CategoryModifier;
|
||||||
import fr.free.nrw.commons.modifications.ModificationsContentProvider;
|
import fr.free.nrw.commons.modifications.ModificationsContentProvider;
|
||||||
import fr.free.nrw.commons.modifications.ModifierSequence;
|
import fr.free.nrw.commons.modifications.ModifierSequence;
|
||||||
|
import fr.free.nrw.commons.modifications.ModifierSequenceDao;
|
||||||
import fr.free.nrw.commons.modifications.TemplateRemoveModifier;
|
import fr.free.nrw.commons.modifications.TemplateRemoveModifier;
|
||||||
import fr.free.nrw.commons.mwapi.MediaWikiApi;
|
import fr.free.nrw.commons.mwapi.MediaWikiApi;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
@ -165,15 +166,14 @@ public class MultipleShareActivity extends AuthenticatedActivity
|
||||||
@Override
|
@Override
|
||||||
public void onCategoriesSave(List<String> categories) {
|
public void onCategoriesSave(List<String> categories) {
|
||||||
if (categories.size() > 0) {
|
if (categories.size() > 0) {
|
||||||
ContentProviderClient client = getContentResolver().acquireContentProviderClient(ModificationsContentProvider.AUTHORITY);
|
ModifierSequenceDao dao = new ModifierSequenceDao(getContentResolver().acquireContentProviderClient(ModificationsContentProvider.AUTHORITY));
|
||||||
for (Contribution contribution : photosList) {
|
for (Contribution contribution : photosList) {
|
||||||
ModifierSequence categoriesSequence = new ModifierSequence(contribution.getContentUri());
|
ModifierSequence categoriesSequence = new ModifierSequence(contribution.getContentUri());
|
||||||
|
|
||||||
categoriesSequence.queueModifier(new CategoryModifier(categories.toArray(new String[]{})));
|
categoriesSequence.queueModifier(new CategoryModifier(categories.toArray(new String[]{})));
|
||||||
categoriesSequence.queueModifier(new TemplateRemoveModifier("Uncategorized"));
|
categoriesSequence.queueModifier(new TemplateRemoveModifier("Uncategorized"));
|
||||||
|
|
||||||
categoriesSequence.setContentProviderClient(client);
|
dao.save(categoriesSequence);
|
||||||
categoriesSequence.save();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// FIXME: Make sure that the content provider is up
|
// FIXME: Make sure that the content provider is up
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,6 @@ import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
import fr.free.nrw.commons.CommonsApplication;
|
|
||||||
import fr.free.nrw.commons.R;
|
import fr.free.nrw.commons.R;
|
||||||
import fr.free.nrw.commons.auth.AuthenticatedActivity;
|
import fr.free.nrw.commons.auth.AuthenticatedActivity;
|
||||||
import fr.free.nrw.commons.auth.SessionManager;
|
import fr.free.nrw.commons.auth.SessionManager;
|
||||||
|
|
@ -50,8 +49,8 @@ import fr.free.nrw.commons.contributions.Contribution;
|
||||||
import fr.free.nrw.commons.modifications.CategoryModifier;
|
import fr.free.nrw.commons.modifications.CategoryModifier;
|
||||||
import fr.free.nrw.commons.modifications.ModificationsContentProvider;
|
import fr.free.nrw.commons.modifications.ModificationsContentProvider;
|
||||||
import fr.free.nrw.commons.modifications.ModifierSequence;
|
import fr.free.nrw.commons.modifications.ModifierSequence;
|
||||||
|
import fr.free.nrw.commons.modifications.ModifierSequenceDao;
|
||||||
import fr.free.nrw.commons.modifications.TemplateRemoveModifier;
|
import fr.free.nrw.commons.modifications.TemplateRemoveModifier;
|
||||||
import fr.free.nrw.commons.mwapi.EventLog;
|
|
||||||
import fr.free.nrw.commons.mwapi.MediaWikiApi;
|
import fr.free.nrw.commons.mwapi.MediaWikiApi;
|
||||||
import timber.log.Timber;
|
import timber.log.Timber;
|
||||||
|
|
||||||
|
|
@ -167,8 +166,8 @@ public class ShareActivity
|
||||||
|
|
||||||
categoriesSequence.queueModifier(new CategoryModifier(categories.toArray(new String[]{})));
|
categoriesSequence.queueModifier(new CategoryModifier(categories.toArray(new String[]{})));
|
||||||
categoriesSequence.queueModifier(new TemplateRemoveModifier("Uncategorized"));
|
categoriesSequence.queueModifier(new TemplateRemoveModifier("Uncategorized"));
|
||||||
categoriesSequence.setContentProviderClient(getContentResolver().acquireContentProviderClient(ModificationsContentProvider.AUTHORITY));
|
ModifierSequenceDao dao = new ModifierSequenceDao(getContentResolver().acquireContentProviderClient(ModificationsContentProvider.AUTHORITY));
|
||||||
categoriesSequence.save();
|
dao.save(categoriesSequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Make sure that the content provider is up
|
// FIXME: Make sure that the content provider is up
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,181 @@
|
||||||
|
package fr.free.nrw.commons.modifications;
|
||||||
|
|
||||||
|
import android.content.ContentProviderClient;
|
||||||
|
import android.content.ContentValues;
|
||||||
|
import android.database.MatrixCursor;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Captor;
|
||||||
|
import org.mockito.InOrder;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import fr.free.nrw.commons.BuildConfig;
|
||||||
|
import fr.free.nrw.commons.TestCommonsApplication;
|
||||||
|
|
||||||
|
import static fr.free.nrw.commons.modifications.ModificationsContentProvider.BASE_URI;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Matchers.isA;
|
||||||
|
import static org.mockito.Matchers.isNull;
|
||||||
|
import static org.mockito.Mockito.inOrder;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
@Config(constants = BuildConfig.class, sdk = 21, application = TestCommonsApplication.class)
|
||||||
|
public class ModifierSequenceDaoTest {
|
||||||
|
|
||||||
|
private static final String EXPECTED_MEDIA_URI = "http://example.com/";
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
ContentProviderClient client;
|
||||||
|
@Mock
|
||||||
|
SQLiteDatabase database;
|
||||||
|
@Captor
|
||||||
|
ArgumentCaptor<ContentValues> contentValuesCaptor;
|
||||||
|
|
||||||
|
private ModifierSequenceDao testObject;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
testObject = new ModifierSequenceDao(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createFromCursorWithEmptyModifiers() {
|
||||||
|
MatrixCursor cursor = createCursor("");
|
||||||
|
|
||||||
|
ModifierSequence seq = ModifierSequenceDao.fromCursor(cursor);
|
||||||
|
|
||||||
|
assertEquals(EXPECTED_MEDIA_URI, seq.getMediaUri().toString());
|
||||||
|
assertEquals(BASE_URI.buildUpon().appendPath("1").toString(), seq.getContentUri().toString());
|
||||||
|
assertTrue(seq.getModifiers().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createFromCursorWtihCategoryModifier() {
|
||||||
|
MatrixCursor cursor = createCursor("{\"name\": \"CategoriesModifier\", \"data\": {}}");
|
||||||
|
|
||||||
|
ModifierSequence seq = ModifierSequenceDao.fromCursor(cursor);
|
||||||
|
|
||||||
|
assertEquals(1, seq.getModifiers().size());
|
||||||
|
assertTrue(seq.getModifiers().get(0) instanceof CategoryModifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createFromCursorWithRemoveModifier() {
|
||||||
|
MatrixCursor cursor = createCursor("{\"name\": \"TemplateRemoverModifier\", \"data\": {}}");
|
||||||
|
|
||||||
|
ModifierSequence seq = ModifierSequenceDao.fromCursor(cursor);
|
||||||
|
|
||||||
|
assertEquals(1, seq.getModifiers().size());
|
||||||
|
assertTrue(seq.getModifiers().get(0) instanceof TemplateRemoveModifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteSequence() throws Exception {
|
||||||
|
when(client.delete(isA(Uri.class), isNull(String.class), isNull(String[].class))).thenReturn(1);
|
||||||
|
ModifierSequence seq = ModifierSequenceDao.fromCursor(createCursor(""));
|
||||||
|
|
||||||
|
testObject.delete(seq);
|
||||||
|
|
||||||
|
verify(client).delete(eq(seq.getContentUri()), isNull(String.class), isNull(String[].class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = RuntimeException.class)
|
||||||
|
public void deleteTranslatesRemoteExceptions() throws Exception {
|
||||||
|
when(client.delete(isA(Uri.class), isNull(String.class), isNull(String[].class))).thenThrow(new RemoteException(""));
|
||||||
|
ModifierSequence seq = ModifierSequenceDao.fromCursor(createCursor(""));
|
||||||
|
|
||||||
|
testObject.delete(seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void saveExistingSequence() throws Exception {
|
||||||
|
String modifierJson = "{\"name\":\"CategoriesModifier\",\"data\":{}}";
|
||||||
|
String expectedData = "{\"modifiers\":[" + modifierJson + "]}";
|
||||||
|
MatrixCursor cursor = createCursor(modifierJson);
|
||||||
|
|
||||||
|
testObject.save(ModifierSequenceDao.fromCursor(cursor));
|
||||||
|
|
||||||
|
verify(client).update(eq(ModifierSequenceDao.fromCursor(cursor).getContentUri()), contentValuesCaptor.capture(), isNull(String.class), isNull(String[].class));
|
||||||
|
ContentValues cv = contentValuesCaptor.getValue();
|
||||||
|
assertEquals(2, cv.size());
|
||||||
|
assertEquals(EXPECTED_MEDIA_URI, cv.get(ModifierSequenceDao.Table.COLUMN_MEDIA_URI));
|
||||||
|
assertEquals(expectedData, cv.get(ModifierSequenceDao.Table.COLUMN_DATA));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void saveNewSequence() throws Exception {
|
||||||
|
Uri expectedContentUri = BASE_URI.buildUpon().appendPath("1").build();
|
||||||
|
when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenReturn(expectedContentUri);
|
||||||
|
|
||||||
|
ModifierSequence seq = new ModifierSequence(Uri.parse(EXPECTED_MEDIA_URI));
|
||||||
|
testObject.save(seq);
|
||||||
|
|
||||||
|
verify(client).insert(eq(ModificationsContentProvider.BASE_URI), contentValuesCaptor.capture());
|
||||||
|
ContentValues cv = contentValuesCaptor.getValue();
|
||||||
|
assertEquals(2, cv.size());
|
||||||
|
assertEquals(EXPECTED_MEDIA_URI, cv.get(ModifierSequenceDao.Table.COLUMN_MEDIA_URI));
|
||||||
|
assertEquals("{\"modifiers\":[]}", cv.get(ModifierSequenceDao.Table.COLUMN_DATA));
|
||||||
|
assertEquals(expectedContentUri.toString(), seq.getContentUri().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = RuntimeException.class)
|
||||||
|
public void saveTranslatesRemoteExceptions() throws Exception {
|
||||||
|
when(client.insert(isA(Uri.class), isA(ContentValues.class))).thenThrow(new RemoteException(""));
|
||||||
|
|
||||||
|
testObject.save(new ModifierSequence(Uri.parse(EXPECTED_MEDIA_URI)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createTable() {
|
||||||
|
ModifierSequenceDao.Table.onCreate(database);
|
||||||
|
|
||||||
|
verify(database).execSQL(ModifierSequenceDao.Table.CREATE_TABLE_STATEMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateTable() {
|
||||||
|
ModifierSequenceDao.Table.onUpdate(database, 1, 2);
|
||||||
|
|
||||||
|
InOrder inOrder = inOrder(database);
|
||||||
|
inOrder.verify(database).execSQL(ModifierSequenceDao.Table.DROP_TABLE_STATEMENT);
|
||||||
|
inOrder.verify(database).execSQL(ModifierSequenceDao.Table.CREATE_TABLE_STATEMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deleteTable() {
|
||||||
|
ModifierSequenceDao.Table.onDelete(database);
|
||||||
|
|
||||||
|
InOrder inOrder = inOrder(database);
|
||||||
|
inOrder.verify(database).execSQL(ModifierSequenceDao.Table.DROP_TABLE_STATEMENT);
|
||||||
|
inOrder.verify(database).execSQL(ModifierSequenceDao.Table.CREATE_TABLE_STATEMENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private MatrixCursor createCursor(String modifierJson) {
|
||||||
|
MatrixCursor cursor = new MatrixCursor(new String[]{
|
||||||
|
ModifierSequenceDao.Table.COLUMN_ID,
|
||||||
|
ModifierSequenceDao.Table.COLUMN_MEDIA_URI,
|
||||||
|
ModifierSequenceDao.Table.COLUMN_DATA
|
||||||
|
}, 1);
|
||||||
|
cursor.addRow(Arrays.asList("1", EXPECTED_MEDIA_URI, "{\"modifiers\": [" + modifierJson + "]}"));
|
||||||
|
cursor.moveToFirst();
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue